aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYoungsang Cho <youngsang@google.com>2016-10-31 15:28:42 -0700
committerYoungsang Cho <youngsang@google.com>2016-10-31 15:28:42 -0700
commit919e1ed7e914029a1a0054237d86dc7b19ced898 (patch)
treecb30cfbafd80e01d314868cdc36e783d39981119
parent2933fcfd17f59c086436b270e7c01f2afcd54aa5 (diff)
downloadTV-919e1ed7e914029a1a0054237d86dc7b19ced898.tar.gz
Sync to ub-tv-killing at 6f6e46557accb62c9548e4177d6005aa944dbf33
Change-Id: I873644d6d9d0110c981ef6075cb4019c16bbb94b
-rw-r--r--Android.mk60
-rw-r--r--AndroidManifest.xml75
-rw-r--r--common/res/layout/fragment_setup_multi_pane.xml2
-rw-r--r--common/res/values-af/strings.xml7
-rw-r--r--common/res/values-am/strings.xml7
-rw-r--r--common/res/values-ar/strings.xml7
-rw-r--r--common/res/values-az-rAZ/strings.xml7
-rw-r--r--common/res/values-bg/strings.xml7
-rw-r--r--common/res/values-bn-rBD/strings.xml7
-rw-r--r--common/res/values-ca/strings.xml7
-rw-r--r--common/res/values-cs/strings.xml7
-rw-r--r--common/res/values-da/strings.xml7
-rw-r--r--common/res/values-de/strings.xml7
-rw-r--r--common/res/values-el/strings.xml7
-rw-r--r--common/res/values-en-rAU/strings.xml7
-rw-r--r--common/res/values-en-rGB/strings.xml7
-rw-r--r--common/res/values-en-rIN/strings.xml7
-rw-r--r--common/res/values-es-rUS/strings.xml7
-rw-r--r--common/res/values-es/strings.xml7
-rw-r--r--common/res/values-et-rEE/strings.xml7
-rw-r--r--common/res/values-eu-rES/strings.xml7
-rw-r--r--common/res/values-fa/strings.xml7
-rw-r--r--common/res/values-fi/strings.xml7
-rw-r--r--common/res/values-fr-rCA/strings.xml7
-rw-r--r--common/res/values-fr/strings.xml7
-rw-r--r--common/res/values-gl-rES/strings.xml7
-rw-r--r--common/res/values-hi/strings.xml7
-rw-r--r--common/res/values-hr/strings.xml7
-rw-r--r--common/res/values-hu/strings.xml7
-rw-r--r--common/res/values-hy-rAM/strings.xml7
-rw-r--r--common/res/values-in/strings.xml7
-rw-r--r--common/res/values-is-rIS/strings.xml7
-rw-r--r--common/res/values-it/strings.xml7
-rw-r--r--common/res/values-iw/strings.xml7
-rw-r--r--common/res/values-ja/strings.xml7
-rw-r--r--common/res/values-ka-rGE/strings.xml7
-rw-r--r--common/res/values-kk-rKZ/strings.xml7
-rw-r--r--common/res/values-km-rKH/strings.xml7
-rw-r--r--common/res/values-kn-rIN/strings.xml7
-rw-r--r--common/res/values-ko/strings.xml7
-rw-r--r--common/res/values-ky-rKG/strings.xml7
-rw-r--r--common/res/values-lo-rLA/strings.xml7
-rw-r--r--common/res/values-lt/strings.xml7
-rw-r--r--common/res/values-lv/strings.xml7
-rw-r--r--common/res/values-mk-rMK/strings.xml7
-rw-r--r--common/res/values-ml-rIN/strings.xml7
-rw-r--r--common/res/values-mn-rMN/strings.xml7
-rw-r--r--common/res/values-mr-rIN/strings.xml7
-rw-r--r--common/res/values-ms-rMY/strings.xml7
-rw-r--r--common/res/values-my-rMM/strings.xml7
-rw-r--r--common/res/values-nb/strings.xml7
-rw-r--r--common/res/values-ne-rNP/strings.xml7
-rw-r--r--common/res/values-nl/strings.xml7
-rw-r--r--common/res/values-pl/strings.xml7
-rw-r--r--common/res/values-pt-rPT/strings.xml7
-rw-r--r--common/res/values-pt/strings.xml7
-rw-r--r--common/res/values-ro/strings.xml7
-rw-r--r--common/res/values-ru/strings.xml7
-rw-r--r--common/res/values-si-rLK/strings.xml7
-rw-r--r--common/res/values-sk/strings.xml7
-rw-r--r--common/res/values-sl/strings.xml7
-rw-r--r--common/res/values-sr/strings.xml7
-rw-r--r--common/res/values-sv/strings.xml7
-rw-r--r--common/res/values-sw/strings.xml7
-rw-r--r--common/res/values-ta-rIN/strings.xml7
-rw-r--r--common/res/values-te-rIN/strings.xml7
-rw-r--r--common/res/values-th/strings.xml7
-rw-r--r--common/res/values-tl/strings.xml7
-rw-r--r--common/res/values-tr/strings.xml7
-rw-r--r--common/res/values-uk/strings.xml7
-rw-r--r--common/res/values-ur-rPK/strings.xml7
-rw-r--r--common/res/values-uz-rUZ/strings.xml7
-rw-r--r--common/res/values-vi/strings.xml7
-rw-r--r--common/res/values-zh-rCN/strings.xml7
-rw-r--r--common/res/values-zh-rHK/strings.xml7
-rw-r--r--common/res/values-zh-rTW/strings.xml7
-rw-r--r--common/res/values-zu/strings.xml7
-rw-r--r--common/res/values/dimens.xml2
-rw-r--r--common/res/values/strings.xml14
-rw-r--r--common/src/com/android/tv/common/CollectionUtils.java56
-rw-r--r--common/src/com/android/tv/common/SharedPreferencesUtils.java16
-rw-r--r--common/src/com/android/tv/common/SoftPreconditions.java17
-rw-r--r--common/src/com/android/tv/common/TvContentRatingCache.java2
-rw-r--r--common/src/com/android/tv/common/feature/CommonFeatures.java20
-rw-r--r--common/src/com/android/tv/common/feature/EngOnlyFeature.java2
-rw-r--r--common/src/com/android/tv/common/feature/Sdk.java4
-rw-r--r--common/src/com/android/tv/common/feature/SharedPreferencesFeature.java4
-rw-r--r--common/src/com/android/tv/common/feature/SystemAppFeature.java34
-rw-r--r--common/src/com/android/tv/common/ui/setup/OnActionClickListener.java11
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupActionHelper.java57
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupActivity.java18
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupFragment.java26
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java7
-rw-r--r--common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java26
-rw-r--r--common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java2
-rw-r--r--common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java5
-rw-r--r--icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java (renamed from usbtuner/icu/icu4j/main/classes/core/src/com/ibm/icu/text/SCSU.java)0
-rw-r--r--icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java (renamed from usbtuner/icu/icu4j/main/classes/core/src/com/ibm/icu/text/UnicodeDecompressor.java)0
-rw-r--r--jni/Android.mk (renamed from usbtuner/jni/Android.mk)0
-rw-r--r--jni/DvbManager.cpp (renamed from usbtuner/jni/DvbManager.cpp)41
-rw-r--r--jni/DvbManager.h (renamed from usbtuner/jni/DvbManager.h)12
-rwxr-xr-xjni/gen_jni.sh3
-rw-r--r--jni/logging.h (renamed from usbtuner/jni/logging.h)0
-rw-r--r--jni/mutex.h (renamed from usbtuner/jni/mutex.h)0
-rw-r--r--jni/tunertvinput_jni.cpp (renamed from usbtuner/jni/tunertvinput_jni.cpp)38
-rw-r--r--jni/tunertvinput_jni.h98
-rw-r--r--libs/exoplayer.jarbin0 -> 792705 bytes
-rw-r--r--proguard.flags9
-rw-r--r--proto/channel.proto (renamed from usbtuner/proto/channel.proto)4
-rw-r--r--proto/track.proto (renamed from usbtuner/proto/track.proto)4
-rw-r--r--res/drawable-nodpi/program_guide_table_item_background_focused.9.pngbin93 -> 92 bytes
-rw-r--r--res/drawable-nodpi/program_guide_table_item_background_focused_enabled.9.pngbin93 -> 92 bytes
-rw-r--r--res/drawable-nodpi/program_guide_table_item_background_normal.9.pngbin92 -> 91 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_00.pngbin266 -> 98 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_01.pngbin1565 -> 463 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_02.pngbin1983 -> 661 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_03.pngbin2206 -> 796 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_04.pngbin2379 -> 884 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_05.pngbin2545 -> 962 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_06.pngbin2646 -> 1019 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_07.pngbin2534 -> 919 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_08.pngbin2630 -> 944 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_09.pngbin2779 -> 1149 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_10.pngbin2819 -> 1143 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_11.pngbin2841 -> 1190 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_12.pngbin2726 -> 1009 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_13.pngbin2824 -> 1109 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_14.pngbin2714 -> 1020 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_15.pngbin2824 -> 1217 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_16.pngbin2770 -> 1137 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_17.pngbin2331 -> 928 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_18.pngbin2845 -> 1233 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_19.pngbin2810 -> 1175 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_20.pngbin2831 -> 1174 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_21.pngbin2851 -> 1236 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_22.pngbin2790 -> 1074 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_23.pngbin2831 -> 1236 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_24.pngbin2790 -> 1118 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_25.pngbin2818 -> 1206 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_26.pngbin2809 -> 1207 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_27.pngbin2836 -> 1150 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_28.pngbin2859 -> 1240 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_29.pngbin2547 -> 925 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_30.pngbin2852 -> 1229 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_31.pngbin2815 -> 1180 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_32.pngbin2868 -> 1198 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_33.pngbin2837 -> 1228 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_34.pngbin2769 -> 1079 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_35.pngbin2810 -> 1239 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_36.pngbin2739 -> 1108 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_37.pngbin2838 -> 1212 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_38.pngbin2822 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_39.pngbin2821 -> 1142 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_40.pngbin2844 -> 1246 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_41.pngbin2367 -> 924 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_42.pngbin2781 -> 1031 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_43.pngbin2846 -> 1167 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_44.pngbin2850 -> 1213 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_45.pngbin2844 -> 1205 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_46.pngbin2805 -> 1070 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_47.pngbin2804 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_48.pngbin2703 -> 1050 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_49.pngbin2776 -> 1145 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_50.pngbin2567 -> 976 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_51.pngbin2643 -> 1063 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_52.pngbin2559 -> 987 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_53.pngbin2520 -> 970 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_54.pngbin2413 -> 928 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_55.pngbin2282 -> 874 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_56.pngbin2277 -> 844 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_57.pngbin2152 -> 765 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_58.pngbin1964 -> 638 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_59.pngbin1699 -> 499 bytes
-rw-r--r--res/drawable-xhdpi/arrow_blue_60.pngbin266 -> 98 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_180.pngbin266 -> 98 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_181.pngbin1548 -> 463 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_182.pngbin1962 -> 661 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_183.pngbin2184 -> 796 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_184.pngbin2358 -> 884 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_185.pngbin2500 -> 962 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_186.pngbin2585 -> 1019 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_187.pngbin2430 -> 919 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_188.pngbin2547 -> 944 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_189.pngbin2646 -> 1149 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_190.pngbin2698 -> 1143 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_191.pngbin2738 -> 1190 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_192.pngbin2698 -> 1009 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_193.pngbin2793 -> 1109 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_194.pngbin2686 -> 1020 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_195.pngbin2786 -> 1217 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_196.pngbin2738 -> 1137 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_197.pngbin2329 -> 928 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_198.pngbin2809 -> 1233 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_199.pngbin2784 -> 1175 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_200.pngbin2796 -> 1174 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_201.pngbin2812 -> 1236 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_202.pngbin2751 -> 1074 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_203.pngbin2805 -> 1236 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_204.pngbin2759 -> 1118 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_205.pngbin2780 -> 1206 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_206.pngbin2776 -> 1207 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_207.pngbin2796 -> 1150 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_208.pngbin2824 -> 1240 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_209.pngbin2517 -> 925 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_210.pngbin2809 -> 1229 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_211.pngbin2773 -> 1180 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_212.pngbin2821 -> 1198 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_213.pngbin2806 -> 1228 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_214.pngbin2739 -> 1079 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_215.pngbin2767 -> 1239 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_216.pngbin2705 -> 1108 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_217.pngbin2804 -> 1212 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_218.pngbin2795 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_219.pngbin2782 -> 1142 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_220.pngbin2808 -> 1245 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_221.pngbin2347 -> 924 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_222.pngbin2749 -> 1031 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_223.pngbin2800 -> 1167 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_224.pngbin2822 -> 1213 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_225.pngbin2815 -> 1205 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_226.pngbin2771 -> 1070 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_227.pngbin2775 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_228.pngbin2676 -> 1050 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_229.pngbin2673 -> 1145 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_230.pngbin2478 -> 976 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_231.pngbin2526 -> 1061 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_232.pngbin2473 -> 985 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_233.pngbin2424 -> 970 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_234.pngbin2339 -> 927 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_235.pngbin2239 -> 873 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_236.pngbin2257 -> 844 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_237.pngbin2125 -> 765 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_238.pngbin1937 -> 638 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_239.pngbin1678 -> 499 bytes
-rw-r--r--res/drawable-xhdpi/arrow_orange_240.pngbin266 -> 98 bytes
-rw-r--r--res/drawable-xhdpi/banner.pngbin6367 -> 4873 bytes
-rw-r--r--res/drawable-xhdpi/bg_protection.pngbin152456 -> 132623 bytes
-rw-r--r--res/drawable-xhdpi/cloud01.pngbin3529 -> 2357 bytes
-rw-r--r--res/drawable-xhdpi/cloud02.pngbin1666 -> 1118 bytes
-rw-r--r--res/drawable-xhdpi/default_now_card.pngbin19513 -> 3370 bytes
-rw-r--r--res/drawable-xhdpi/dvr_default_poster.pngbin0 -> 766 bytes
-rw-r--r--res/drawable-xhdpi/dvr_default_program_art.pngbin12853 -> 11562 bytes
-rw-r--r--res/drawable-xhdpi/dvr_full_schedule.pngbin0 -> 1750 bytes
-rw-r--r--res/drawable-xhdpi/ic_channel_guide.pngbin1448 -> 906 bytes
-rw-r--r--res/drawable-xhdpi/ic_check_circle_white_48dp.pngbin0 -> 361 bytes
-rw-r--r--res/drawable-xhdpi/ic_delete_32dp.pngbin0 -> 802 bytes
-rwxr-xr-xres/drawable-xhdpi/ic_developer_mode_tv_white_48dp.pngbin0 -> 851 bytes
-rw-r--r--res/drawable-xhdpi/ic_draggable_white.pngbin0 -> 148 bytes
-rw-r--r--res/drawable-xhdpi/ic_dragging_grey.pngbin0 -> 313 bytes
-rw-r--r--res/drawable-xhdpi/ic_dvr.pngbin684 -> 934 bytes
-rw-r--r--res/drawable-xhdpi/ic_dvr_cancel.pngbin0 -> 658 bytes
-rw-r--r--res/drawable-xhdpi/ic_dvr_cancel_32dp.pngbin0 -> 1514 bytes
-rw-r--r--res/drawable-xhdpi/ic_dvr_cancel_large.pngbin0 -> 1158 bytes
-rw-r--r--res/drawable-xhdpi/ic_dvr_delete.pngbin0 -> 657 bytes
-rw-r--r--res/drawable-xhdpi/ic_error_recording.pngbin0 -> 729 bytes
-rw-r--r--res/drawable-xhdpi/ic_error_white_48dp.pngbin0 -> 1117 bytes
-rw-r--r--res/drawable-xhdpi/ic_fresh.pngbin0 -> 13892 bytes
-rw-r--r--res/drawable-xhdpi/ic_guide_lock.pngbin1065 -> 737 bytes
-rw-r--r--res/drawable-xhdpi/ic_launcher.pngbin3822 -> 3325 bytes
-rw-r--r--res/drawable-xhdpi/ic_launcher_s.pngbin1437 -> 401 bytes
-rw-r--r--res/drawable-xhdpi/ic_message_lock.pngbin7078 -> 3928 bytes
-rw-r--r--res/drawable-xhdpi/ic_message_lock_no_permission.pngbin3553 -> 2147 bytes
-rw-r--r--res/drawable-xhdpi/ic_message_lock_preview.pngbin2593 -> 1847 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_input.pngbin445 -> 270 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_layout1.pngbin302 -> 175 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_layout2.pngbin300 -> 176 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_layout3.pngbin299 -> 176 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_layout4.pngbin296 -> 175 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_layout5.pngbin308 -> 178 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_size.pngbin262 -> 155 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_swap.pngbin388 -> 241 bytes
-rw-r--r--res/drawable-xhdpi/ic_pip_option_swap_audio.pngbin846 -> 479 bytes
-rw-r--r--res/drawable-xhdpi/ic_playstore.pngbin3822 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/ic_recent_thumbnail_default.pngbin2977 -> 1961 bytes
-rw-r--r--res/drawable-xhdpi/ic_record_start.pngbin0 -> 556 bytes
-rw-r--r--res/drawable-xhdpi/ic_record_start_white.pngbin614 -> 0 bytes
-rw-r--r--res/drawable-xhdpi/ic_record_stop.pngbin95 -> 127 bytes
-rw-r--r--res/drawable-xhdpi/ic_recorded_program.pngbin0 -> 612 bytes
-rw-r--r--res/drawable-xhdpi/ic_recording_program.pngbin0 -> 313 bytes
-rw-r--r--res/drawable-xhdpi/ic_related_actor.pngbin2582 -> 1275 bytes
-rw-r--r--res/drawable-xhdpi/ic_related_search.pngbin3702 -> 2707 bytes
-rw-r--r--res/drawable-xhdpi/ic_sad_cloud.pngbin6411 -> 2507 bytes
-rw-r--r--res/drawable-xhdpi/ic_schedule_32dp.pngbin0 -> 1490 bytes
-rw-r--r--res/drawable-xhdpi/ic_scheduled_recording.pngbin0 -> 902 bytes
-rw-r--r--res/drawable-xhdpi/ic_scheduled_white.pngbin0 -> 491 bytes
-rw-r--r--res/drawable-xhdpi/ic_settings.pngbin763 -> 406 bytes
-rw-r--r--res/drawable-xhdpi/ic_setup_antenna.pngbin2637 -> 1264 bytes
-rw-r--r--res/drawable-xhdpi/ic_setup_channels.pngbin2068 -> 1465 bytes
-rw-r--r--res/drawable-xhdpi/ic_store.pngbin3822 -> 3894 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_aspect.pngbin333 -> 188 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_cc.pngbin500 -> 268 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_channel_sources.pngbin423 -> 272 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_multi_track.pngbin862 -> 412 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_pip.pngbin347 -> 192 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvoption_pip_off.pngbin469 -> 261 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_000.pngbin1411 -> 938 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_001.pngbin1385 -> 934 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_002.pngbin1327 -> 887 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_003.pngbin1243 -> 815 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_004.pngbin1229 -> 804 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_005.pngbin1390 -> 942 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_006.pngbin1656 -> 1117 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_007.pngbin1848 -> 1265 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_008.pngbin1818 -> 1219 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_009.pngbin1628 -> 1093 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_010.pngbin1604 -> 1104 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_011.pngbin1557 -> 1060 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_012.pngbin1528 -> 1030 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_013.pngbin1573 -> 1058 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_014.pngbin1551 -> 1047 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_015.pngbin1551 -> 1045 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_000.pngbin1502 -> 972 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_001.pngbin1599 -> 1046 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_002.pngbin1626 -> 1116 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_003.pngbin1672 -> 1148 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_004.pngbin1553 -> 1074 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_005.pngbin1442 -> 972 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_006.pngbin1385 -> 927 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_007.pngbin1375 -> 914 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_008.pngbin1331 -> 877 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_009.pngbin1313 -> 864 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_010.pngbin1295 -> 841 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_011.pngbin1274 -> 831 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_012.pngbin1250 -> 837 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_013.pngbin1251 -> 837 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_014.pngbin1236 -> 829 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_015.pngbin1244 -> 830 bytes
-rw-r--r--res/drawable-xhdpi/ic_tvsidepanel_partial_locked.pngbin1088 -> 754 bytes
-rw-r--r--res/drawable-xhdpi/ic_warning_gray600_36dp.pngbin0 -> 335 bytes
-rw-r--r--res/drawable-xhdpi/ic_warning_white_12dp.pngbin0 -> 242 bytes
-rw-r--r--res/drawable-xhdpi/ic_warning_white_18dp.pngbin0 -> 356 bytes
-rw-r--r--res/drawable-xhdpi/ic_warning_white_32dp.pngbin0 -> 553 bytes
-rw-r--r--res/drawable-xhdpi/ic_warning_white_96dp.pngbin0 -> 992 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_remote.pngbin10193 -> 5556 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_000.pngbin2007 -> 1120 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_001.pngbin2387 -> 1470 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_002.pngbin2588 -> 1682 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_003.pngbin2771 -> 1871 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_004.pngbin2935 -> 2064 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_005.pngbin3097 -> 2164 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_006.pngbin3186 -> 2279 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_007.pngbin3221 -> 2279 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_008.pngbin3350 -> 2324 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_009.pngbin3543 -> 2352 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_010.pngbin3480 -> 2325 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_011.pngbin3561 -> 2222 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_012.pngbin3568 -> 2181 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_013.pngbin3680 -> 2110 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_014.pngbin3638 -> 1944 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_015.pngbin3600 -> 1871 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_016.pngbin3672 -> 1918 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_017.pngbin3731 -> 1976 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_018.pngbin3780 -> 2036 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_019.pngbin3773 -> 2069 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_020.pngbin3843 -> 2097 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_021.pngbin3823 -> 2078 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_022.pngbin3850 -> 2148 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_023.pngbin3927 -> 2266 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_024.pngbin3909 -> 2245 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_025.pngbin3930 -> 2278 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_026.pngbin3834 -> 2236 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_027.pngbin3807 -> 2217 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_028.pngbin3706 -> 2113 bytes
-rw-r--r--res/drawable-xhdpi/ic_welcome_ripple_029.pngbin3502 -> 1905 bytes
-rw-r--r--res/drawable-xhdpi/splash_logo.pngbin12853 -> 11562 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_01.pngbin892 -> 106 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_02.pngbin1241 -> 446 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_03.pngbin1136 -> 394 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_04.pngbin1152 -> 377 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_05.pngbin3804 -> 1971 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_06.pngbin5334 -> 3413 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_07.pngbin7904 -> 4871 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_08.pngbin8949 -> 5486 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_09.pngbin9578 -> 5878 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_10.pngbin9784 -> 6009 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_11.pngbin9786 -> 6009 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_12.pngbin9788 -> 6014 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_13.pngbin9788 -> 6010 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_14.pngbin9790 -> 6010 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_15.pngbin9789 -> 6012 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_16.pngbin9786 -> 6008 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_17.pngbin9790 -> 6009 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_18.pngbin9781 -> 5999 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_19.pngbin9782 -> 6002 bytes
-rw-r--r--res/drawable-xhdpi/tv_1a_20.pngbin9773 -> 5988 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_01.pngbin9773 -> 5987 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_02.pngbin9788 -> 6008 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_03.pngbin9787 -> 6008 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_04.pngbin9649 -> 5946 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_05.pngbin8081 -> 4987 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_06.pngbin5506 -> 3410 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_07.pngbin3970 -> 1713 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_08.pngbin2520 -> 1098 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_09.pngbin1930 -> 847 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_10.pngbin1299 -> 451 bytes
-rw-r--r--res/drawable-xhdpi/tv_1b_11.pngbin892 -> 106 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_01.pngbin892 -> 106 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_02.pngbin946 -> 135 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_03.pngbin1057 -> 264 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_04.pngbin1271 -> 344 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_05.pngbin1879 -> 788 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_06.pngbin3475 -> 1698 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_07.pngbin5792 -> 3732 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_08.pngbin8301 -> 5378 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_09.pngbin9109 -> 5899 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_10.pngbin8822 -> 5678 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_11.pngbin8460 -> 5600 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_12.pngbin8163 -> 5466 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_13.pngbin8011 -> 5482 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_14.pngbin7594 -> 5126 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_15.pngbin6541 -> 4335 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_16.pngbin6003 -> 2883 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_17.pngbin5615 -> 2632 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_18.pngbin5280 -> 2476 bytes
-rw-r--r--res/drawable-xhdpi/tv_2a_19.pngbin5159 -> 2211 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_01.pngbin5159 -> 2211 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_02.pngbin4978 -> 2222 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_03.pngbin4858 -> 2089 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_04.pngbin4756 -> 2003 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_05.pngbin4614 -> 1934 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_06.pngbin4551 -> 1863 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_07.pngbin4322 -> 1747 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_08.pngbin4230 -> 1679 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_09.pngbin4119 -> 1595 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_10.pngbin4039 -> 1551 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_11.pngbin3979 -> 1496 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_12.pngbin3800 -> 1427 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_13.pngbin3624 -> 1348 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_14.pngbin3371 -> 1275 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_15.pngbin3170 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_16.pngbin2785 -> 1045 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_17.pngbin2617 -> 987 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_18.pngbin2364 -> 886 bytes
-rw-r--r--res/drawable-xhdpi/tv_2b_19.pngbin2059 -> 812 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_01.pngbin1038 -> 216 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_02.pngbin1240 -> 351 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_03.pngbin1970 -> 850 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_04.pngbin3399 -> 1833 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_05.pngbin5445 -> 3958 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_06.pngbin7325 -> 5285 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_07.pngbin7690 -> 5482 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_08.pngbin7390 -> 5369 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_09.pngbin7150 -> 5180 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_10.pngbin6990 -> 5172 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_11.pngbin6898 -> 5146 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_12.pngbin5809 -> 4283 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_13.pngbin5046 -> 3736 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_14.pngbin4544 -> 3386 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_15.pngbin4200 -> 2300 bytes
-rw-r--r--res/drawable-xhdpi/tv_2c_16.pngbin3995 -> 2027 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_00.pngbin892 -> 106 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_01.pngbin990 -> 158 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_02.pngbin995 -> 197 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_03.pngbin1097 -> 237 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_04.pngbin1255 -> 303 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_05.pngbin1260 -> 323 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_06.pngbin1311 -> 327 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_07.pngbin1357 -> 393 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_08.pngbin1418 -> 418 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_09.pngbin1400 -> 413 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_10.pngbin1461 -> 441 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_11.pngbin1636 -> 487 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_12.pngbin1642 -> 498 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_13.pngbin1725 -> 522 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_14.pngbin1841 -> 532 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_15.pngbin1775 -> 526 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_16.pngbin1702 -> 388 bytes
-rw-r--r--res/drawable-xhdpi/tv_3a_17.pngbin1657 -> 308 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_100.pngbin2051 -> 519 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_101.pngbin1697 -> 378 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_102.pngbin1820 -> 520 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_103.pngbin1819 -> 515 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_104.pngbin1824 -> 528 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_105.pngbin1827 -> 528 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_106.pngbin1897 -> 566 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_107.pngbin1889 -> 566 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_108.pngbin1958 -> 615 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_109.pngbin1961 -> 615 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_110.pngbin1910 -> 597 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_111.pngbin1912 -> 600 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_112.pngbin1939 -> 631 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_113.pngbin1935 -> 631 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_114.pngbin1935 -> 619 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_115.pngbin1936 -> 623 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_116.pngbin1935 -> 597 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_117.pngbin1935 -> 597 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_118.pngbin1937 -> 594 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_75.pngbin1657 -> 308 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_76.pngbin1681 -> 319 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_77.pngbin1726 -> 329 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_78.pngbin1851 -> 364 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_79.pngbin2077 -> 517 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_80.pngbin2313 -> 628 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_81.pngbin2452 -> 666 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_82.pngbin2831 -> 755 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_83.pngbin3013 -> 799 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_84.pngbin3064 -> 817 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_85.pngbin3073 -> 812 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_86.pngbin3187 -> 854 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_87.pngbin3252 -> 843 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_88.pngbin3181 -> 870 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_89.pngbin3204 -> 875 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_90.pngbin3132 -> 829 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_91.pngbin3070 -> 822 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_92.pngbin3053 -> 827 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_93.pngbin3020 -> 812 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_94.pngbin2971 -> 820 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_95.pngbin2918 -> 802 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_96.pngbin2755 -> 770 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_97.pngbin2611 -> 732 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_98.pngbin2387 -> 689 bytes
-rw-r--r--res/drawable-xhdpi/tv_3b_99.pngbin2249 -> 650 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_1.pngbin116 -> 115 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_10.pngbin1331 -> 1267 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_100.pngbin5624 -> 5329 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_101.pngbin5797 -> 5517 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_102.pngbin5881 -> 5575 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_103.pngbin6012 -> 5720 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_104.pngbin5827 -> 5553 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_105.pngbin5946 -> 5681 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_106.pngbin6027 -> 5782 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_107.pngbin6201 -> 5898 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_108.pngbin6252 -> 5958 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_109.pngbin6509 -> 6163 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_11.pngbin1359 -> 1287 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_110.pngbin6202 -> 5937 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_111.pngbin6187 -> 5944 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_112.pngbin6057 -> 5794 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_113.pngbin6021 -> 5743 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_114.pngbin5966 -> 5727 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_115.pngbin5861 -> 5595 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_116.pngbin5777 -> 5517 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_117.pngbin5557 -> 5277 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_118.pngbin5434 -> 5176 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_119.pngbin5262 -> 5005 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_12.pngbin1389 -> 1316 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_120.pngbin5176 -> 4908 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_121.pngbin5216 -> 4932 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_122.pngbin5089 -> 4766 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_123.pngbin4941 -> 4595 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_124.pngbin4818 -> 4443 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_125.pngbin4886 -> 4528 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_126.pngbin4800 -> 4440 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_127.pngbin4761 -> 4438 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_128.pngbin4813 -> 4478 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_129.pngbin4839 -> 4521 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_13.pngbin1471 -> 1400 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_130.pngbin4526 -> 4198 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_131.pngbin4573 -> 4242 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_132.pngbin4674 -> 4338 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_133.pngbin4631 -> 4360 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_134.pngbin4574 -> 4295 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_135.pngbin5077 -> 4827 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_136.pngbin4905 -> 4598 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_137.pngbin4692 -> 4326 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_138.pngbin4451 -> 4120 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_139.pngbin4381 -> 4052 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_14.pngbin1615 -> 1507 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_140.pngbin4287 -> 3976 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_141.pngbin4224 -> 3933 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_142.pngbin4093 -> 3761 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_143.pngbin4076 -> 3709 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_144.pngbin4062 -> 3708 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_145.pngbin4161 -> 3814 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_146.pngbin4185 -> 3858 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_147.pngbin3792 -> 3515 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_148.pngbin3650 -> 3373 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_149.pngbin3586 -> 3294 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_15.pngbin1680 -> 1588 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_150.pngbin3785 -> 3459 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_151.pngbin3619 -> 3315 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_152.pngbin3735 -> 3403 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_153.pngbin3606 -> 3302 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_154.pngbin3638 -> 3340 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_155.pngbin3568 -> 3282 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_156.pngbin3533 -> 3261 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_157.pngbin3259 -> 2997 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_158.pngbin3304 -> 3071 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_159.pngbin3147 -> 2902 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_16.pngbin1890 -> 1785 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_160.pngbin3344 -> 3054 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_161.pngbin3304 -> 3024 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_162.pngbin3132 -> 2891 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_163.pngbin3279 -> 3004 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_164.pngbin3304 -> 3047 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_165.pngbin3221 -> 2969 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_166.pngbin3139 -> 2878 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_167.pngbin2903 -> 2681 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_168.pngbin2856 -> 2626 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_169.pngbin2854 -> 2616 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_17.pngbin2027 -> 1931 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_170.pngbin2667 -> 2452 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_171.pngbin2714 -> 2506 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_172.pngbin2597 -> 2387 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_173.pngbin2571 -> 2358 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_174.pngbin2668 -> 2462 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_175.pngbin2715 -> 2510 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_176.pngbin2580 -> 2370 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_177.pngbin2465 -> 2262 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_178.pngbin2398 -> 2200 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_179.pngbin2422 -> 2209 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_18.pngbin2049 -> 1951 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_180.pngbin2503 -> 2316 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_181.pngbin2518 -> 2321 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_182.pngbin2560 -> 2376 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_183.pngbin2534 -> 2322 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_184.pngbin2515 -> 2321 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_185.pngbin2508 -> 2316 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_186.pngbin2457 -> 2267 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_187.pngbin2517 -> 2329 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_188.pngbin2568 -> 2401 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_189.pngbin2622 -> 2449 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_19.pngbin2090 -> 2002 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_190.pngbin2577 -> 2390 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_191.pngbin2504 -> 2321 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_192.pngbin2493 -> 2303 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_193.pngbin2542 -> 2362 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_194.pngbin2512 -> 2340 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_195.pngbin2392 -> 2213 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_196.pngbin2356 -> 2169 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_197.pngbin2289 -> 2135 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_198.pngbin2208 -> 2026 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_199.pngbin2065 -> 1880 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_2.pngbin423 -> 380 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_20.pngbin2315 -> 2220 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_200.pngbin1987 -> 1833 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_201.pngbin1913 -> 1745 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_202.pngbin1954 -> 1779 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_203.pngbin1942 -> 1771 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_204.pngbin2044 -> 1881 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_205.pngbin2051 -> 1870 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_206.pngbin2047 -> 1864 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_207.pngbin2063 -> 1874 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_208.pngbin2057 -> 1878 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_209.pngbin2082 -> 1910 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_21.pngbin2533 -> 2414 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_210.pngbin1998 -> 1816 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_211.pngbin1986 -> 1807 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_212.pngbin1968 -> 1791 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_213.pngbin1750 -> 1579 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_214.pngbin1750 -> 1577 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_215.pngbin1767 -> 1604 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_216.pngbin1889 -> 1726 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_217.pngbin1807 -> 1662 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_218.pngbin1802 -> 1645 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_219.pngbin1789 -> 1617 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_22.pngbin2611 -> 2489 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_220.pngbin1838 -> 1673 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_221.pngbin1761 -> 1610 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_222.pngbin1603 -> 1451 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_223.pngbin1513 -> 1357 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_224.pngbin1518 -> 1357 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_23.pngbin2663 -> 2549 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_24.pngbin2785 -> 2656 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_25.pngbin2924 -> 2799 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_26.pngbin2996 -> 2869 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_27.pngbin3174 -> 3045 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_28.pngbin3258 -> 3121 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_29.pngbin3399 -> 3254 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_3.pngbin536 -> 496 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_30.pngbin3554 -> 3390 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_31.pngbin3657 -> 3494 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_32.pngbin3674 -> 3521 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_33.pngbin3663 -> 3485 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_34.pngbin3739 -> 3546 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_35.pngbin4212 -> 3990 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_36.pngbin4681 -> 4419 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_37.pngbin4595 -> 4364 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_38.pngbin4779 -> 4500 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_39.pngbin4896 -> 4547 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_4.pngbin675 -> 633 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_40.pngbin5001 -> 4595 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_41.pngbin5157 -> 4741 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_42.pngbin5029 -> 4657 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_43.pngbin4997 -> 4505 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_44.pngbin4917 -> 4581 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_45.pngbin4788 -> 4448 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_46.pngbin5094 -> 4721 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_47.pngbin4979 -> 4723 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_48.pngbin4784 -> 4556 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_49.pngbin4695 -> 4433 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_5.pngbin813 -> 768 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_50.pngbin4682 -> 4448 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_51.pngbin4927 -> 4641 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_52.pngbin5036 -> 4732 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_53.pngbin5143 -> 4845 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_54.pngbin5171 -> 4880 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_55.pngbin5217 -> 4950 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_56.pngbin5077 -> 4817 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_57.pngbin5031 -> 4749 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_58.pngbin4951 -> 4665 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_59.pngbin4955 -> 4683 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_6.pngbin915 -> 871 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_60.pngbin5055 -> 4802 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_61.pngbin5082 -> 4814 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_62.pngbin5141 -> 4897 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_63.pngbin5192 -> 4921 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_64.pngbin4737 -> 4437 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_65.pngbin4659 -> 4378 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_66.pngbin4757 -> 4525 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_67.pngbin4894 -> 4640 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_68.pngbin4968 -> 4711 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_69.pngbin4792 -> 4508 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_7.pngbin993 -> 951 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_70.pngbin5197 -> 4858 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_71.pngbin5462 -> 5107 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_72.pngbin5438 -> 5131 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_73.pngbin5450 -> 5163 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_74.pngbin5568 -> 5270 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_75.pngbin5466 -> 5176 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_76.pngbin5385 -> 5091 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_77.pngbin5307 -> 4985 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_78.pngbin5251 -> 4955 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_79.pngbin5443 -> 5129 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_8.pngbin1122 -> 1074 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_80.pngbin5450 -> 5129 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_81.pngbin5548 -> 5204 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_82.pngbin5651 -> 5295 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_83.pngbin5498 -> 5152 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_84.pngbin5461 -> 5137 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_85.pngbin5500 -> 5195 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_86.pngbin5541 -> 5214 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_87.pngbin5402 -> 5108 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_88.pngbin5584 -> 5276 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_89.pngbin5584 -> 5307 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_9.pngbin1257 -> 1195 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_90.pngbin5977 -> 5684 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_91.pngbin5800 -> 5526 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_92.pngbin5630 -> 5356 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_93.pngbin5672 -> 5402 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_94.pngbin5541 -> 5273 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_95.pngbin5232 -> 4963 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_96.pngbin5236 -> 4977 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_97.pngbin5291 -> 5036 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_98.pngbin5116 -> 4886 bytes
-rw-r--r--res/drawable-xhdpi/tv_5a_99.pngbin5338 -> 5081 bytes
-rw-r--r--res/drawable-xhdpi/tv_bg.pngbin765 -> 108 bytes
-rw-r--r--res/drawable-xhdpi/tv_error.pngbin5430 -> 2846 bytes
-rw-r--r--res/drawable-xhdpi/tv_shadow.pngbin706 -> 497 bytes
-rw-r--r--res/drawable-xhdpi/tv_usb_antenna.pngbin25405 -> 21390 bytes
-rw-r--r--res/drawable-xhdpi/usb_antenna.pngbin2897 -> 1639 bytes
-rw-r--r--res/drawable/dvr_selector_background.xml26
-rw-r--r--res/drawable/ic_dvr_badge.xml (renamed from res/drawable/ic_record_start.xml)4
-rw-r--r--res/drawable/priority_settings_action_item_selected.xml26
-rw-r--r--res/drawable/progress_horizontal.xml2
-rw-r--r--res/layout/activity_dvr_details.xml20
-rw-r--r--res/layout/activity_dvr_playback.xml48
-rw-r--r--res/layout/activity_dvr_schedules.xml36
-rw-r--r--res/layout/activity_dvr_series_settings.xml20
-rw-r--r--res/layout/activity_tv.xml21
-rw-r--r--res/layout/block_screen.xml4
-rw-r--r--res/layout/channel_banner.xml13
-rw-r--r--res/layout/dvr_details_description.xml69
-rw-r--r--res/layout/dvr_recording_card_view.xml103
-rw-r--r--res/layout/dvr_schedules_header.xml73
-rw-r--r--res/layout/dvr_schedules_header_button.xml27
-rw-r--r--res/layout/dvr_schedules_item.xml141
-rw-r--r--res/layout/guided_action_divider.xml (renamed from res/layout/onboarding_item_divider.xml)0
-rw-r--r--res/layout/halfsized_dialog.xml9
-rw-r--r--res/layout/halfsized_guidance.xml45
-rw-r--r--res/layout/lb_details_overview.xml89
-rw-r--r--res/layout/menu_card_app_link.xml26
-rw-r--r--res/layout/menu_card_channel.xml26
-rw-r--r--res/layout/menu_card_dvr.xml18
-rw-r--r--res/layout/menu_card_setup.xml4
-rw-r--r--res/layout/menu_card_text.xml (renamed from res/layout/menu_card_record.xml)44
-rw-r--r--res/layout/overlay_root_view.xml43
-rw-r--r--res/layout/play_controls_contents.xml43
-rw-r--r--res/layout/priority_settings_action_item.xml56
-rw-r--r--res/layout/program_guide_critic_score_layout.xml48
-rw-r--r--res/layout/program_guide_table_row.xml4
-rw-r--r--res/layout/program_guide_table_row_detail.xml44
-rw-r--r--res/layout/program_track_meta.xml20
-rw-r--r--res/layout/tunable_tv_view.xml14
-rw-r--r--res/values-af/arrays.xml52
-rw-r--r--res/values-af/rating_system_strings.xml48
-rw-r--r--res/values-af/strings.xml168
-rw-r--r--res/values-am/arrays.xml52
-rw-r--r--res/values-am/rating_system_strings.xml48
-rw-r--r--res/values-am/strings.xml168
-rw-r--r--res/values-ar/arrays.xml52
-rw-r--r--res/values-ar/rating_system_strings.xml48
-rw-r--r--res/values-ar/strings.xml212
-rw-r--r--res/values-az-rAZ/arrays.xml52
-rw-r--r--res/values-az-rAZ/rating_system_strings.xml48
-rw-r--r--res/values-az-rAZ/strings.xml168
-rw-r--r--res/values-bg/arrays.xml52
-rw-r--r--res/values-bg/rating_system_strings.xml48
-rw-r--r--res/values-bg/strings.xml168
-rw-r--r--res/values-bn-rBD/arrays.xml52
-rw-r--r--res/values-bn-rBD/rating_system_strings.xml48
-rw-r--r--res/values-bn-rBD/strings.xml168
-rw-r--r--res/values-ca/arrays.xml52
-rw-r--r--res/values-ca/rating_system_strings.xml48
-rw-r--r--res/values-ca/strings.xml170
-rw-r--r--res/values-cs/arrays.xml52
-rw-r--r--res/values-cs/rating_system_strings.xml48
-rw-r--r--res/values-cs/strings.xml194
-rw-r--r--res/values-da/arrays.xml52
-rw-r--r--res/values-da/rating_system_strings.xml48
-rw-r--r--res/values-da/strings.xml168
-rw-r--r--res/values-de/arrays.xml52
-rw-r--r--res/values-de/rating_system_strings.xml48
-rw-r--r--res/values-de/strings.xml168
-rw-r--r--res/values-el/arrays.xml52
-rw-r--r--res/values-el/rating_system_strings.xml48
-rw-r--r--res/values-el/strings.xml168
-rw-r--r--res/values-en-rAU/arrays.xml52
-rw-r--r--res/values-en-rAU/rating_system_strings.xml48
-rw-r--r--res/values-en-rAU/strings.xml172
-rw-r--r--res/values-en-rGB/arrays.xml52
-rw-r--r--res/values-en-rGB/rating_system_strings.xml48
-rw-r--r--res/values-en-rGB/strings.xml172
-rw-r--r--res/values-en-rIN/arrays.xml52
-rw-r--r--res/values-en-rIN/rating_system_strings.xml48
-rw-r--r--res/values-en-rIN/strings.xml172
-rw-r--r--res/values-es-rUS/arrays.xml52
-rw-r--r--res/values-es-rUS/rating_system_strings.xml48
-rw-r--r--res/values-es-rUS/strings.xml168
-rw-r--r--res/values-es/arrays.xml52
-rw-r--r--res/values-es/rating_system_strings.xml48
-rw-r--r--res/values-es/strings.xml168
-rw-r--r--res/values-et-rEE/arrays.xml52
-rw-r--r--res/values-et-rEE/rating_system_strings.xml48
-rw-r--r--res/values-et-rEE/strings.xml168
-rw-r--r--res/values-eu-rES/arrays.xml52
-rw-r--r--res/values-eu-rES/rating_system_strings.xml48
-rw-r--r--res/values-eu-rES/strings.xml170
-rw-r--r--res/values-fa/arrays.xml52
-rw-r--r--res/values-fa/rating_system_strings.xml48
-rw-r--r--res/values-fa/strings.xml170
-rw-r--r--res/values-fi/arrays.xml52
-rw-r--r--res/values-fi/rating_system_strings.xml48
-rw-r--r--res/values-fi/strings.xml168
-rw-r--r--res/values-fr-rCA/arrays.xml52
-rw-r--r--res/values-fr-rCA/rating_system_strings.xml48
-rw-r--r--res/values-fr-rCA/strings.xml168
-rw-r--r--res/values-fr/arrays.xml52
-rw-r--r--res/values-fr/rating_system_strings.xml48
-rw-r--r--res/values-fr/strings.xml168
-rw-r--r--res/values-gl-rES/arrays.xml52
-rw-r--r--res/values-gl-rES/rating_system_strings.xml48
-rw-r--r--res/values-gl-rES/strings.xml168
-rw-r--r--res/values-hi/arrays.xml52
-rw-r--r--res/values-hi/rating_system_strings.xml48
-rw-r--r--res/values-hi/strings.xml168
-rw-r--r--res/values-hr/arrays.xml52
-rw-r--r--res/values-hr/rating_system_strings.xml48
-rw-r--r--res/values-hr/strings.xml179
-rw-r--r--res/values-hu/arrays.xml52
-rw-r--r--res/values-hu/rating_system_strings.xml48
-rw-r--r--res/values-hu/strings.xml168
-rw-r--r--res/values-hy-rAM/arrays.xml52
-rw-r--r--res/values-hy-rAM/rating_system_strings.xml48
-rw-r--r--res/values-hy-rAM/strings.xml168
-rw-r--r--res/values-in/arrays.xml52
-rw-r--r--res/values-in/rating_system_strings.xml48
-rw-r--r--res/values-in/strings.xml168
-rw-r--r--res/values-is-rIS/arrays.xml52
-rw-r--r--res/values-is-rIS/rating_system_strings.xml48
-rw-r--r--res/values-is-rIS/strings.xml168
-rw-r--r--res/values-it/arrays.xml52
-rw-r--r--res/values-it/rating_system_strings.xml48
-rw-r--r--res/values-it/strings.xml168
-rw-r--r--res/values-iw/arrays.xml52
-rw-r--r--res/values-iw/rating_system_strings.xml48
-rw-r--r--res/values-iw/strings.xml190
-rw-r--r--res/values-ja/arrays.xml52
-rw-r--r--res/values-ja/rating_system_strings.xml48
-rw-r--r--res/values-ja/strings.xml174
-rw-r--r--res/values-ka-rGE/arrays.xml52
-rw-r--r--res/values-ka-rGE/rating_system_strings.xml48
-rw-r--r--res/values-ka-rGE/strings.xml168
-rw-r--r--res/values-kk-rKZ/arrays.xml52
-rw-r--r--res/values-kk-rKZ/rating_system_strings.xml48
-rw-r--r--res/values-kk-rKZ/strings.xml168
-rw-r--r--res/values-km-rKH/arrays.xml52
-rw-r--r--res/values-km-rKH/rating_system_strings.xml48
-rw-r--r--res/values-km-rKH/strings.xml168
-rw-r--r--res/values-kn-rIN/arrays.xml54
-rw-r--r--res/values-kn-rIN/rating_system_strings.xml48
-rw-r--r--res/values-kn-rIN/strings.xml174
-rw-r--r--res/values-ko/arrays.xml52
-rw-r--r--res/values-ko/rating_system_strings.xml48
-rw-r--r--res/values-ko/strings.xml168
-rw-r--r--res/values-ky-rKG/arrays.xml52
-rw-r--r--res/values-ky-rKG/rating_system_strings.xml48
-rw-r--r--res/values-ky-rKG/strings.xml168
-rw-r--r--res/values-lo-rLA/arrays.xml52
-rw-r--r--res/values-lo-rLA/rating_system_strings.xml48
-rw-r--r--res/values-lo-rLA/strings.xml168
-rw-r--r--res/values-lt/arrays.xml52
-rw-r--r--res/values-lt/rating_system_strings.xml48
-rw-r--r--res/values-lt/strings.xml190
-rw-r--r--res/values-lv/arrays.xml52
-rw-r--r--res/values-lv/rating_system_strings.xml48
-rw-r--r--res/values-lv/strings.xml176
-rw-r--r--res/values-mk-rMK/arrays.xml52
-rw-r--r--res/values-mk-rMK/rating_system_strings.xml48
-rw-r--r--res/values-mk-rMK/strings.xml198
-rw-r--r--res/values-ml-rIN/arrays.xml52
-rw-r--r--res/values-ml-rIN/rating_system_strings.xml48
-rw-r--r--res/values-ml-rIN/strings.xml170
-rw-r--r--res/values-mn-rMN/arrays.xml52
-rw-r--r--res/values-mn-rMN/rating_system_strings.xml48
-rw-r--r--res/values-mn-rMN/strings.xml168
-rw-r--r--res/values-mr-rIN/arrays.xml52
-rw-r--r--res/values-mr-rIN/rating_system_strings.xml48
-rw-r--r--res/values-mr-rIN/strings.xml168
-rw-r--r--res/values-ms-rMY/arrays.xml52
-rw-r--r--res/values-ms-rMY/rating_system_strings.xml48
-rw-r--r--res/values-ms-rMY/strings.xml168
-rw-r--r--res/values-my-rMM/arrays.xml54
-rw-r--r--res/values-my-rMM/rating_system_strings.xml48
-rw-r--r--res/values-my-rMM/strings.xml174
-rw-r--r--res/values-nb/arrays.xml52
-rw-r--r--res/values-nb/rating_system_strings.xml48
-rw-r--r--res/values-nb/strings.xml168
-rw-r--r--res/values-ne-rNP/arrays.xml52
-rw-r--r--res/values-ne-rNP/rating_system_strings.xml48
-rw-r--r--res/values-ne-rNP/strings.xml172
-rw-r--r--res/values-nl/arrays.xml52
-rw-r--r--res/values-nl/rating_system_strings.xml48
-rw-r--r--res/values-nl/strings.xml174
-rw-r--r--res/values-pl/arrays.xml52
-rw-r--r--res/values-pl/rating_system_strings.xml48
-rw-r--r--res/values-pl/strings.xml190
-rw-r--r--res/values-pt-rPT/arrays.xml52
-rw-r--r--res/values-pt-rPT/rating_system_strings.xml48
-rw-r--r--res/values-pt-rPT/strings.xml168
-rw-r--r--res/values-pt/arrays.xml52
-rw-r--r--res/values-pt/rating_system_strings.xml48
-rw-r--r--res/values-pt/strings.xml168
-rw-r--r--res/values-ro/arrays.xml52
-rw-r--r--res/values-ro/rating_system_strings.xml48
-rw-r--r--res/values-ro/strings.xml179
-rw-r--r--res/values-ru/arrays.xml52
-rw-r--r--res/values-ru/rating_system_strings.xml48
-rw-r--r--res/values-ru/strings.xml190
-rw-r--r--res/values-si-rLK/arrays.xml52
-rw-r--r--res/values-si-rLK/rating_system_strings.xml48
-rw-r--r--res/values-si-rLK/strings.xml168
-rw-r--r--res/values-sk/arrays.xml52
-rw-r--r--res/values-sk/rating_system_strings.xml48
-rw-r--r--res/values-sk/strings.xml190
-rw-r--r--res/values-sl/arrays.xml52
-rw-r--r--res/values-sl/rating_system_strings.xml48
-rw-r--r--res/values-sl/strings.xml190
-rw-r--r--res/values-sr/arrays.xml52
-rw-r--r--res/values-sr/rating_system_strings.xml48
-rw-r--r--res/values-sr/strings.xml189
-rw-r--r--res/values-sv/arrays.xml52
-rw-r--r--res/values-sv/rating_system_strings.xml48
-rw-r--r--res/values-sv/strings.xml168
-rw-r--r--res/values-sw/arrays.xml52
-rw-r--r--res/values-sw/rating_system_strings.xml48
-rw-r--r--res/values-sw/strings.xml168
-rw-r--r--res/values-ta-rIN/arrays.xml52
-rw-r--r--res/values-ta-rIN/rating_system_strings.xml48
-rw-r--r--res/values-ta-rIN/strings.xml168
-rw-r--r--res/values-te-rIN/arrays.xml52
-rw-r--r--res/values-te-rIN/rating_system_strings.xml48
-rw-r--r--res/values-te-rIN/strings.xml168
-rw-r--r--res/values-th/arrays.xml52
-rw-r--r--res/values-th/rating_system_strings.xml48
-rw-r--r--res/values-th/strings.xml170
-rw-r--r--res/values-tl/arrays.xml52
-rw-r--r--res/values-tl/rating_system_strings.xml48
-rw-r--r--res/values-tl/strings.xml168
-rw-r--r--res/values-tr/arrays.xml52
-rw-r--r--res/values-tr/rating_system_strings.xml48
-rw-r--r--res/values-tr/strings.xml168
-rw-r--r--res/values-uk/arrays.xml52
-rw-r--r--res/values-uk/rating_system_strings.xml48
-rw-r--r--res/values-uk/strings.xml190
-rw-r--r--res/values-ur-rPK/arrays.xml52
-rw-r--r--res/values-ur-rPK/rating_system_strings.xml48
-rw-r--r--res/values-ur-rPK/strings.xml168
-rw-r--r--res/values-uz-rUZ/arrays.xml52
-rw-r--r--res/values-uz-rUZ/rating_system_strings.xml48
-rw-r--r--res/values-uz-rUZ/strings.xml172
-rw-r--r--res/values-vi/arrays.xml52
-rw-r--r--res/values-vi/rating_system_strings.xml48
-rw-r--r--res/values-vi/strings.xml168
-rw-r--r--res/values-zh-rCN/arrays.xml52
-rw-r--r--res/values-zh-rCN/rating_system_strings.xml48
-rw-r--r--res/values-zh-rCN/strings.xml168
-rw-r--r--res/values-zh-rHK/arrays.xml52
-rw-r--r--res/values-zh-rHK/rating_system_strings.xml48
-rw-r--r--res/values-zh-rHK/strings.xml168
-rw-r--r--res/values-zh-rTW/arrays.xml52
-rw-r--r--res/values-zh-rTW/rating_system_strings.xml48
-rw-r--r--res/values-zh-rTW/strings.xml170
-rw-r--r--res/values-zu/arrays.xml52
-rw-r--r--res/values-zu/rating_system_strings.xml48
-rw-r--r--res/values-zu/strings.xml168
-rw-r--r--res/values/arrays.xml25
-rw-r--r--res/values/colors.xml18
-rw-r--r--res/values/dimens.xml87
-rwxr-xr-xres/values/google-services.xml8
-rw-r--r--res/values/integers.xml3
-rw-r--r--res/values/rating_system_strings.xml48
-rw-r--r--res/values/strings.xml466
-rw-r--r--res/values/styles.xml89
-rw-r--r--res/values/themes.xml45
-rw-r--r--res/xml/remote_config_defaults.xml22
-rw-r--r--src/com/android/exoplayer/MediaFormatUtil.java (renamed from usbtuner/src/com/google/android/exoplayer/MediaFormatUtil.java)33
-rw-r--r--src/com/android/exoplayer/MediaSoftwareCodecUtil.java (renamed from usbtuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java)20
-rw-r--r--src/com/android/exoplayer/text/SubtitleView.java (renamed from usbtuner/src/com/google/android/exoplayer/text/SubtitleView.java)29
-rw-r--r--src/com/android/tv/ApplicationSingletons.java18
-rw-r--r--src/com/android/tv/Features.java61
-rw-r--r--src/com/android/tv/InputSessionManager.java549
-rw-r--r--src/com/android/tv/MainActivity.java776
-rw-r--r--src/com/android/tv/MainActivityWrapper.java5
-rw-r--r--src/com/android/tv/SetupPassthroughActivity.java23
-rw-r--r--src/com/android/tv/TimeShiftManager.java165
-rw-r--r--src/com/android/tv/TvApplication.java230
-rw-r--r--src/com/android/tv/TvOptionsManager.java3
-rw-r--r--src/com/android/tv/config/ConfigKeys.java (renamed from src/com/android/tv/dvr/ui/EmptyHolder.java)10
-rw-r--r--src/com/android/tv/config/DefaultConfigManager.java55
-rw-r--r--src/com/android/tv/config/RemoteConfig.java48
-rw-r--r--src/com/android/tv/config/RemoteConfigFeature.java43
-rw-r--r--src/com/android/tv/data/BaseProgram.java177
-rw-r--r--src/com/android/tv/data/Channel.java52
-rw-r--r--src/com/android/tv/data/ChannelDataManager.java22
-rw-r--r--src/com/android/tv/data/GenreItems.java34
-rw-r--r--src/com/android/tv/data/InternalDataUtils.java133
-rw-r--r--src/com/android/tv/data/Lineup.java94
-rw-r--r--src/com/android/tv/data/ParcelableList.java86
-rw-r--r--src/com/android/tv/data/Program.java501
-rw-r--r--src/com/android/tv/data/ProgramDataManager.java31
-rw-r--r--src/com/android/tv/data/StreamInfo.java3
-rw-r--r--src/com/android/tv/data/WatchedHistoryManager.java2
-rw-r--r--src/com/android/tv/data/epg/EpgFetcher.java387
-rw-r--r--src/com/android/tv/data/epg/EpgReader.java15
-rw-r--r--src/com/android/tv/data/epg/StubEpgReader.java20
-rw-r--r--src/com/android/tv/dialog/PinDialogFragment.java15
-rw-r--r--src/com/android/tv/dialog/SafeDismissDialogFragment.java6
-rw-r--r--src/com/android/tv/dvr/BaseDvrDataManager.java210
-rw-r--r--src/com/android/tv/dvr/ConflictChecker.java277
-rw-r--r--src/com/android/tv/dvr/DvrDataManager.java154
-rw-r--r--src/com/android/tv/dvr/DvrDataManagerImpl.java846
-rw-r--r--src/com/android/tv/dvr/DvrDbSync.java363
-rw-r--r--src/com/android/tv/dvr/DvrManager.java786
-rw-r--r--src/com/android/tv/dvr/DvrPlayActivity.java47
-rw-r--r--src/com/android/tv/dvr/DvrPlaybackActivity.java67
-rw-r--r--src/com/android/tv/dvr/DvrPlaybackMediaSessionHelper.java327
-rw-r--r--src/com/android/tv/dvr/DvrPlayer.java425
-rw-r--r--src/com/android/tv/dvr/DvrRecordingService.java35
-rw-r--r--src/com/android/tv/dvr/DvrScheduleManager.java980
-rw-r--r--src/com/android/tv/dvr/DvrSessionManager.java130
-rw-r--r--src/com/android/tv/dvr/DvrStartRecordingReceiver.java3
-rw-r--r--src/com/android/tv/dvr/DvrStorageStatusManager.java376
-rw-r--r--src/com/android/tv/dvr/DvrUiHelper.java450
-rw-r--r--src/com/android/tv/dvr/DvrWatchedPositionManager.java154
-rw-r--r--src/com/android/tv/dvr/EpisodicProgramLoadTask.java382
-rw-r--r--src/com/android/tv/dvr/IdGenerator.java50
-rw-r--r--src/com/android/tv/dvr/InputTaskScheduler.java431
-rw-r--r--src/com/android/tv/dvr/RecordedProgram.java (renamed from common/src/com/android/tv/common/recording/RecordedProgram.java)290
-rw-r--r--src/com/android/tv/dvr/RecordingTask.java368
-rw-r--r--src/com/android/tv/dvr/ScheduledProgramReaper.java20
-rw-r--r--src/com/android/tv/dvr/ScheduledRecording.java694
-rw-r--r--src/com/android/tv/dvr/Scheduler.java252
-rw-r--r--src/com/android/tv/dvr/SeriesInfo.java76
-rw-r--r--src/com/android/tv/dvr/SeriesRecording.java755
-rw-r--r--src/com/android/tv/dvr/SeriesRecordingScheduler.java579
-rw-r--r--src/com/android/tv/dvr/WritableDvrDataManager.java45
-rw-r--r--src/com/android/tv/dvr/provider/AsyncDvrDbTask.java137
-rw-r--r--src/com/android/tv/dvr/provider/DvrContract.java302
-rw-r--r--src/com/android/tv/dvr/provider/DvrDatabaseHelper.java362
-rw-r--r--src/com/android/tv/dvr/ui/ActionPresenterSelector.java138
-rw-r--r--src/com/android/tv/dvr/ui/CurrentRecordingDetailsFragment.java59
-rw-r--r--src/com/android/tv/dvr/ui/DetailsContent.java207
-rw-r--r--src/com/android/tv/dvr/ui/DetailsContentPresenter.java300
-rw-r--r--src/com/android/tv/dvr/ui/DetailsViewBackgroundHelper.java92
-rw-r--r--src/com/android/tv/dvr/ui/DvrActivity.java2
-rw-r--r--src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java103
-rw-r--r--src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java107
-rw-r--r--src/com/android/tv/dvr/ui/DvrBrowseFragment.java610
-rw-r--r--src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java109
-rw-r--r--src/com/android/tv/dvr/ui/DvrConflictFragment.java339
-rw-r--r--src/com/android/tv/dvr/ui/DvrDetailsActivity.java98
-rw-r--r--src/com/android/tv/dvr/ui/DvrDetailsFragment.java344
-rw-r--r--src/com/android/tv/dvr/ui/DvrDialogFragment.java50
-rw-r--r--src/com/android/tv/dvr/ui/DvrForgetStorageErrorFragment.java87
-rw-r--r--src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java78
-rw-r--r--src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java74
-rw-r--r--src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java228
-rw-r--r--src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java71
-rw-r--r--src/com/android/tv/dvr/ui/DvrItemPresenter.java80
-rw-r--r--src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java79
-rw-r--r--src/com/android/tv/dvr/ui/DvrPlaybackCardPresenter.java82
-rw-r--r--src/com/android/tv/dvr/ui/DvrPlaybackControlHelper.java313
-rw-r--r--src/com/android/tv/dvr/ui/DvrPlaybackOverlayFragment.java304
-rw-r--r--src/com/android/tv/dvr/ui/DvrRecordConflictFragment.java82
-rw-r--r--src/com/android/tv/dvr/ui/DvrRecordDeleteFragment.java48
-rw-r--r--src/com/android/tv/dvr/ui/DvrRecordScheduleFragment.java70
-rw-r--r--src/com/android/tv/dvr/ui/DvrScheduleFragment.java147
-rw-r--r--src/com/android/tv/dvr/ui/DvrSchedulesActivity.java104
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java50
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java48
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java154
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java82
-rw-r--r--src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java161
-rw-r--r--src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java48
-rw-r--r--src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java104
-rw-r--r--src/com/android/tv/dvr/ui/EmptyItemPresenter.java66
-rw-r--r--src/com/android/tv/dvr/ui/FullScheduleCardHolder.java (renamed from src/com/android/tv/dvr/SeasonRecording.java)20
-rw-r--r--src/com/android/tv/dvr/ui/FullSchedulesCardPresenter.java84
-rw-r--r--src/com/android/tv/dvr/ui/HalfSizedDialogFragment.java93
-rw-r--r--src/com/android/tv/dvr/ui/PrioritySettingsFragment.java251
-rw-r--r--src/com/android/tv/dvr/ui/RecordedProgramDetailsFragment.java170
-rw-r--r--src/com/android/tv/dvr/ui/RecordedProgramPresenter.java195
-rw-r--r--src/com/android/tv/dvr/ui/RecordedProgramsAdapter.java65
-rw-r--r--src/com/android/tv/dvr/ui/RecordingCardView.java102
-rw-r--r--src/com/android/tv/dvr/ui/RecordingDetailsFragment.java87
-rw-r--r--src/com/android/tv/dvr/ui/ScheduledRecordingDetailsFragment.java97
-rw-r--r--src/com/android/tv/dvr/ui/ScheduledRecordingPresenter.java200
-rw-r--r--src/com/android/tv/dvr/ui/ScheduledRecordingsAdapter.java85
-rw-r--r--src/com/android/tv/dvr/ui/SeriesDeletionFragment.java252
-rw-r--r--src/com/android/tv/dvr/ui/SeriesRecordingDetailsFragment.java375
-rw-r--r--src/com/android/tv/dvr/ui/SeriesRecordingPresenter.java234
-rw-r--r--src/com/android/tv/dvr/ui/SeriesSettingsFragment.java397
-rw-r--r--src/com/android/tv/dvr/ui/SortedArrayAdapter.java208
-rw-r--r--src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java178
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSchedulesFocusView.java88
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java86
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java208
-rw-r--r--src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java89
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRow.java203
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java425
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java795
-rw-r--r--src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java122
-rw-r--r--src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java273
-rw-r--r--src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java269
-rw-r--r--src/com/android/tv/dvr/ui/list/SeriesScheduleRowPresenter.java143
-rw-r--r--src/com/android/tv/experiments/ExperimentFlag.java42
-rw-r--r--src/com/android/tv/experiments/Experiments.java42
-rw-r--r--src/com/android/tv/guide/ProgramGuide.java67
-rw-r--r--src/com/android/tv/guide/ProgramItemView.java141
-rw-r--r--src/com/android/tv/guide/ProgramManager.java137
-rw-r--r--src/com/android/tv/guide/ProgramRow.java114
-rw-r--r--src/com/android/tv/guide/ProgramTableAdapter.java270
-rw-r--r--src/com/android/tv/menu/ActionCardView.java2
-rw-r--r--src/com/android/tv/menu/AppLinkCardView.java78
-rw-r--r--src/com/android/tv/menu/BaseCardView.java109
-rw-r--r--src/com/android/tv/menu/ChannelCardView.java99
-rw-r--r--src/com/android/tv/menu/ChannelsRowAdapter.java67
-rw-r--r--src/com/android/tv/menu/IMenuView.java7
-rw-r--r--src/com/android/tv/menu/Menu.java85
-rw-r--r--src/com/android/tv/menu/MenuAction.java5
-rw-r--r--src/com/android/tv/menu/MenuLayoutManager.java4
-rw-r--r--src/com/android/tv/menu/MenuRow.java17
-rw-r--r--src/com/android/tv/menu/MenuRowFactory.java8
-rw-r--r--src/com/android/tv/menu/MenuRowView.java19
-rw-r--r--src/com/android/tv/menu/MenuUpdater.java96
-rw-r--r--src/com/android/tv/menu/MenuView.java46
-rw-r--r--src/com/android/tv/menu/PlayControlsButton.java37
-rw-r--r--src/com/android/tv/menu/PlayControlsRow.java14
-rw-r--r--src/com/android/tv/menu/PlayControlsRowView.java297
-rw-r--r--src/com/android/tv/menu/RecordCardView.java189
-rw-r--r--src/com/android/tv/menu/SetupCardView.java53
-rw-r--r--src/com/android/tv/menu/SimpleCardView.java10
-rw-r--r--src/com/android/tv/menu/TvOptionsRowAdapter.java45
-rw-r--r--src/com/android/tv/onboarding/NewSourcesFragment.java33
-rw-r--r--src/com/android/tv/onboarding/OnboardingActivity.java88
-rw-r--r--src/com/android/tv/onboarding/SetupSourcesFragment.java216
-rw-r--r--src/com/android/tv/onboarding/WelcomeFragment.java6
-rw-r--r--src/com/android/tv/receiver/BootCompletedReceiver.java5
-rw-r--r--src/com/android/tv/receiver/GlobalKeyReceiver.java1
-rw-r--r--src/com/android/tv/receiver/PackageIntentsReceiver.java1
-rw-r--r--src/com/android/tv/recommendation/NotificationService.java27
-rw-r--r--src/com/android/tv/recommendation/RecommendationDataManager.java35
-rw-r--r--src/com/android/tv/search/DataManagerSearch.java36
-rw-r--r--src/com/android/tv/search/LocalSearchProvider.java10
-rw-r--r--src/com/android/tv/search/TvProviderSearch.java34
-rw-r--r--src/com/android/tv/setup/SystemSetupActivity.java124
-rw-r--r--src/com/android/tv/tuner/ChannelScanFileParser.java (renamed from usbtuner/src/com/android/usbtuner/ChannelScanFileParser.java)27
-rw-r--r--src/com/android/tv/tuner/DvbDeviceAccessor.java (renamed from usbtuner/src/com/android/usbtuner/DvbDeviceAccessor.java)42
-rw-r--r--src/com/android/tv/tuner/TunerHal.java (renamed from usbtuner/src/com/android/usbtuner/TunerHal.java)48
-rw-r--r--src/com/android/tv/tuner/TunerInputController.java (renamed from src/com/android/usbtuner/UsbInputController.java)67
-rw-r--r--src/com/android/tv/tuner/TunerPreferenceProvider.java (renamed from usbtuner/src/com/android/usbtuner/UsbTunerPreferenceProvider.java)21
-rw-r--r--src/com/android/tv/tuner/TunerPreferences.java310
-rw-r--r--src/com/android/tv/tuner/UsbTunerHal.java (renamed from usbtuner/src/com/android/usbtuner/UsbTunerHal.java)12
-rw-r--r--src/com/android/tv/tuner/cc/CaptionLayout.java (renamed from usbtuner/src/com/android/usbtuner/cc/CaptionLayout.java)6
-rw-r--r--src/com/android/tv/tuner/cc/CaptionTrackRenderer.java (renamed from usbtuner/src/com/android/usbtuner/cc/CaptionTrackRenderer.java)16
-rw-r--r--src/com/android/tv/tuner/cc/CaptionWindowLayout.java (renamed from usbtuner/src/com/android/usbtuner/cc/CaptionWindowLayout.java)117
-rw-r--r--src/com/android/tv/tuner/cc/Cea708Parser.java (renamed from usbtuner/src/com/android/usbtuner/cc/Cea708Parser.java)22
-rw-r--r--src/com/android/tv/tuner/data/Cea708Data.java (renamed from usbtuner/src/com/android/usbtuner/data/Cea708Data.java)11
-rw-r--r--src/com/android/tv/tuner/data/PsiData.java (renamed from usbtuner/src/com/android/usbtuner/data/PsiData.java)6
-rw-r--r--src/com/android/tv/tuner/data/PsipData.java (renamed from usbtuner/src/com/android/usbtuner/data/PsipData.java)33
-rw-r--r--src/com/android/tv/tuner/data/TunerChannel.java (renamed from usbtuner/src/com/android/usbtuner/data/TunerChannel.java)60
-rw-r--r--src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/Cea708TextTrackRenderer.java)24
-rw-r--r--src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java398
-rw-r--r--src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/ReplaySampleSourceExtractor.java)73
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPlayer.java)386
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPassthroughAc3RendererBuilder.java)42
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java335
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSource.java)56
-rw-r--r--src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/MpegTsVideoTrackRenderer.java)45
-rw-r--r--src/com/android/tv/tuner/exoplayer/SampleExtractor.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/SampleExtractor.java)44
-rw-r--r--src/com/android/tv/tuner/exoplayer/ac3/Ac3PassthroughTrackRenderer.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3TrackRenderer.java)113
-rw-r--r--src/com/android/tv/tuner/exoplayer/ac3/Ac3TrackRenderer.java94
-rw-r--r--src/com/android/tv/tuner/exoplayer/ac3/AudioClock.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioClock.java)31
-rw-r--r--src/com/android/tv/tuner/exoplayer/ac3/AudioTrackMonitor.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackMonitor.java)6
-rw-r--r--src/com/android/tv/tuner/exoplayer/ac3/AudioTrackWrapper.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackWrapper.java)37
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/CacheManager.java)409
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/DvrStorageManager.java)35
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java306
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java419
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java406
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/SamplePool.java)2
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleQueue.java)19
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/SimpleSampleBuffer.java)40
-rw-r--r--src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java (renamed from usbtuner/src/com/android/usbtuner/exoplayer/cache/TrickplayStorageManager.java)54
-rw-r--r--src/com/android/tv/tuner/layout/ScaledLayout.java (renamed from usbtuner/src/com/android/usbtuner/layout/ScaledLayout.java)30
-rw-r--r--src/com/android/tv/tuner/setup/ConnectionTypeFragment.java (renamed from usbtuner/src/com/android/usbtuner/setup/ConnectionTypeFragment.java)6
-rw-r--r--src/com/android/tv/tuner/setup/ScanFragment.java (renamed from usbtuner/src/com/android/usbtuner/setup/ScanFragment.java)240
-rw-r--r--src/com/android/tv/tuner/setup/ScanResultFragment.java (renamed from usbtuner/src/com/android/usbtuner/setup/ScanResultFragment.java)26
-rw-r--r--src/com/android/tv/tuner/setup/TunerSetupActivity.java (renamed from usbtuner/src/com/android/usbtuner/setup/TunerSetupActivity.java)90
-rw-r--r--src/com/android/tv/tuner/setup/WelcomeFragment.java (renamed from usbtuner/src/com/android/usbtuner/setup/WelcomeFragment.java)28
-rw-r--r--src/com/android/tv/tuner/source/FileTsStreamer.java (renamed from usbtuner/src/com/android/usbtuner/FileDataSource.java)189
-rw-r--r--src/com/android/tv/tuner/source/TsDataSource.java50
-rw-r--r--src/com/android/tv/tuner/source/TsDataSourceManager.java135
-rw-r--r--src/com/android/tv/tuner/source/TsStreamWriter.java237
-rw-r--r--src/com/android/tv/tuner/source/TsStreamer.java56
-rw-r--r--src/com/android/tv/tuner/source/TunerTsStreamer.java363
-rw-r--r--src/com/android/tv/tuner/source/TunerTsStreamerManager.java287
-rw-r--r--src/com/android/tv/tuner/ts/SectionParser.java (renamed from usbtuner/src/com/android/usbtuner/ts/SectionParser.java)102
-rw-r--r--src/com/android/tv/tuner/ts/TsParser.java (renamed from usbtuner/src/com/android/usbtuner/ts/TsParser.java)94
-rw-r--r--src/com/android/tv/tuner/tvinput/ChannelDataManager.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/ChannelDataManager.java)355
-rw-r--r--src/com/android/tv/tuner/tvinput/EventDetector.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/EventDetector.java)87
-rw-r--r--src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/FileSourceEventDetector.java)62
-rw-r--r--src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/PlaybackCacheListener.java)20
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerDebug.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/UsbTunerDebug.java)90
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerRecordingSession.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSession.java)26
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java594
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerSession.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/TunerSession.java)73
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerSessionWorker.java (renamed from usbtuner/src/com/android/usbtuner/tvinput/TunerSessionWorker.java)956
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java166
-rw-r--r--src/com/android/tv/tuner/tvinput/TunerTvInputService.java146
-rw-r--r--src/com/android/tv/tuner/util/ByteArrayBuffer.java (renamed from usbtuner/src/com/android/usbtuner/util/ByteArrayBuffer.java)2
-rw-r--r--src/com/android/tv/tuner/util/ConvertUtils.java (renamed from usbtuner/src/com/android/usbtuner/util/ConvertUtils.java)2
-rw-r--r--src/com/android/tv/tuner/util/GlobalSettingsUtils.java36
-rw-r--r--src/com/android/tv/tuner/util/Ints.java (renamed from usbtuner/src/com/android/usbtuner/util/Ints.java)2
-rw-r--r--src/com/android/tv/tuner/util/StatusTextUtils.java (renamed from usbtuner/src/com/android/usbtuner/util/StatusTextUtils.java)16
-rw-r--r--src/com/android/tv/tuner/util/StringUtils.java (renamed from usbtuner/src/com/android/usbtuner/util/StringUtils.java)2
-rw-r--r--src/com/android/tv/tuner/util/SystemPropertiesProxy.java (renamed from usbtuner/src/com/android/usbtuner/util/SystemPropertiesProxy.java)2
-rw-r--r--src/com/android/tv/tuner/util/TisConfiguration.java (renamed from usbtuner/src/com/android/usbtuner/util/TisConfiguration.java)2
-rw-r--r--src/com/android/tv/tuner/util/TunerInputInfoUtils.java100
-rw-r--r--src/com/android/tv/ui/AppLayerTvView.java13
-rw-r--r--src/com/android/tv/ui/ChannelBannerView.java265
-rw-r--r--src/com/android/tv/ui/GuidedActionsStylistWithDivider.java65
-rw-r--r--src/com/android/tv/ui/OverlayRootView.java51
-rw-r--r--src/com/android/tv/ui/SelectInputView.java9
-rw-r--r--src/com/android/tv/ui/TunableTvView.java559
-rw-r--r--src/com/android/tv/ui/TvOverlayManager.java283
-rw-r--r--src/com/android/tv/ui/TvViewUiManager.java90
-rw-r--r--src/com/android/tv/ui/ViewUtils.java50
-rw-r--r--src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java3
-rw-r--r--src/com/android/tv/ui/sidepanel/DebugOptionFragment.java48
-rw-r--r--src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java101
-rw-r--r--src/com/android/tv/ui/sidepanel/DisplayModeFragment.java6
-rw-r--r--src/com/android/tv/ui/sidepanel/SettingsFragment.java23
-rw-r--r--src/com/android/tv/ui/sidepanel/SideFragment.java17
-rw-r--r--src/com/android/tv/ui/sidepanel/SideFragmentManager.java12
-rw-r--r--src/com/android/tv/util/AccountHelper.java111
-rw-r--r--src/com/android/tv/util/AsyncDbTask.java81
-rw-r--r--src/com/android/tv/util/BitmapUtils.java55
-rw-r--r--src/com/android/tv/util/CompositeComparator.java42
-rw-r--r--src/com/android/tv/util/Filter.java27
-rw-r--r--src/com/android/tv/util/ImageCache.java10
-rw-r--r--src/com/android/tv/util/ImageLoader.java12
-rw-r--r--src/com/android/tv/util/LocationUtils.java120
-rw-r--r--src/com/android/tv/util/OnboardingUtils.java15
-rw-r--r--src/com/android/tv/util/PermissionUtils.java52
-rw-r--r--src/com/android/tv/util/PipInputManager.java2
-rw-r--r--src/com/android/tv/util/RecurringRunner.java6
-rw-r--r--src/com/android/tv/util/SearchManagerHelper.java12
-rw-r--r--src/com/android/tv/util/SetupUtils.java89
-rw-r--r--src/com/android/tv/util/SystemProperties.java6
-rw-r--r--src/com/android/tv/util/TimeShiftUtils.java63
-rw-r--r--src/com/android/tv/util/ToastUtils.java43
-rw-r--r--src/com/android/tv/util/TvInputManagerHelper.java63
-rw-r--r--src/com/android/tv/util/TvProviderUriMatcher.java72
-rw-r--r--src/com/android/tv/util/TvSettings.java6
-rw-r--r--src/com/android/tv/util/TvTrackInfoUtils.java8
-rw-r--r--src/com/android/tv/util/Utils.java350
-rw-r--r--tests/common/res/drawable-xhdpi/blue.pngbin3253 -> 152 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/blue_small.pngbin1158 -> 109 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/crash_test_android_logo.pngbin18721 -> 14828 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/green.pngbin3253 -> 152 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/green_large.pngbin10263 -> 327 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/red.pngbin3252 -> 152 bytes
-rw-r--r--tests/common/res/drawable-xhdpi/red_large.pngbin10262 -> 327 bytes
-rw-r--r--tests/common/src/com/android/tv/MockTvApplication.java84
-rw-r--r--tests/common/src/com/android/tv/input/TunerHelper.java155
-rw-r--r--tests/common/src/com/android/tv/testing/ChannelInfo.java2
-rw-r--r--tests/common/src/com/android/tv/testing/ChannelUtils.java31
-rw-r--r--tests/common/src/com/android/tv/testing/Constants.java2
-rw-r--r--tests/common/src/com/android/tv/testing/ProgramInfo.java6
-rw-r--r--tests/common/src/com/android/tv/testing/ProgramUtils.java18
-rw-r--r--tests/common/src/com/android/tv/testing/TvContentRatingConstants.java7
-rw-r--r--tests/common/src/com/android/tv/testing/Utils.java6
-rw-r--r--tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java41
-rw-r--r--tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/ProgramGuidePerformanceTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java2
-rw-r--r--tests/func/src/com/android/tv/tests/ui/TimeoutTest.java2
-rw-r--r--tests/input/AndroidManifest.xml2
-rw-r--r--tests/input/res/drawable-xhdpi/android_48dp.pngbin5985 -> 5706 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_1000_logo.pngbin1499 -> 1041 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_100_logo.pngbin1548 -> 1128 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_101_logo.pngbin1252 -> 921 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_102_logo.pngbin1579 -> 1224 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_103_logo.pngbin1341 -> 971 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_104_logo.pngbin1280 -> 952 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_105_logo.pngbin1337 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_106_logo.pngbin1098 -> 884 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_107_logo.pngbin1192 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_108_logo.pngbin1041 -> 848 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_109_logo.pngbin1042 -> 842 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_10_logo.pngbin1200 -> 936 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_110_logo.pngbin1584 -> 1155 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_111_logo.pngbin1279 -> 915 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_112_logo.pngbin992 -> 843 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_113_logo.pngbin1472 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_114_logo.pngbin1152 -> 861 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_115_logo.pngbin1286 -> 995 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_116_logo.pngbin1512 -> 1086 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_117_logo.pngbin1270 -> 917 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_118_logo.pngbin1522 -> 1131 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_119_logo.pngbin1184 -> 875 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_11_logo.pngbin1266 -> 932 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_120_logo.pngbin1504 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_121_logo.pngbin838 -> 663 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_122_logo.pngbin1089 -> 845 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_123_logo.pngbin1504 -> 1090 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_124_logo.pngbin1362 -> 1033 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_125_logo.pngbin1137 -> 880 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_126_logo.pngbin1392 -> 1051 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_127_logo.pngbin1314 -> 1044 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_128_logo.pngbin1398 -> 1051 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_129_logo.pngbin1370 -> 983 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_12_logo.pngbin1481 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_130_logo.pngbin1245 -> 891 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_131_logo.pngbin1288 -> 975 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_132_logo.pngbin1280 -> 1076 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_133_logo.pngbin1307 -> 971 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_134_logo.pngbin1590 -> 1191 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_135_logo.pngbin1615 -> 1143 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_136_logo.pngbin1485 -> 1057 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_137_logo.pngbin1401 -> 1007 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_138_logo.pngbin1257 -> 995 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_139_logo.pngbin1497 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_13_logo.pngbin1201 -> 896 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_140_logo.pngbin1315 -> 1010 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_141_logo.pngbin1356 -> 970 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_142_logo.pngbin1497 -> 1103 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_143_logo.pngbin1507 -> 1206 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_144_logo.pngbin1419 -> 1023 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_145_logo.pngbin1474 -> 1037 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_146_logo.pngbin1278 -> 994 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_147_logo.pngbin1108 -> 828 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_148_logo.pngbin1248 -> 1009 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_149_logo.pngbin1110 -> 882 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_14_logo.pngbin1649 -> 1193 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_150_logo.pngbin1624 -> 1314 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_151_logo.pngbin1229 -> 931 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_152_logo.pngbin1394 -> 1030 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_153_logo.pngbin1703 -> 1245 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_154_logo.pngbin1378 -> 1017 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_155_logo.pngbin1818 -> 1317 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_156_logo.pngbin1430 -> 1080 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_157_logo.pngbin1562 -> 1126 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_158_logo.pngbin1542 -> 1223 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_159_logo.pngbin1638 -> 1362 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_15_logo.pngbin1549 -> 1123 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_160_logo.pngbin1396 -> 1059 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_161_logo.pngbin1439 -> 1074 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_162_logo.pngbin1327 -> 1015 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_163_logo.pngbin1472 -> 1093 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_164_logo.pngbin1532 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_165_logo.pngbin1326 -> 1001 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_166_logo.pngbin1721 -> 1276 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_167_logo.pngbin1647 -> 1184 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_168_logo.pngbin1216 -> 963 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_169_logo.pngbin1539 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_16_logo.pngbin1120 -> 877 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_170_logo.pngbin1145 -> 957 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_171_logo.pngbin1421 -> 978 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_172_logo.pngbin1282 -> 939 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_173_logo.pngbin1177 -> 906 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_174_logo.pngbin1221 -> 875 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_175_logo.pngbin1357 -> 974 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_176_logo.pngbin1509 -> 1146 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_177_logo.pngbin1370 -> 951 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_178_logo.pngbin1598 -> 1224 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_179_logo.pngbin1287 -> 948 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_17_logo.pngbin1366 -> 956 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_180_logo.pngbin1322 -> 980 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_181_logo.pngbin1230 -> 903 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_182_logo.pngbin1081 -> 854 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_183_logo.pngbin1164 -> 908 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_184_logo.pngbin967 -> 804 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_185_logo.pngbin1058 -> 840 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_186_logo.pngbin1651 -> 1238 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_187_logo.pngbin1547 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_188_logo.pngbin1102 -> 883 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_189_logo.pngbin1508 -> 1127 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_18_logo.pngbin1073 -> 903 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_190_logo.pngbin1281 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_191_logo.pngbin1263 -> 984 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_192_logo.pngbin1565 -> 1131 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_193_logo.pngbin1421 -> 1050 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_194_logo.pngbin1557 -> 1164 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_195_logo.pngbin1224 -> 918 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_196_logo.pngbin1471 -> 1124 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_197_logo.pngbin914 -> 723 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_198_logo.pngbin1159 -> 929 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_199_logo.pngbin1427 -> 1072 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_19_logo.pngbin1448 -> 1011 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_1_logo.pngbin1446 -> 1009 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_200_logo.pngbin1313 -> 1019 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_201_logo.pngbin1153 -> 923 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_202_logo.pngbin1412 -> 1029 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_203_logo.pngbin1408 -> 1107 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_204_logo.pngbin1609 -> 1148 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_205_logo.pngbin1296 -> 954 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_206_logo.pngbin1379 -> 940 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_207_logo.pngbin1434 -> 1062 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_208_logo.pngbin1307 -> 1108 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_209_logo.pngbin1397 -> 1062 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_20_logo.pngbin1331 -> 973 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_210_logo.pngbin1697 -> 1230 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_211_logo.pngbin1512 -> 1048 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_212_logo.pngbin1336 -> 962 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_213_logo.pngbin1409 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_214_logo.pngbin1133 -> 888 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_215_logo.pngbin1458 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_216_logo.pngbin1367 -> 1038 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_217_logo.pngbin1530 -> 1058 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_218_logo.pngbin1512 -> 1124 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_219_logo.pngbin1551 -> 1277 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_21_logo.pngbin1087 -> 833 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_220_logo.pngbin1555 -> 1100 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_221_logo.pngbin1350 -> 972 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_222_logo.pngbin1292 -> 943 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_223_logo.pngbin1153 -> 850 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_224_logo.pngbin1199 -> 967 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_225_logo.pngbin1132 -> 898 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_226_logo.pngbin1577 -> 1287 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_227_logo.pngbin1380 -> 1013 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_228_logo.pngbin1348 -> 999 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_229_logo.pngbin1682 -> 1209 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_22_logo.pngbin1157 -> 814 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_230_logo.pngbin1469 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_231_logo.pngbin1853 -> 1371 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_232_logo.pngbin1425 -> 1038 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_233_logo.pngbin1750 -> 1234 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_234_logo.pngbin1364 -> 1122 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_235_logo.pngbin1653 -> 1351 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_236_logo.pngbin1444 -> 1089 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_237_logo.pngbin1535 -> 1143 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_238_logo.pngbin1302 -> 1028 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_239_logo.pngbin1464 -> 1116 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_23_logo.pngbin1249 -> 905 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_240_logo.pngbin1537 -> 1101 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_241_logo.pngbin1274 -> 959 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_242_logo.pngbin1649 -> 1238 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_243_logo.pngbin1548 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_244_logo.pngbin1089 -> 849 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_245_logo.pngbin1372 -> 1058 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_246_logo.pngbin1175 -> 991 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_247_logo.pngbin1368 -> 991 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_248_logo.pngbin1401 -> 1034 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_249_logo.pngbin1202 -> 942 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_24_logo.pngbin1438 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_250_logo.pngbin1285 -> 955 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_251_logo.pngbin1349 -> 966 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_252_logo.pngbin1415 -> 1048 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_253_logo.pngbin1495 -> 1084 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_254_logo.pngbin1576 -> 1231 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_255_logo.pngbin1257 -> 917 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_256_logo.pngbin1309 -> 999 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_257_logo.pngbin1297 -> 963 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_258_logo.pngbin1232 -> 968 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_259_logo.pngbin1238 -> 970 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_25_logo.pngbin1407 -> 994 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_260_logo.pngbin1034 -> 858 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_261_logo.pngbin1007 -> 809 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_262_logo.pngbin1609 -> 1179 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_263_logo.pngbin1585 -> 1170 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_264_logo.pngbin1094 -> 914 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_265_logo.pngbin1583 -> 1154 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_266_logo.pngbin1261 -> 947 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_267_logo.pngbin1230 -> 986 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_268_logo.pngbin1468 -> 1103 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_269_logo.pngbin1472 -> 1075 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_26_logo.pngbin1535 -> 1193 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_270_logo.pngbin1613 -> 1143 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_271_logo.pngbin1168 -> 872 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_272_logo.pngbin1445 -> 1057 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_273_logo.pngbin949 -> 748 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_274_logo.pngbin1133 -> 896 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_275_logo.pngbin1519 -> 1095 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_276_logo.pngbin1366 -> 1061 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_277_logo.pngbin1082 -> 847 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_278_logo.pngbin1456 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_279_logo.pngbin1289 -> 1008 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_27_logo.pngbin1236 -> 887 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_280_logo.pngbin1543 -> 1142 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_281_logo.pngbin1355 -> 980 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_282_logo.pngbin1177 -> 833 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_283_logo.pngbin1466 -> 1080 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_284_logo.pngbin1271 -> 1082 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_285_logo.pngbin1404 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_286_logo.pngbin1650 -> 1254 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_287_logo.pngbin1604 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_288_logo.pngbin1458 -> 1013 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_289_logo.pngbin1425 -> 1058 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_28_logo.pngbin1263 -> 928 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_290_logo.pngbin1262 -> 1002 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_291_logo.pngbin1474 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_292_logo.pngbin1262 -> 946 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_293_logo.pngbin1618 -> 1160 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_294_logo.pngbin1533 -> 1133 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_295_logo.pngbin1595 -> 1303 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_296_logo.pngbin1448 -> 1085 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_297_logo.pngbin1463 -> 1060 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_298_logo.pngbin1288 -> 1028 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_299_logo.pngbin1118 -> 842 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_29_logo.pngbin1192 -> 886 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_2_logo.pngbin1262 -> 907 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_300_logo.pngbin1144 -> 934 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_301_logo.pngbin1069 -> 887 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_302_logo.pngbin1641 -> 1338 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_303_logo.pngbin1407 -> 1055 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_304_logo.pngbin1388 -> 1045 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_305_logo.pngbin1736 -> 1282 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_306_logo.pngbin1338 -> 1027 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_307_logo.pngbin1724 -> 1272 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_308_logo.pngbin1480 -> 1115 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_309_logo.pngbin1807 -> 1324 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_30_logo.pngbin1125 -> 894 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_310_logo.pngbin1509 -> 1222 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_311_logo.pngbin1563 -> 1303 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_312_logo.pngbin1439 -> 1057 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_313_logo.pngbin1471 -> 1085 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_314_logo.pngbin1261 -> 990 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_315_logo.pngbin1494 -> 1109 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_316_logo.pngbin1580 -> 1109 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_317_logo.pngbin1293 -> 968 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_318_logo.pngbin1585 -> 1206 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_319_logo.pngbin1482 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_31_logo.pngbin1115 -> 858 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_320_logo.pngbin1249 -> 979 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_321_logo.pngbin1479 -> 1092 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_322_logo.pngbin1145 -> 939 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_323_logo.pngbin1465 -> 1017 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_324_logo.pngbin1381 -> 1008 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_325_logo.pngbin1229 -> 953 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_326_logo.pngbin1290 -> 966 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_327_logo.pngbin1404 -> 1000 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_328_logo.pngbin1652 -> 1205 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_329_logo.pngbin1467 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_32_logo.pngbin972 -> 781 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_330_logo.pngbin1563 -> 1201 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_331_logo.pngbin1256 -> 899 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_332_logo.pngbin1300 -> 946 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_333_logo.pngbin1220 -> 863 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_334_logo.pngbin1093 -> 857 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_335_logo.pngbin1210 -> 913 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_336_logo.pngbin985 -> 805 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_337_logo.pngbin1003 -> 773 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_338_logo.pngbin1598 -> 1167 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_339_logo.pngbin1513 -> 1110 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_33_logo.pngbin910 -> 708 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_340_logo.pngbin1092 -> 937 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_341_logo.pngbin1449 -> 1070 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_342_logo.pngbin1297 -> 984 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_343_logo.pngbin1303 -> 1010 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_344_logo.pngbin1508 -> 1091 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_345_logo.pngbin1345 -> 996 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_346_logo.pngbin1659 -> 1243 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_347_logo.pngbin1245 -> 920 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_348_logo.pngbin1529 -> 1103 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_349_logo.pngbin959 -> 770 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_34_logo.pngbin1537 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_350_logo.pngbin1194 -> 961 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_351_logo.pngbin1547 -> 1147 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_352_logo.pngbin1346 -> 1036 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_353_logo.pngbin1176 -> 920 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_354_logo.pngbin1456 -> 1075 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_355_logo.pngbin1292 -> 1010 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_356_logo.pngbin1624 -> 1176 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_357_logo.pngbin1374 -> 997 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_358_logo.pngbin1252 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_359_logo.pngbin1473 -> 1102 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_35_logo.pngbin1407 -> 1038 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_360_logo.pngbin1279 -> 1119 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_361_logo.pngbin1350 -> 1025 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_362_logo.pngbin1711 -> 1264 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_363_logo.pngbin1518 -> 1099 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_364_logo.pngbin1429 -> 1032 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_365_logo.pngbin1294 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_366_logo.pngbin1239 -> 967 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_367_logo.pngbin1375 -> 1061 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_368_logo.pngbin1339 -> 1023 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_369_logo.pngbin1641 -> 1178 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_36_logo.pngbin1032 -> 847 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_370_logo.pngbin1552 -> 1148 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_371_logo.pngbin1528 -> 1249 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_372_logo.pngbin1565 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_373_logo.pngbin1422 -> 999 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_374_logo.pngbin1283 -> 989 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_375_logo.pngbin1187 -> 900 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_376_logo.pngbin1249 -> 1031 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_377_logo.pngbin1144 -> 886 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_378_logo.pngbin1652 -> 1334 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_379_logo.pngbin1420 -> 1099 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_37_logo.pngbin1489 -> 1060 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_380_logo.pngbin1331 -> 1009 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_381_logo.pngbin1642 -> 1223 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_382_logo.pngbin1470 -> 1072 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_383_logo.pngbin1719 -> 1249 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_384_logo.pngbin1412 -> 1083 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_385_logo.pngbin1845 -> 1344 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_386_logo.pngbin1530 -> 1244 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_387_logo.pngbin1671 -> 1380 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_388_logo.pngbin1334 -> 981 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_389_logo.pngbin1602 -> 1197 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_38_logo.pngbin1257 -> 938 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_390_logo.pngbin1252 -> 986 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_391_logo.pngbin1424 -> 1084 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_392_logo.pngbin1591 -> 1118 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_393_logo.pngbin1319 -> 981 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_394_logo.pngbin1636 -> 1231 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_395_logo.pngbin1661 -> 1243 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_396_logo.pngbin1253 -> 995 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_397_logo.pngbin1532 -> 1118 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_398_logo.pngbin1244 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_399_logo.pngbin1487 -> 1049 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_39_logo.pngbin1296 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_3_logo.pngbin1717 -> 1160 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_400_logo.pngbin1317 -> 974 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_401_logo.pngbin1114 -> 862 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_402_logo.pngbin1302 -> 945 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_403_logo.pngbin1361 -> 1004 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_404_logo.pngbin1484 -> 1106 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_405_logo.pngbin1422 -> 1051 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_406_logo.pngbin1543 -> 1184 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_407_logo.pngbin1234 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_408_logo.pngbin1325 -> 992 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_409_logo.pngbin1339 -> 988 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_40_logo.pngbin1507 -> 1078 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_410_logo.pngbin1150 -> 915 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_411_logo.pngbin1091 -> 842 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_412_logo.pngbin1003 -> 814 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_413_logo.pngbin1032 -> 817 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_414_logo.pngbin1536 -> 1120 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_415_logo.pngbin1522 -> 1116 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_416_logo.pngbin1126 -> 923 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_417_logo.pngbin1433 -> 1044 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_418_logo.pngbin1234 -> 946 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_419_logo.pngbin1334 -> 1045 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_41_logo.pngbin1195 -> 857 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_420_logo.pngbin1399 -> 1056 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_421_logo.pngbin1380 -> 1003 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_422_logo.pngbin1595 -> 1154 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_423_logo.pngbin1235 -> 921 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_424_logo.pngbin1457 -> 1069 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_425_logo.pngbin948 -> 744 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_426_logo.pngbin1160 -> 923 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_427_logo.pngbin1511 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_428_logo.pngbin1400 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_429_logo.pngbin1179 -> 940 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_42_logo.pngbin1563 -> 1135 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_430_logo.pngbin1414 -> 1072 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_431_logo.pngbin1344 -> 1059 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_432_logo.pngbin1620 -> 1149 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_433_logo.pngbin1330 -> 933 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_434_logo.pngbin1308 -> 867 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_435_logo.pngbin1403 -> 1055 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_436_logo.pngbin1228 -> 1039 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_437_logo.pngbin1362 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_438_logo.pngbin1634 -> 1241 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_439_logo.pngbin1563 -> 1134 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_43_logo.pngbin1092 -> 810 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_440_logo.pngbin1372 -> 987 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_441_logo.pngbin1227 -> 905 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_442_logo.pngbin1165 -> 906 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_443_logo.pngbin1424 -> 1071 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_444_logo.pngbin1167 -> 871 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_445_logo.pngbin1555 -> 1073 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_446_logo.pngbin1484 -> 1083 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_447_logo.pngbin1463 -> 1196 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_448_logo.pngbin1500 -> 1077 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_449_logo.pngbin1428 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_44_logo.pngbin1332 -> 966 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_450_logo.pngbin1351 -> 1066 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_451_logo.pngbin1119 -> 845 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_452_logo.pngbin1278 -> 1028 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_453_logo.pngbin1176 -> 946 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_454_logo.pngbin1511 -> 1228 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_455_logo.pngbin1374 -> 1035 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_456_logo.pngbin1398 -> 1061 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_457_logo.pngbin1643 -> 1162 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_458_logo.pngbin1457 -> 1067 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_459_logo.pngbin1885 -> 1384 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_45_logo.pngbin851 -> 674 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_460_logo.pngbin1464 -> 1087 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_461_logo.pngbin1717 -> 1234 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_462_logo.pngbin1526 -> 1212 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_463_logo.pngbin1654 -> 1360 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_464_logo.pngbin1384 -> 1024 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_465_logo.pngbin1559 -> 1159 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_466_logo.pngbin1223 -> 973 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_467_logo.pngbin1456 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_468_logo.pngbin1535 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_469_logo.pngbin1310 -> 1011 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_46_logo.pngbin1031 -> 815 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_470_logo.pngbin1694 -> 1271 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_471_logo.pngbin1559 -> 1096 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_472_logo.pngbin1184 -> 925 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_473_logo.pngbin1542 -> 1104 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_474_logo.pngbin1073 -> 892 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_475_logo.pngbin1542 -> 1065 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_476_logo.pngbin1375 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_477_logo.pngbin1097 -> 833 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_478_logo.pngbin1298 -> 936 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_479_logo.pngbin1387 -> 991 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_47_logo.pngbin1438 -> 1054 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_480_logo.pngbin1584 -> 1193 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_481_logo.pngbin1369 -> 1001 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_482_logo.pngbin1557 -> 1242 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_483_logo.pngbin1326 -> 981 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_484_logo.pngbin1203 -> 870 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_485_logo.pngbin1352 -> 992 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_486_logo.pngbin1115 -> 899 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_487_logo.pngbin1198 -> 930 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_488_logo.pngbin983 -> 790 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_489_logo.pngbin1042 -> 846 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_48_logo.pngbin1316 -> 1008 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_490_logo.pngbin1643 -> 1228 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_491_logo.pngbin1534 -> 1125 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_492_logo.pngbin1134 -> 940 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_493_logo.pngbin1604 -> 1151 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_494_logo.pngbin1139 -> 866 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_495_logo.pngbin1372 -> 1072 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_496_logo.pngbin1572 -> 1155 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_497_logo.pngbin1270 -> 945 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_498_logo.pngbin1656 -> 1241 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_499_logo.pngbin1201 -> 873 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_49_logo.pngbin1104 -> 872 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_4_logo.pngbin1190 -> 852 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_500_logo.pngbin1367 -> 1022 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_501_logo.pngbin920 -> 745 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_502_logo.pngbin1194 -> 944 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_503_logo.pngbin1554 -> 1198 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_504_logo.pngbin1405 -> 1087 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_505_logo.pngbin1180 -> 928 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_506_logo.pngbin1446 -> 1104 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_507_logo.pngbin1357 -> 1088 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_508_logo.pngbin1503 -> 1109 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_509_logo.pngbin1299 -> 973 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_50_logo.pngbin1343 -> 992 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_510_logo.pngbin1375 -> 935 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_511_logo.pngbin1326 -> 981 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_512_logo.pngbin1285 -> 1078 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_513_logo.pngbin1438 -> 1065 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_514_logo.pngbin1522 -> 1132 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_515_logo.pngbin1505 -> 1066 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_516_logo.pngbin1481 -> 1061 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_517_logo.pngbin1389 -> 1005 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_518_logo.pngbin1253 -> 975 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_519_logo.pngbin1504 -> 1143 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_51_logo.pngbin1300 -> 1003 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_520_logo.pngbin1405 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_521_logo.pngbin1586 -> 1123 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_522_logo.pngbin1509 -> 1086 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_523_logo.pngbin1600 -> 1308 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_524_logo.pngbin1559 -> 1129 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_525_logo.pngbin1410 -> 1021 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_526_logo.pngbin1295 -> 1020 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_527_logo.pngbin1162 -> 879 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_528_logo.pngbin1271 -> 1043 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_529_logo.pngbin1182 -> 961 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_52_logo.pngbin1526 -> 1083 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_530_logo.pngbin1594 -> 1332 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_531_logo.pngbin1375 -> 1071 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_532_logo.pngbin1433 -> 1071 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_533_logo.pngbin1683 -> 1211 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_534_logo.pngbin1422 -> 1058 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_535_logo.pngbin1922 -> 1380 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_536_logo.pngbin1490 -> 1124 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_537_logo.pngbin1788 -> 1298 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_538_logo.pngbin1592 -> 1273 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_539_logo.pngbin1679 -> 1391 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_53_logo.pngbin1281 -> 938 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_540_logo.pngbin1422 -> 1086 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_541_logo.pngbin1523 -> 1127 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_542_logo.pngbin1303 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_543_logo.pngbin1514 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_544_logo.pngbin1530 -> 1059 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_545_logo.pngbin1273 -> 949 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_546_logo.pngbin1795 -> 1343 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_547_logo.pngbin1612 -> 1138 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_548_logo.pngbin1201 -> 975 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_549_logo.pngbin1545 -> 1144 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_54_logo.pngbin1168 -> 808 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_550_logo.pngbin1094 -> 923 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_551_logo.pngbin1342 -> 953 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_552_logo.pngbin1426 -> 1005 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_553_logo.pngbin1193 -> 918 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_554_logo.pngbin1225 -> 892 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_555_logo.pngbin1290 -> 903 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_556_logo.pngbin1570 -> 1172 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_557_logo.pngbin1456 -> 1005 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_558_logo.pngbin1609 -> 1241 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_559_logo.pngbin1323 -> 963 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_55_logo.pngbin1336 -> 951 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_560_logo.pngbin1320 -> 1011 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_561_logo.pngbin1313 -> 968 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_562_logo.pngbin1221 -> 962 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_563_logo.pngbin1259 -> 982 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_564_logo.pngbin1041 -> 854 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_565_logo.pngbin1042 -> 827 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_566_logo.pngbin1600 -> 1186 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_567_logo.pngbin1542 -> 1145 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_568_logo.pngbin1182 -> 984 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_569_logo.pngbin1527 -> 1134 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_56_logo.pngbin1123 -> 967 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_570_logo.pngbin1296 -> 992 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_571_logo.pngbin1292 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_572_logo.pngbin1576 -> 1138 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_573_logo.pngbin1347 -> 995 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_574_logo.pngbin1596 -> 1169 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_575_logo.pngbin1163 -> 853 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_576_logo.pngbin1548 -> 1148 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_577_logo.pngbin870 -> 684 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_578_logo.pngbin1184 -> 932 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_579_logo.pngbin1558 -> 1159 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_57_logo.pngbin1336 -> 981 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_580_logo.pngbin1435 -> 1107 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_581_logo.pngbin1164 -> 939 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_582_logo.pngbin1479 -> 1093 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_583_logo.pngbin1364 -> 1066 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_584_logo.pngbin1529 -> 1134 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_585_logo.pngbin1341 -> 960 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_586_logo.pngbin1295 -> 925 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_587_logo.pngbin1452 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_588_logo.pngbin1258 -> 1053 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_589_logo.pngbin1418 -> 1081 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_58_logo.pngbin1641 -> 1193 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_590_logo.pngbin1646 -> 1258 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_591_logo.pngbin1623 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_592_logo.pngbin1507 -> 1072 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_593_logo.pngbin1446 -> 1071 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_594_logo.pngbin1259 -> 988 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_595_logo.pngbin1476 -> 1106 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_596_logo.pngbin1402 -> 1089 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_597_logo.pngbin1585 -> 1132 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_598_logo.pngbin1563 -> 1164 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_599_logo.pngbin1533 -> 1257 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_59_logo.pngbin1583 -> 1097 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_5_logo.pngbin1620 -> 1137 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_600_logo.pngbin1544 -> 1107 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_601_logo.pngbin1449 -> 1059 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_602_logo.pngbin1401 -> 1078 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_603_logo.pngbin1198 -> 925 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_604_logo.pngbin1160 -> 961 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_605_logo.pngbin1229 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_606_logo.pngbin1458 -> 1217 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_607_logo.pngbin1456 -> 1094 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_608_logo.pngbin1359 -> 1050 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_609_logo.pngbin1730 -> 1273 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_60_logo.pngbin1318 -> 958 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_610_logo.pngbin1348 -> 1009 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_611_logo.pngbin1851 -> 1320 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_612_logo.pngbin1434 -> 1076 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_613_logo.pngbin1787 -> 1300 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_614_logo.pngbin1468 -> 1185 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_615_logo.pngbin1632 -> 1360 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_616_logo.pngbin1311 -> 985 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_617_logo.pngbin1476 -> 1113 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_618_logo.pngbin1300 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_619_logo.pngbin1357 -> 1031 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_61_logo.pngbin1223 -> 898 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_620_logo.pngbin1606 -> 1127 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_621_logo.pngbin1299 -> 975 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_622_logo.pngbin1735 -> 1268 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_623_logo.pngbin1710 -> 1233 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_624_logo.pngbin1223 -> 954 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_625_logo.pngbin1373 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_626_logo.pngbin1076 -> 931 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_627_logo.pngbin1500 -> 1068 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_628_logo.pngbin1305 -> 994 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_629_logo.pngbin1155 -> 911 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_62_logo.pngbin1179 -> 926 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_630_logo.pngbin1299 -> 974 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_631_logo.pngbin1391 -> 1006 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_632_logo.pngbin1630 -> 1207 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_633_logo.pngbin1414 -> 1019 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_634_logo.pngbin1540 -> 1185 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_635_logo.pngbin1373 -> 1005 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_636_logo.pngbin1290 -> 950 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_637_logo.pngbin1267 -> 942 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_638_logo.pngbin1226 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_639_logo.pngbin1256 -> 982 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_63_logo.pngbin1394 -> 1070 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_640_logo.pngbin1045 -> 861 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_641_logo.pngbin1014 -> 811 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_642_logo.pngbin1656 -> 1230 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_643_logo.pngbin1582 -> 1172 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_644_logo.pngbin1062 -> 883 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_645_logo.pngbin1430 -> 1078 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_646_logo.pngbin1179 -> 878 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_647_logo.pngbin1289 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_648_logo.pngbin1564 -> 1161 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_649_logo.pngbin1453 -> 1068 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_64_logo.pngbin1281 -> 976 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_650_logo.pngbin1687 -> 1263 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_651_logo.pngbin1202 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_652_logo.pngbin1498 -> 1138 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_653_logo.pngbin985 -> 777 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_654_logo.pngbin1106 -> 894 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_655_logo.pngbin1401 -> 1052 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_656_logo.pngbin1360 -> 1049 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_657_logo.pngbin1167 -> 937 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_658_logo.pngbin1489 -> 1120 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_659_logo.pngbin1437 -> 1134 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_65_logo.pngbin1504 -> 1048 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_660_logo.pngbin1490 -> 1107 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_661_logo.pngbin1280 -> 929 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_662_logo.pngbin1299 -> 887 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_663_logo.pngbin1410 -> 1039 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_664_logo.pngbin1213 -> 1033 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_665_logo.pngbin1401 -> 1036 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_666_logo.pngbin1575 -> 1134 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_667_logo.pngbin1557 -> 1087 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_668_logo.pngbin1449 -> 1032 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_669_logo.pngbin1400 -> 1029 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_66_logo.pngbin1360 -> 1023 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_670_logo.pngbin1253 -> 974 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_671_logo.pngbin1441 -> 1103 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_672_logo.pngbin1350 -> 1016 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_673_logo.pngbin1635 -> 1157 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_674_logo.pngbin1525 -> 1118 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_675_logo.pngbin1587 -> 1288 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_676_logo.pngbin1445 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_677_logo.pngbin1422 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_678_logo.pngbin1394 -> 1081 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_679_logo.pngbin1157 -> 898 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_67_logo.pngbin1493 -> 1208 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_680_logo.pngbin1283 -> 1061 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_681_logo.pngbin1099 -> 901 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_682_logo.pngbin1667 -> 1340 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_683_logo.pngbin1482 -> 1123 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_684_logo.pngbin1382 -> 1045 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_685_logo.pngbin1631 -> 1220 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_686_logo.pngbin1388 -> 1042 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_687_logo.pngbin1923 -> 1417 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_688_logo.pngbin1408 -> 1052 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_689_logo.pngbin1817 -> 1331 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_68_logo.pngbin1526 -> 1106 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_690_logo.pngbin1576 -> 1253 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_691_logo.pngbin1639 -> 1359 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_692_logo.pngbin1425 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_693_logo.pngbin1544 -> 1169 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_694_logo.pngbin1304 -> 1025 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_695_logo.pngbin1532 -> 1136 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_696_logo.pngbin1559 -> 1078 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_697_logo.pngbin1337 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_698_logo.pngbin1818 -> 1366 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_699_logo.pngbin1647 -> 1191 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_69_logo.pngbin1426 -> 1035 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_6_logo.pngbin1215 -> 1002 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_700_logo.pngbin1166 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_701_logo.pngbin1486 -> 1088 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_702_logo.pngbin1179 -> 967 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_703_logo.pngbin1516 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_704_logo.pngbin1358 -> 986 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_705_logo.pngbin1187 -> 926 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_706_logo.pngbin1294 -> 952 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_707_logo.pngbin1312 -> 928 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_708_logo.pngbin1457 -> 1089 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_709_logo.pngbin1475 -> 1062 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_70_logo.pngbin1336 -> 996 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_710_logo.pngbin1513 -> 1152 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_711_logo.pngbin1192 -> 855 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_712_logo.pngbin1281 -> 944 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_713_logo.pngbin1296 -> 952 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_714_logo.pngbin1089 -> 861 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_715_logo.pngbin1193 -> 918 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_716_logo.pngbin1009 -> 827 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_717_logo.pngbin938 -> 736 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_718_logo.pngbin1618 -> 1183 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_719_logo.pngbin1519 -> 1115 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_71_logo.pngbin1036 -> 770 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_720_logo.pngbin1145 -> 927 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_721_logo.pngbin1483 -> 1080 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_722_logo.pngbin1246 -> 909 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_723_logo.pngbin1304 -> 1002 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_724_logo.pngbin1541 -> 1110 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_725_logo.pngbin1421 -> 1037 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_726_logo.pngbin1601 -> 1195 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_727_logo.pngbin1129 -> 814 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_728_logo.pngbin1547 -> 1129 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_729_logo.pngbin935 -> 743 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_72_logo.pngbin1151 -> 919 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_730_logo.pngbin1151 -> 921 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_731_logo.pngbin1511 -> 1122 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_732_logo.pngbin1370 -> 1054 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_733_logo.pngbin1110 -> 865 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_734_logo.pngbin1440 -> 1052 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_735_logo.pngbin1397 -> 1086 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_736_logo.pngbin1529 -> 1135 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_737_logo.pngbin1290 -> 911 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_738_logo.pngbin1408 -> 936 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_739_logo.pngbin1462 -> 1081 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_73_logo.pngbin1091 -> 861 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_740_logo.pngbin1204 -> 1011 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_741_logo.pngbin1310 -> 982 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_742_logo.pngbin1616 -> 1149 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_743_logo.pngbin1608 -> 1119 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_744_logo.pngbin1328 -> 944 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_745_logo.pngbin1314 -> 967 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_746_logo.pngbin1214 -> 958 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_747_logo.pngbin1379 -> 1035 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_748_logo.pngbin1350 -> 1023 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_749_logo.pngbin1589 -> 1105 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_74_logo.pngbin1384 -> 1126 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_750_logo.pngbin1575 -> 1147 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_751_logo.pngbin1544 -> 1249 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_752_logo.pngbin1537 -> 1117 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_753_logo.pngbin1493 -> 1070 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_754_logo.pngbin1370 -> 1040 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_755_logo.pngbin1144 -> 837 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_756_logo.pngbin1271 -> 1032 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_757_logo.pngbin1143 -> 879 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_758_logo.pngbin1475 -> 1220 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_759_logo.pngbin1463 -> 1088 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_75_logo.pngbin1337 -> 993 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_760_logo.pngbin1370 -> 1047 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_761_logo.pngbin1646 -> 1201 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_762_logo.pngbin1409 -> 1033 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_763_logo.pngbin1789 -> 1294 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_764_logo.pngbin1418 -> 1059 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_765_logo.pngbin1778 -> 1271 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_766_logo.pngbin1441 -> 1153 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_767_logo.pngbin1612 -> 1309 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_768_logo.pngbin1456 -> 1081 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_769_logo.pngbin1563 -> 1162 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_76_logo.pngbin1324 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_770_logo.pngbin1157 -> 897 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_771_logo.pngbin1338 -> 990 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_772_logo.pngbin1515 -> 1034 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_773_logo.pngbin1256 -> 933 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_774_logo.pngbin1677 -> 1208 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_775_logo.pngbin1483 -> 1064 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_776_logo.pngbin1181 -> 912 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_777_logo.pngbin1305 -> 943 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_778_logo.pngbin1127 -> 924 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_779_logo.pngbin1487 -> 1025 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_77_logo.pngbin1543 -> 1091 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_780_logo.pngbin1429 -> 1033 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_781_logo.pngbin1156 -> 904 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_782_logo.pngbin1235 -> 899 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_783_logo.pngbin1401 -> 1013 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_784_logo.pngbin1543 -> 1153 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_785_logo.pngbin1447 -> 1052 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_786_logo.pngbin1586 -> 1264 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_787_logo.pngbin1281 -> 910 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_788_logo.pngbin1288 -> 931 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_789_logo.pngbin1340 -> 983 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_78_logo.pngbin1328 -> 969 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_790_logo.pngbin1188 -> 943 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_791_logo.pngbin1112 -> 864 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_792_logo.pngbin1043 -> 838 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_793_logo.pngbin1046 -> 843 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_794_logo.pngbin1605 -> 1175 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_795_logo.pngbin1482 -> 1087 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_796_logo.pngbin1112 -> 934 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_797_logo.pngbin1514 -> 1075 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_798_logo.pngbin1301 -> 986 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_799_logo.pngbin1316 -> 1010 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_79_logo.pngbin1806 -> 1300 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_7_logo.pngbin1484 -> 1196 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_800_logo.pngbin1573 -> 1135 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_801_logo.pngbin1418 -> 1043 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_802_logo.pngbin1681 -> 1254 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_803_logo.pngbin1228 -> 931 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_804_logo.pngbin1523 -> 1145 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_805_logo.pngbin983 -> 778 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_806_logo.pngbin1186 -> 964 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_807_logo.pngbin1551 -> 1157 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_808_logo.pngbin1362 -> 1047 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_809_logo.pngbin1231 -> 982 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_80_logo.pngbin1406 -> 1035 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_810_logo.pngbin1448 -> 1079 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_811_logo.pngbin1224 -> 960 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_812_logo.pngbin1573 -> 1154 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_813_logo.pngbin1365 -> 1006 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_814_logo.pngbin1168 -> 849 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_815_logo.pngbin1394 -> 1054 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_816_logo.pngbin1273 -> 1093 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_817_logo.pngbin1392 -> 1031 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_818_logo.pngbin1586 -> 1164 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_819_logo.pngbin1535 -> 1132 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_81_logo.pngbin1680 -> 1191 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_820_logo.pngbin1514 -> 1066 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_821_logo.pngbin1389 -> 1012 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_822_logo.pngbin1232 -> 947 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_823_logo.pngbin1510 -> 1151 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_824_logo.pngbin1300 -> 984 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_825_logo.pngbin1452 -> 1086 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_826_logo.pngbin1560 -> 1161 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_827_logo.pngbin1570 -> 1283 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_828_logo.pngbin1544 -> 1100 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_829_logo.pngbin1521 -> 1100 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_82_logo.pngbin1423 -> 1151 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_830_logo.pngbin1300 -> 1034 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_831_logo.pngbin1152 -> 885 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_832_logo.pngbin1304 -> 1056 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_833_logo.pngbin1156 -> 924 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_834_logo.pngbin1640 -> 1339 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_835_logo.pngbin1425 -> 1111 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_836_logo.pngbin1391 -> 1075 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_837_logo.pngbin1725 -> 1251 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_838_logo.pngbin1426 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_839_logo.pngbin1980 -> 1448 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_83_logo.pngbin1588 -> 1315 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_840_logo.pngbin1467 -> 1102 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_841_logo.pngbin1744 -> 1254 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_842_logo.pngbin1484 -> 1209 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_843_logo.pngbin1646 -> 1346 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_844_logo.pngbin1361 -> 985 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_845_logo.pngbin1469 -> 1095 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_846_logo.pngbin1346 -> 1056 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_847_logo.pngbin1349 -> 1008 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_848_logo.pngbin1508 -> 1057 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_849_logo.pngbin1313 -> 1018 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_84_logo.pngbin1324 -> 991 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_850_logo.pngbin1811 -> 1347 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_851_logo.pngbin1647 -> 1196 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_852_logo.pngbin1197 -> 941 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_853_logo.pngbin1575 -> 1156 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_854_logo.pngbin1158 -> 986 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_855_logo.pngbin1529 -> 1071 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_856_logo.pngbin1457 -> 1074 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_857_logo.pngbin1210 -> 942 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_858_logo.pngbin1280 -> 920 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_859_logo.pngbin1435 -> 1046 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_85_logo.pngbin1476 -> 1104 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_860_logo.pngbin1581 -> 1210 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_861_logo.pngbin1384 -> 1032 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_862_logo.pngbin1541 -> 1263 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_863_logo.pngbin1389 -> 1015 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_864_logo.pngbin1319 -> 989 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_865_logo.pngbin1359 -> 1014 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_866_logo.pngbin1176 -> 923 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_867_logo.pngbin1226 -> 961 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_868_logo.pngbin1016 -> 824 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_869_logo.pngbin1060 -> 875 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_86_logo.pngbin1214 -> 975 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_870_logo.pngbin1503 -> 1125 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_871_logo.pngbin1536 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_872_logo.pngbin1142 -> 937 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_873_logo.pngbin1530 -> 1131 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_874_logo.pngbin1242 -> 944 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_875_logo.pngbin1314 -> 1026 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_876_logo.pngbin1519 -> 1149 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_877_logo.pngbin1344 -> 977 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_878_logo.pngbin1463 -> 1075 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_879_logo.pngbin1242 -> 941 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_87_logo.pngbin1316 -> 959 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_880_logo.pngbin1450 -> 1081 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_881_logo.pngbin858 -> 679 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_882_logo.pngbin1120 -> 883 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_883_logo.pngbin1541 -> 1127 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_884_logo.pngbin1360 -> 1028 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_885_logo.pngbin1153 -> 904 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_886_logo.pngbin1427 -> 1046 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_887_logo.pngbin1364 -> 1040 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_888_logo.pngbin1473 -> 1030 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_889_logo.pngbin1333 -> 961 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_88_logo.pngbin1418 -> 982 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_890_logo.pngbin1395 -> 954 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_891_logo.pngbin1433 -> 1070 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_892_logo.pngbin1242 -> 1055 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_893_logo.pngbin1467 -> 1092 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_894_logo.pngbin1627 -> 1237 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_895_logo.pngbin1464 -> 1100 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_896_logo.pngbin1526 -> 1095 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_897_logo.pngbin1423 -> 1040 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_898_logo.pngbin1239 -> 959 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_899_logo.pngbin1475 -> 1099 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_89_logo.pngbin1239 -> 939 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_8_logo.pngbin1274 -> 914 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_900_logo.pngbin1346 -> 1021 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_901_logo.pngbin1515 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_902_logo.pngbin1577 -> 1157 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_903_logo.pngbin1611 -> 1307 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_904_logo.pngbin1582 -> 1151 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_905_logo.pngbin1521 -> 1106 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_906_logo.pngbin1418 -> 1102 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_907_logo.pngbin1193 -> 900 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_908_logo.pngbin1274 -> 1054 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_909_logo.pngbin1163 -> 928 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_90_logo.pngbin1675 -> 1252 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_910_logo.pngbin1459 -> 1225 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_911_logo.pngbin1367 -> 1016 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_912_logo.pngbin1345 -> 1002 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_913_logo.pngbin1683 -> 1245 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_914_logo.pngbin1406 -> 1030 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_915_logo.pngbin1885 -> 1384 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_916_logo.pngbin1423 -> 1095 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_917_logo.pngbin1757 -> 1259 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_918_logo.pngbin1546 -> 1229 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_919_logo.pngbin1568 -> 1311 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_91_logo.pngbin1541 -> 1121 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_920_logo.pngbin1348 -> 1011 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_921_logo.pngbin1512 -> 1133 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_922_logo.pngbin1171 -> 913 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_923_logo.pngbin1508 -> 1119 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_924_logo.pngbin1571 -> 1104 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_925_logo.pngbin1341 -> 1027 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_926_logo.pngbin1799 -> 1346 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_927_logo.pngbin1536 -> 1126 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_928_logo.pngbin1268 -> 989 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_929_logo.pngbin1523 -> 1088 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_92_logo.pngbin1153 -> 907 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_930_logo.pngbin1200 -> 1017 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_931_logo.pngbin1408 -> 1008 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_932_logo.pngbin1402 -> 1047 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_933_logo.pngbin1186 -> 908 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_934_logo.pngbin1231 -> 912 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_935_logo.pngbin1422 -> 1041 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_936_logo.pngbin1574 -> 1219 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_937_logo.pngbin1488 -> 1065 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_938_logo.pngbin1464 -> 1194 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_939_logo.pngbin1234 -> 908 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_93_logo.pngbin1486 -> 1077 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_940_logo.pngbin1344 -> 1009 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_941_logo.pngbin1221 -> 913 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_942_logo.pngbin1176 -> 947 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_943_logo.pngbin1260 -> 971 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_944_logo.pngbin989 -> 795 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_945_logo.pngbin1069 -> 850 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_946_logo.pngbin1668 -> 1255 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_947_logo.pngbin1548 -> 1135 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_948_logo.pngbin1098 -> 942 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_949_logo.pngbin1528 -> 1091 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_94_logo.pngbin1113 -> 913 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_950_logo.pngbin1297 -> 997 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_951_logo.pngbin1357 -> 1060 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_952_logo.pngbin1561 -> 1153 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_953_logo.pngbin1431 -> 1057 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_954_logo.pngbin1665 -> 1233 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_955_logo.pngbin1247 -> 901 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_956_logo.pngbin1571 -> 1177 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_957_logo.pngbin961 -> 751 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_958_logo.pngbin1209 -> 965 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_959_logo.pngbin1504 -> 1125 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_95_logo.pngbin1489 -> 1048 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_960_logo.pngbin1401 -> 1102 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_961_logo.pngbin1178 -> 943 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_962_logo.pngbin1486 -> 1107 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_963_logo.pngbin1436 -> 1138 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_964_logo.pngbin1623 -> 1173 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_965_logo.pngbin1385 -> 1024 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_966_logo.pngbin1305 -> 904 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_967_logo.pngbin1368 -> 1020 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_968_logo.pngbin1253 -> 1074 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_969_logo.pngbin1357 -> 1022 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_96_logo.pngbin1337 -> 989 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_970_logo.pngbin1506 -> 1164 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_971_logo.pngbin1563 -> 1103 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_972_logo.pngbin1469 -> 1054 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_973_logo.pngbin1434 -> 1044 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_974_logo.pngbin1233 -> 966 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_975_logo.pngbin1474 -> 1098 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_976_logo.pngbin1387 -> 1068 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_977_logo.pngbin1486 -> 1062 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_978_logo.pngbin1579 -> 1157 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_979_logo.pngbin1508 -> 1234 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_97_logo.pngbin1125 -> 861 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_980_logo.pngbin1635 -> 1188 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_981_logo.pngbin1474 -> 1069 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_982_logo.pngbin1397 -> 1087 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_983_logo.pngbin1205 -> 920 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_984_logo.pngbin1278 -> 1041 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_985_logo.pngbin1227 -> 984 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_986_logo.pngbin1615 -> 1346 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_987_logo.pngbin1450 -> 1091 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_988_logo.pngbin1347 -> 1001 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_989_logo.pngbin1643 -> 1201 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_98_logo.pngbin1216 -> 902 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_990_logo.pngbin1419 -> 1027 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_991_logo.pngbin1850 -> 1334 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_992_logo.pngbin1438 -> 1055 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_993_logo.pngbin1769 -> 1252 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_994_logo.pngbin1487 -> 1168 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_995_logo.pngbin1605 -> 1305 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_996_logo.pngbin1413 -> 1047 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_997_logo.pngbin1513 -> 1104 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_998_logo.pngbin1289 -> 996 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_999_logo.pngbin1386 -> 999 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_99_logo.pngbin1287 -> 900 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/ch_9_logo.pngbin1414 -> 1031 bytes
-rw-r--r--tests/input/res/drawable-xhdpi/icon.pngbin3641 -> 272 bytes
-rw-r--r--tests/input/res/values/integers.xml20
-rw-r--r--tests/input/res/xml/testtvinputservice.xml4
-rw-r--r--tests/input/src/com/android/tv/testinput/TestTvInputService.java230
-rw-r--r--tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java86
-rw-r--r--tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java84
-rw-r--r--tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java41
-rw-r--r--tests/jank/src/com/android/tv/tests/jank/Utils.java35
-rw-r--r--tests/unit/Android.mk2
-rw-r--r--tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java2
-rw-r--r--tests/unit/src/com/android/tv/FeaturesTest.java2
-rw-r--r--tests/unit/src/com/android/tv/MainActivityTest.java2
-rw-r--r--tests/unit/src/com/android/tv/TimeShiftManagerTest.java2
-rw-r--r--tests/unit/src/com/android/tv/common/TvContentRatingCacheTest.java4
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java8
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelNumberTest.java2
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelTest.java5
-rw-r--r--tests/unit/src/com/android/tv/data/GenreItemTest.java3
-rw-r--r--tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java6
-rw-r--r--tests/unit/src/com/android/tv/data/ProgramTest.java76
-rw-r--r--tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java6
-rw-r--r--tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java12
-rw-r--r--tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java5
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java18
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java (renamed from src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java)160
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrDbSyncTest.java121
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrRecordingServiceTest.java18
-rw-r--r--tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java634
-rw-r--r--tests/unit/src/com/android/tv/dvr/EpisodicProgramLoadTaskTest.java76
-rw-r--r--tests/unit/src/com/android/tv/dvr/InputTaskSchedulerTest.java220
-rw-r--r--tests/unit/src/com/android/tv/dvr/RecordingTaskTest.java87
-rw-r--r--tests/unit/src/com/android/tv/dvr/ScheduledProgramReaperTest.java19
-rw-r--r--tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java41
-rw-r--r--tests/unit/src/com/android/tv/dvr/SchedulerTest.java27
-rw-r--r--tests/unit/src/com/android/tv/dvr/SeriesRecordingSchedulerTest.java111
-rw-r--r--tests/unit/src/com/android/tv/dvr/SeriesRecordingTest.java125
-rw-r--r--tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java51
-rw-r--r--tests/unit/src/com/android/tv/menu/MenuTest.java2
-rw-r--r--tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java14
-rw-r--r--tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecommenderTest.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java12
-rw-r--r--tests/unit/src/com/android/tv/tests/TvActivityTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/ImageCacheTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/TestUtils.java59
-rw-r--r--tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java5
-rw-r--r--tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java32
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java10
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java2
-rw-r--r--tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java2
-rw-r--r--usbtuner-res/animator/setup_before_entry.xml (renamed from usbtuner/res/animator/setup_before_entry.xml)0
-rw-r--r--usbtuner-res/animator/setup_before_exit.xml (renamed from usbtuner/res/animator/setup_before_exit.xml)0
-rw-r--r--usbtuner-res/animator/setup_entry.xml (renamed from usbtuner/res/animator/setup_entry.xml)0
-rw-r--r--usbtuner-res/animator/setup_exit.xml (renamed from usbtuner/res/animator/setup_exit.xml)0
-rw-r--r--usbtuner-res/drawable-xhdpi/ic_setup_antenna.pngbin0 -> 1264 bytes
-rw-r--r--usbtuner-res/drawable-xhdpi/recommendation_antenna.pngbin0 -> 1662 bytes
-rw-r--r--usbtuner-res/drawable-xhdpi/usb_antenna.pngbin0 -> 1639 bytes
-rw-r--r--usbtuner-res/drawable/ut_scan_progress.xml (renamed from usbtuner/res/drawable/ut_scan_progress.xml)0
-rw-r--r--usbtuner-res/drawable/ut_selector_background.xml (renamed from usbtuner/res/drawable/ut_selector_background.xml)0
-rw-r--r--usbtuner-res/layout/ut_activity_playback.xml (renamed from usbtuner/res/layout/ut_activity_playback.xml)0
-rw-r--r--usbtuner-res/layout/ut_channel_list.xml (renamed from usbtuner/res/layout/ut_channel_list.xml)0
-rw-r--r--usbtuner-res/layout/ut_channel_scan.xml (renamed from usbtuner/res/layout/ut_channel_scan.xml)2
-rw-r--r--usbtuner-res/layout/ut_guidance.xml (renamed from usbtuner/res/layout/ut_guidance.xml)0
-rw-r--r--usbtuner-res/layout/ut_guidedactions.xml (renamed from usbtuner/res/layout/ut_guidedactions.xml)0
-rw-r--r--usbtuner-res/layout/ut_overlay_view.xml (renamed from usbtuner/res/layout/ut_overlay_view.xml)2
-rw-r--r--usbtuner-res/raw/ut_kr_all (renamed from usbtuner/res/raw/ut_kr_all)0
-rw-r--r--usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb (renamed from usbtuner/res/raw/ut_kr_atsc_center_frequencies_8vsb)0
-rw-r--r--usbtuner-res/raw/ut_kr_cable_standard_center_frequencies_qam256 (renamed from usbtuner/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 usbtuner/res/raw/ut_kr_dev_cj_cable_center_frequencies_qam256)0
-rw-r--r--usbtuner-res/raw/ut_us_all (renamed from usbtuner/res/raw/ut_us_all)136
-rw-r--r--usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb71
-rw-r--r--usbtuner-res/raw/ut_us_cable_standard_center_frequencies_qam256 (renamed from usbtuner/res/raw/ut_us_cable_standard_center_frequencies_qam256)0
-rw-r--r--usbtuner-res/values-af/strings.xml87
-rw-r--r--usbtuner-res/values-am/strings.xml87
-rw-r--r--usbtuner-res/values-ar/strings.xml99
-rw-r--r--usbtuner-res/values-az-rAZ/strings.xml87
-rw-r--r--usbtuner-res/values-bg/strings.xml87
-rw-r--r--usbtuner-res/values-bn-rBD/strings.xml87
-rw-r--r--usbtuner-res/values-ca/strings.xml87
-rw-r--r--usbtuner-res/values-cs/strings.xml93
-rw-r--r--usbtuner-res/values-da/strings.xml87
-rw-r--r--usbtuner-res/values-de/strings.xml87
-rw-r--r--usbtuner-res/values-el/strings.xml87
-rw-r--r--usbtuner-res/values-en-rAU/strings.xml87
-rw-r--r--usbtuner-res/values-en-rGB/strings.xml87
-rw-r--r--usbtuner-res/values-en-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-es-rUS/strings.xml87
-rw-r--r--usbtuner-res/values-es/strings.xml87
-rw-r--r--usbtuner-res/values-et-rEE/strings.xml87
-rw-r--r--usbtuner-res/values-eu-rES/strings.xml87
-rw-r--r--usbtuner-res/values-fa/strings.xml87
-rw-r--r--usbtuner-res/values-fi/strings.xml87
-rw-r--r--usbtuner-res/values-fr-rCA/strings.xml87
-rw-r--r--usbtuner-res/values-fr/strings.xml87
-rw-r--r--usbtuner-res/values-gl-rES/strings.xml87
-rw-r--r--usbtuner-res/values-hi/strings.xml87
-rw-r--r--usbtuner-res/values-hr/strings.xml90
-rw-r--r--usbtuner-res/values-hu/strings.xml87
-rw-r--r--usbtuner-res/values-hy-rAM/strings.xml87
-rw-r--r--usbtuner-res/values-in/strings.xml87
-rw-r--r--usbtuner-res/values-is-rIS/strings.xml87
-rw-r--r--usbtuner-res/values-it/strings.xml87
-rw-r--r--usbtuner-res/values-iw/strings.xml93
-rw-r--r--usbtuner-res/values-ja/strings.xml87
-rw-r--r--usbtuner-res/values-ka-rGE/strings.xml87
-rw-r--r--usbtuner-res/values-kk-rKZ/strings.xml87
-rw-r--r--usbtuner-res/values-km-rKH/strings.xml87
-rw-r--r--usbtuner-res/values-kn-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-ko/strings.xml87
-rw-r--r--usbtuner-res/values-ky-rKG/strings.xml87
-rw-r--r--usbtuner-res/values-lo-rLA/strings.xml87
-rw-r--r--usbtuner-res/values-lt/strings.xml93
-rw-r--r--usbtuner-res/values-lv/strings.xml90
-rw-r--r--usbtuner-res/values-mk-rMK/strings.xml87
-rw-r--r--usbtuner-res/values-ml-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-mn-rMN/strings.xml87
-rw-r--r--usbtuner-res/values-mr-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-ms-rMY/strings.xml87
-rw-r--r--usbtuner-res/values-my-rMM/strings.xml87
-rw-r--r--usbtuner-res/values-nb/strings.xml87
-rw-r--r--usbtuner-res/values-ne-rNP/strings.xml87
-rw-r--r--usbtuner-res/values-nl/strings.xml87
-rw-r--r--usbtuner-res/values-pl/strings.xml93
-rw-r--r--usbtuner-res/values-pt-rPT/strings.xml87
-rw-r--r--usbtuner-res/values-pt/strings.xml87
-rw-r--r--usbtuner-res/values-ro/strings.xml90
-rw-r--r--usbtuner-res/values-ru/strings.xml89
-rw-r--r--usbtuner-res/values-si-rLK/strings.xml87
-rw-r--r--usbtuner-res/values-sk/strings.xml93
-rw-r--r--usbtuner-res/values-sl/strings.xml93
-rw-r--r--usbtuner-res/values-sr/strings.xml90
-rw-r--r--usbtuner-res/values-sv/strings.xml87
-rw-r--r--usbtuner-res/values-sw/strings.xml87
-rw-r--r--usbtuner-res/values-ta-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-te-rIN/strings.xml87
-rw-r--r--usbtuner-res/values-th/strings.xml87
-rw-r--r--usbtuner-res/values-tl/strings.xml87
-rw-r--r--usbtuner-res/values-tr/strings.xml87
-rw-r--r--usbtuner-res/values-uk/strings.xml93
-rw-r--r--usbtuner-res/values-ur-rPK/strings.xml87
-rw-r--r--usbtuner-res/values-uz-rUZ/strings.xml87
-rw-r--r--usbtuner-res/values-vi/strings.xml87
-rw-r--r--usbtuner-res/values-zh-rCN/strings.xml87
-rw-r--r--usbtuner-res/values-zh-rHK/strings.xml87
-rw-r--r--usbtuner-res/values-zh-rTW/strings.xml87
-rw-r--r--usbtuner-res/values-zu/strings.xml87
-rw-r--r--usbtuner-res/values/attrs.xml (renamed from usbtuner/res/values/attrs.xml)0
-rw-r--r--usbtuner-res/values/colors.xml (renamed from usbtuner/res/values/colors.xml)0
-rw-r--r--usbtuner-res/values/dimens.xml (renamed from usbtuner/res/values/dimens.xml)0
-rw-r--r--usbtuner-res/values/integers.xml (renamed from usbtuner/res/values/integers.xml)0
-rw-r--r--usbtuner-res/values/strings.xml (renamed from usbtuner/res/values/strings.xml)57
-rw-r--r--usbtuner-res/values/styles.xml (renamed from usbtuner/res/values/styles.xml)0
-rw-r--r--usbtuner-res/xml/ut_tvinputservice.xml (renamed from usbtuner/res/xml/ut_tvinputservice.xml)2
-rw-r--r--usbtuner/Android.mk110
-rw-r--r--usbtuner/AndroidManifest.xml55
-rwxr-xr-xusbtuner/jni/gen_jni.sh3
-rw-r--r--usbtuner/jni/tunertvinput_jni.h90
-rw-r--r--usbtuner/libs/exoplayer_1.5.6.jarbin752820 -> 0 bytes
-rw-r--r--usbtuner/res/drawable-xhdpi/ic_setup_antenna.pngbin2637 -> 0 bytes
-rw-r--r--usbtuner/res/drawable-xhdpi/recommendation_antenna.pngbin4815 -> 0 bytes
-rw-r--r--usbtuner/res/drawable-xhdpi/usb_antenna.pngbin2897 -> 0 bytes
-rw-r--r--usbtuner/res/raw/ut_us_atsc_center_frequencies_8vsb71
-rw-r--r--usbtuner/res/values-af/strings.xml78
-rw-r--r--usbtuner/res/values-am/strings.xml78
-rw-r--r--usbtuner/res/values-ar/strings.xml90
-rw-r--r--usbtuner/res/values-az-rAZ/strings.xml78
-rw-r--r--usbtuner/res/values-bg/strings.xml78
-rw-r--r--usbtuner/res/values-bn-rBD/strings.xml78
-rw-r--r--usbtuner/res/values-ca/strings.xml78
-rw-r--r--usbtuner/res/values-cs/strings.xml84
-rw-r--r--usbtuner/res/values-da/strings.xml78
-rw-r--r--usbtuner/res/values-de/strings.xml78
-rw-r--r--usbtuner/res/values-el/strings.xml78
-rw-r--r--usbtuner/res/values-en-rAU/strings.xml78
-rw-r--r--usbtuner/res/values-en-rGB/strings.xml78
-rw-r--r--usbtuner/res/values-en-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-es-rUS/strings.xml78
-rw-r--r--usbtuner/res/values-es/strings.xml78
-rw-r--r--usbtuner/res/values-et-rEE/strings.xml78
-rw-r--r--usbtuner/res/values-eu-rES/strings.xml78
-rw-r--r--usbtuner/res/values-fa/strings.xml78
-rw-r--r--usbtuner/res/values-fi/strings.xml78
-rw-r--r--usbtuner/res/values-fr-rCA/strings.xml78
-rw-r--r--usbtuner/res/values-fr/strings.xml78
-rw-r--r--usbtuner/res/values-gl-rES/strings.xml78
-rw-r--r--usbtuner/res/values-hi/strings.xml78
-rw-r--r--usbtuner/res/values-hr/strings.xml81
-rw-r--r--usbtuner/res/values-hu/strings.xml78
-rw-r--r--usbtuner/res/values-hy-rAM/strings.xml78
-rw-r--r--usbtuner/res/values-in/strings.xml78
-rw-r--r--usbtuner/res/values-is-rIS/strings.xml78
-rw-r--r--usbtuner/res/values-it/strings.xml78
-rw-r--r--usbtuner/res/values-iw/strings.xml84
-rw-r--r--usbtuner/res/values-ja/strings.xml78
-rw-r--r--usbtuner/res/values-ka-rGE/strings.xml78
-rw-r--r--usbtuner/res/values-kk-rKZ/strings.xml78
-rw-r--r--usbtuner/res/values-km-rKH/strings.xml78
-rw-r--r--usbtuner/res/values-kn-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-ko/strings.xml78
-rw-r--r--usbtuner/res/values-ky-rKG/strings.xml78
-rw-r--r--usbtuner/res/values-lo-rLA/strings.xml78
-rw-r--r--usbtuner/res/values-lt/strings.xml84
-rw-r--r--usbtuner/res/values-lv/strings.xml81
-rw-r--r--usbtuner/res/values-mk-rMK/strings.xml78
-rw-r--r--usbtuner/res/values-ml-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-mn-rMN/strings.xml78
-rw-r--r--usbtuner/res/values-mr-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-ms-rMY/strings.xml78
-rw-r--r--usbtuner/res/values-my-rMM/strings.xml78
-rw-r--r--usbtuner/res/values-nb/strings.xml78
-rw-r--r--usbtuner/res/values-ne-rNP/strings.xml78
-rw-r--r--usbtuner/res/values-nl/strings.xml78
-rw-r--r--usbtuner/res/values-pl/strings.xml84
-rw-r--r--usbtuner/res/values-pt-rPT/strings.xml78
-rw-r--r--usbtuner/res/values-pt/strings.xml78
-rw-r--r--usbtuner/res/values-ro/strings.xml81
-rw-r--r--usbtuner/res/values-ru/strings.xml84
-rw-r--r--usbtuner/res/values-si-rLK/strings.xml78
-rw-r--r--usbtuner/res/values-sk/strings.xml84
-rw-r--r--usbtuner/res/values-sl/strings.xml84
-rw-r--r--usbtuner/res/values-sr/strings.xml81
-rw-r--r--usbtuner/res/values-sv/strings.xml78
-rw-r--r--usbtuner/res/values-sw/strings.xml78
-rw-r--r--usbtuner/res/values-ta-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-te-rIN/strings.xml78
-rw-r--r--usbtuner/res/values-th/strings.xml78
-rw-r--r--usbtuner/res/values-tl/strings.xml78
-rw-r--r--usbtuner/res/values-tr/strings.xml78
-rw-r--r--usbtuner/res/values-uk/strings.xml84
-rw-r--r--usbtuner/res/values-ur-rPK/strings.xml78
-rw-r--r--usbtuner/res/values-uz-rUZ/strings.xml78
-rw-r--r--usbtuner/res/values-vi/strings.xml78
-rw-r--r--usbtuner/res/values-zh-rCN/strings.xml78
-rw-r--r--usbtuner/res/values-zh-rHK/strings.xml78
-rw-r--r--usbtuner/res/values-zh-rTW/strings.xml78
-rw-r--r--usbtuner/res/values-zu/strings.xml78
-rw-r--r--usbtuner/res/values/themes.xml32
-rw-r--r--usbtuner/src/com/android/usbtuner/InputStreamSource.java73
-rw-r--r--usbtuner/src/com/android/usbtuner/InternalTunerHal.java57
-rw-r--r--usbtuner/src/com/android/usbtuner/UsbTunerDataSource.java310
-rw-r--r--usbtuner/src/com/android/usbtuner/UsbTunerPreferences.java195
-rw-r--r--usbtuner/src/com/android/usbtuner/UsbTunerTsScannerSource.java156
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSourceExtractor.java293
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/PlaySampleExtractor.java228
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/Recorder.java216
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3Decoder.java43
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3PassthroughDecoder.java40
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/cache/RecordingSampleBuffer.java419
-rw-r--r--usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleCache.java401
-rw-r--r--usbtuner/src/com/android/usbtuner/tvinput/BaseTunerTvInputService.java101
-rw-r--r--usbtuner/src/com/android/usbtuner/tvinput/InternalTunerTvInputService.java105
-rw-r--r--usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSessionWorker.java549
-rw-r--r--usbtuner/src/com/android/usbtuner/tvinput/UsbTunerTvInputService.java65
-rw-r--r--usbtuner/src/com/android/usbtuner/util/IsoUtils.java44
-rw-r--r--version.mk4
2574 files changed, 62002 insertions, 19839 deletions
diff --git a/Android.mk b/Android.mk
index ef49c8b1..31fcec21 100644
--- a/Android.mk
+++ b/Android.mk
@@ -15,13 +15,16 @@
#
LOCAL_PATH:= $(call my-dir)
+
include $(CLEAR_VARS)
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
@@ -32,9 +35,18 @@ LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 23 # M
LOCAL_RESOURCE_DIR := \
$(LOCAL_PATH)/res \
- $(LOCAL_PATH)/common/res \
+ $(LOCAL_PATH)/usbtuner-res \
+ $(LOCAL_PATH)/common/res
+
+ifdef TARGET_BUILD_APPS
+LOCAL_RESOURCE_DIR += \
+ $(TOP)/prebuilts/sdk/current/support/v17/leanback/res \
+ $(TOP)/prebuilts/sdk/current/support/v7/recyclerview/res
+else # !TARGET_BUILD_APPS
+LOCAL_RESOURCE_DIR += \
$(TOP)/frameworks/support/v17/leanback/res \
- $(TOP)/frameworks/support/v7/recyclerview/res \
+ $(TOP)/frameworks/support/v7/recyclerview/res
+endif
LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-annotations \
@@ -42,11 +54,14 @@ LOCAL_STATIC_JAVA_LIBRARIES := \
android-support-v7-palette \
android-support-v7-recyclerview \
android-support-v17-leanback \
+ icu4j-usbtuner \
+ lib-exoplayer \
tv-common \
-LOCAL_JAVACFLAGS := -Xlint:deprecation -Xlint:unchecked
+LOCAL_JAVACFLAGS := -Xlint:deprecation -Xlint:unchecked
+
LOCAL_AAPT_FLAGS := --auto-add-overlay \
--extra-packages android.support.v7.recyclerview \
--extra-packages android.support.v17.leanback \
@@ -57,11 +72,42 @@ LOCAL_AAPT_FLAGS := --auto-add-overlay \
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
-LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/usbtuner/res
-LOCAL_STATIC_JAVA_LIBRARIES += usbtuner-tvinput
LOCAL_JNI_SHARED_LIBRARIES := libtunertvinput_jni
-LOCAL_AAPT_FLAGS += --extra-packages com.android.usbtuner
+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
+#############################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
+ lib-exoplayer:libs/exoplayer.jar \
+
+
+include $(BUILD_MULTI_PREBUILT)
+
+
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index a40313cc..1faa2ae3 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -18,6 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tv" xmlns:tools="http://schemas.android.com/tools">
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.GLOBAL_SEARCH" tools:ignore="ProtectedPermissions"/>
<uses-permission android:name="android.permission.INTERNET" />
@@ -39,6 +40,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"
@@ -89,9 +91,11 @@
</activity>
<activity android:name=".LauncherActivity"
+ android:configChanges="keyboard|keyboardHidden"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity android:name=".SetupPassthroughActivity"
+ android:configChanges="keyboard|keyboardHidden"
android:theme="@android:style/Theme.Translucent.NoTitleBar">
<intent-filter>
<action android:name="com.android.tv.action.LAUNCH_INPUT_SETUP" />
@@ -100,17 +104,44 @@
</activity>
<activity android:name=".SelectInputActivity"
+ android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
android:theme="@style/Theme.SelectInputActivity" />
<activity android:name=".onboarding.OnboardingActivity"
+ android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTop"
android:theme="@style/Theme.Setup.GuidedStep" />
<activity android:name=".dvr.ui.DvrActivity"
+ android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
android:theme="@style/Theme.Leanback.Browse" />
+ <activity android:name=".dvr.DvrPlaybackActivity"
+ android:configChanges="keyboard|keyboardHidden|screenSize|smallestScreenSize|screenLayout|orientation"
+ android:launchMode="singleTask"
+ android:theme="@style/Theme.Leanback" />
+
+ <activity android:name=".dvr.ui.DvrDetailsActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:theme="@style/Theme.TV.Dvr.Browse.Details" />
+
+ <activity android:name=".dvr.ui.DvrSeriesSettingsActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:theme="@style/Theme.TV.Dvr.Series.Settings.GuidedStep" />
+
+ <activity android:name=".dvr.ui.DvrSeriesDeletionActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:theme="@style/Theme.TV.Dvr.Series.Deletion.GuidedStep" />
+
+ <activity android:name=".dvr.ui.DvrSeriesScheduledDialogActivity"
+ android:theme="@style/Theme.TV.dialog.HalfSizedDialog"/>
+
+ <activity android:name=".dvr.ui.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"
@@ -153,20 +184,21 @@
</receiver>
<!-- USB tuner components definition -->
- <activity android:name="com.android.usbtuner.setup.TunerSetupActivity"
- android:label="@string/ut_app_name"
+ <activity android:name="com.android.tv.tuner.setup.TunerSetupActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:label="@string/bt_app_name"
android:launchMode="singleInstance"
- android:process="com.android.usbtuner"
+ android:process="com.android.tv.tuner"
android:theme="@style/Theme.Setup.GuidedStep" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
- <activity android:name=".dvr.DvrPlayActivity"/>
- <service android:name="com.android.usbtuner.tvinput.UsbTunerTvInputService"
+
+ <service android:name=".tuner.tvinput.TunerTvInputService"
android:enabled="false"
- android:process="com.android.usbtuner"
- android:label="@string/ut_app_name"
+ android:process="com.android.tv.tuner"
+ android:label="@string/bt_app_name"
android:permission="android.permission.BIND_TV_INPUT" >
<intent-filter>
<action android:name="android.media.tv.TvInputService" />
@@ -174,17 +206,29 @@
<meta-data android:name="android.media.tv.input"
android:resource="@xml/ut_tvinputservice" />
</service>
- <provider android:name="com.android.usbtuner.UsbTunerPreferenceProvider"
- android:authorities="com.android.usbtuner.preferences"
- android:process="com.android.usbtuner"
+ <provider android:name=".tuner.TunerPreferenceProvider"
+ android:authorities="com.android.tv.tuner.preferences"
+ android:process="com.android.tv.tuner"
android:exported="false" />
- <!-- UsbInputController should be the same process with MainActivity to check status of MainActivity -->
- <receiver android:name="com.android.usbtuner.UsbInputController"
+ <!-- System initial setup component definition -->
+ <activity android:name=".setup.SystemSetupActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:label="@string/bt_app_name"
+ android:launchMode="singleInstance"
+ android:theme="@style/Theme.Setup.GuidedStep" >
+ <intent-filter>
+ <action android:name="com.android.tv.action.LAUNCH_SYSTEM_SETUP" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+ <!-- TunerInputController should be the same process with MainActivity to check status of MainActivity -->
+ <receiver android:name=".tuner.TunerInputController"
android:exported="false">
<intent-filter>
- <action android:name="android.intent.action.BOOT_COMPLETED"/>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
+ <action android:name="com.android.tv.action.APPLICATION_FIRST_LAUNCHED" />
</intent-filter>
</receiver>
@@ -192,5 +236,10 @@
<service android:name=".dvr.DvrRecordingService" android:label="@string/dvr_service_name"/>
<receiver android:name=".dvr.DvrStartRecordingReceiver"/>
+ <service android:name=".tuner.tvinput.TunerStorageCleanUpService"
+ android:permission="android.permission.BIND_JOB_SERVICE"
+ android:process="com.android.tv.tuner"
+ android:exported="true" />
+
</application>
</manifest>
diff --git a/common/res/layout/fragment_setup_multi_pane.xml b/common/res/layout/fragment_setup_multi_pane.xml
index 84798c02..45aff132 100644
--- a/common/res/layout/fragment_setup_multi_pane.xml
+++ b/common/res/layout/fragment_setup_multi_pane.xml
@@ -39,7 +39,7 @@
android:layout_marginEnd="1dp"
android:clipChildren="false"
android:clipToPadding="false" />
- // TODO: Use button action list in GuidedStepFragment
+ <!-- TODO: Use button action list in GuidedStepFragment -->
<FrameLayout
android:id="@+id/done_button_container"
android:layout_width="@dimen/setup_done_button_container_width"
diff --git a/common/res/values-af/strings.xml b/common/res/values-af/strings.xml
index 83ad9ae6..7a114849 100644
--- a/common/res/values-af/strings.xml
+++ b/common/res/values-af/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Klaar"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S.<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-am/strings.xml b/common/res/values-am/strings.xml
index 17442b05..45a1b7cb 100644
--- a/common/res/values-am/strings.xml
+++ b/common/res/values-am/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"ተከናውኗል"</string>
- <string name="episode_format" msgid="5985513854870276591">"ምዕ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>፦ ክፍል <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g><xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"ም<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>፦ ክ.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ክ.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"ም<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>፦ ክፍል <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ክፍል <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ም<xliff:g id="SEASONNUMBER">%2$s</xliff:g>፦ ክፍል <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ክፍል <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ar/strings.xml b/common/res/values-ar/strings.xml
index 27d6ce66..bedd137b 100644
--- a/common/res/values-ar/strings.xml
+++ b/common/res/values-ar/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"تم"</string>
- <string name="episode_format" msgid="5985513854870276591">"الموسم <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: الحلقة <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"الموسم <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: الحلقة <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"الحلقة <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"الموسم <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: الحلقة <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"الحلقة <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> الموسم رقم <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: الحلقة رقم <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> الحلقة رقم <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-az-rAZ/strings.xml b/common/res/values-az-rAZ/strings.xml
index 35e847a9..c844cd60 100644
--- a/common/res/values-az-rAZ/strings.xml
+++ b/common/res/values-az-rAZ/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Hazırdır"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Epizod<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-bg/strings.xml b/common/res/values-bg/strings.xml
index 87c5c919..264a1118 100644
--- a/common/res/values-bg/strings.xml
+++ b/common/res/values-bg/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Готово"</string>
- <string name="episode_format" msgid="5985513854870276591">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Еп. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – „<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>“"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: епизод <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Епизод <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Еп. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – „<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>“"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Еп. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> – „<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>“"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"„<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“, сезон <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, епизод <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"„<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“, епизод <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-bn-rBD/strings.xml b/common/res/values-bn-rBD/strings.xml
index 5a7614f8..836a62a5 100644
--- a/common/res/values-bn-rBD/strings.xml
+++ b/common/res/values-bn-rBD/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"সম্পন্ন"</string>
- <string name="episode_format" msgid="5985513854870276591">"সিঃ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: এপিঃ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"সিজন <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> , পর্ব <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"পর্ব<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"সিঃ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: এপিঃ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"এপিঃ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> সিজিন<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: পর্ব <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> পর্ব. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ca/strings.xml b/common/res/values-ca/strings.xml
index c3c62cc0..6382648e 100644
--- a/common/res/values-ca/strings.xml
+++ b/common/res/values-ca/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Fet"</string>
- <string name="episode_format" msgid="5985513854870276591">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episodi <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodi <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Episodi <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodi <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Episodi <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: temporada <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, episodi <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: episodi <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-cs/strings.xml b/common/res/values-cs/strings.xml
index 8550e53c..0be8026c 100644
--- a/common/res/values-cs/strings.xml
+++ b/common/res/values-cs/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Hotovo"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>E<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"E<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-da/strings.xml b/common/res/values-da/strings.xml
index ccc2d53c..4685b818 100644
--- a/common/res/values-da/strings.xml
+++ b/common/res/values-da/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Udført"</string>
- <string name="episode_format" msgid="5985513854870276591">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, afsn. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, afsn. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Afsn. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Afsnit <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Afsnit <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S. <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Afsn. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> afsn. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-de/strings.xml b/common/res/values-de/strings.xml
index 965c63fb..a487ff8a 100644
--- a/common/res/values-de/strings.xml
+++ b/common/res/values-de/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Fertig"</string>
- <string name="episode_format" msgid="5985513854870276591">"Staffel <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Folge <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: F<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Folge <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Staffel <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Folge <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Folge <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, Staffel <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Folge <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, Folge <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-el/strings.xml b/common/res/values-el/strings.xml
index 361a0d55..dba894cb 100644
--- a/common/res/values-el/strings.xml
+++ b/common/res/values-el/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Τέλος"</string>
- <string name="episode_format" msgid="5985513854870276591">"Σεζ. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Επ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Σεζ. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Επ.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Επ.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Σεζ.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Επ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Επ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Σεζόν<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Επ. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Επ. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-en-rAU/strings.xml b/common/res/values-en-rAU/strings.xml
index 423dc885..0ea27edc 100644
--- a/common/res/values-en-rAU/strings.xml
+++ b/common/res/values-en-rAU/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Finished"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-en-rGB/strings.xml b/common/res/values-en-rGB/strings.xml
index 423dc885..0ea27edc 100644
--- a/common/res/values-en-rGB/strings.xml
+++ b/common/res/values-en-rGB/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Finished"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-en-rIN/strings.xml b/common/res/values-en-rIN/strings.xml
index 423dc885..0ea27edc 100644
--- a/common/res/values-en-rIN/strings.xml
+++ b/common/res/values-en-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Finished"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-es-rUS/strings.xml b/common/res/values-es-rUS/strings.xml
index ac34b685..87c881b8 100644
--- a/common/res/values-es-rUS/strings.xml
+++ b/common/res/values-es-rUS/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Listo"</string>
- <string name="episode_format" msgid="5985513854870276591">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. Episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Episodio <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Episodio <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: T<xliff:g id="SEASONNUMBER">%2$s</xliff:g>, episodio <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: episodio <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-es/strings.xml b/common/res/values-es/strings.xml
index 5d21f0a5..32536d93 100644
--- a/common/res/values-es/strings.xml
+++ b/common/res/values-es/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Listo"</string>
- <string name="episode_format" msgid="5985513854870276591">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Episodio <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episodio <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Episodio <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"Temporada <xliff:g id="SEASONNUMBER">%2$s</xliff:g> de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>, episodio <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"Episodio <xliff:g id="EPISODENUMBER">%2$s</xliff:g> de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-et-rEE/strings.xml b/common/res/values-et-rEE/strings.xml
index d97e467a..9052178a 100644
--- a/common/res/values-et-rEE/strings.xml
+++ b/common/res/values-et-rEE/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Valmis"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. hooaeg: jagu <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. hooaeg: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. jagu"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. jagu"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. hooaeg: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. jagu – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. jagu – <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. hooaeg, <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. jagu"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. jagu"</string>
</resources>
diff --git a/common/res/values-eu-rES/strings.xml b/common/res/values-eu-rES/strings.xml
index 4e84f936..d7ab52a8 100644
--- a/common/res/values-eu-rES/strings.xml
+++ b/common/res/values-eu-rES/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Eginda"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. denboraldiko <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. atala: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. denboraldiko <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. atala"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. atala"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. denboraldiko <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. atala: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. atala: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. denboraldia: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. atala"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. atala"</string>
</resources>
diff --git a/common/res/values-fa/strings.xml b/common/res/values-fa/strings.xml
index 3f531a2b..67e9c4e6 100644
--- a/common/res/values-fa/strings.xml
+++ b/common/res/values-fa/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"تمام"</string>
- <string name="episode_format" msgid="5985513854870276591">"ف<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ق <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"فصل<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: قسمت<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"اپیزود <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"ف.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ق. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ق. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> فصل <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: قسمت <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> قسمت <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-fi/strings.xml b/common/res/values-fi/strings.xml
index 566ca328..8c6b99bf 100644
--- a/common/res/values-fi/strings.xml
+++ b/common/res/values-fi/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Valmis"</string>
- <string name="episode_format" msgid="5985513854870276591">"Kausi <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: jakso <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Kausi <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, jakso <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Jakso <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Kausi <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, jakso <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Jakso <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> kausi <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, jakso <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> jakso <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-fr-rCA/strings.xml b/common/res/values-fr-rCA/strings.xml
index 59d6bbf2..ed5678e2 100644
--- a/common/res/values-fr-rCA/strings.xml
+++ b/common/res/values-fr-rCA/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Terminé"</string>
- <string name="episode_format" msgid="5985513854870276591">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, épisode <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, « <xliff:g id="EPISODE_TITLE">%3$s</xliff:g> »"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, ép. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ép. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, épisode <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, « <xliff:g id="EPISODE_TITLE">%3$s</xliff:g> »"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Épisode <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>, « <xliff:g id="EPISODE_TITLE">%2$s</xliff:g> »"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, saison <xliff:g id="SEASONNUMBER">%2$s</xliff:g> : épisode <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, épisode <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-fr/strings.xml b/common/res/values-fr/strings.xml
index 10a0b5ee..b5b28104 100644
--- a/common/res/values-fr/strings.xml
+++ b/common/res/values-fr/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"OK"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, ép. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> : <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, épisode <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Épisode <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, ép. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> : <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ép. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> : <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – S <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, ép. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – Ép. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-gl-rES/strings.xml b/common/res/values-gl-rES/strings.xml
index 356e84d2..356ac562 100644
--- a/common/res/values-gl-rES/strings.xml
+++ b/common/res/values-gl-rES/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Feito"</string>
- <string name="episode_format" msgid="5985513854870276591">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"T <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> T<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-hi/strings.xml b/common/res/values-hi/strings.xml
index 2aaad475..27cae84d 100644
--- a/common/res/values-hi/strings.xml
+++ b/common/res/values-hi/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"हो गया"</string>
- <string name="episode_format" msgid="5985513854870276591">"सीज़न<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"सीज़न<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"एपिसोड <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"सीज़न<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"एपिसोड <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> सीज़न<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: एपिसोड <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> एपिसोड <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-hr/strings.xml b/common/res/values-hr/strings.xml
index 6ab8b924..66127784 100644
--- a/common/res/values-hr/strings.xml
+++ b/common/res/values-hr/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Gotovo"</string>
- <string name="episode_format" msgid="5985513854870276591">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. s.: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. ep."</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. ep."</string>
</resources>
diff --git a/common/res/values-hu/strings.xml b/common/res/values-hu/strings.xml
index d73e295c..138ad857 100644
--- a/common/res/values-hu/strings.xml
+++ b/common/res/values-hu/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Kész"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. évad, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. rész: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. évad, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. rész"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. rész"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. évad, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. rész: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. rész: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. évad, <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. epizód"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. epizód"</string>
</resources>
diff --git a/common/res/values-hy-rAM/strings.xml b/common/res/values-hy-rAM/strings.xml
index b9b2b5d6..aaa7470f 100644
--- a/common/res/values-hy-rAM/strings.xml
+++ b/common/res/values-hy-rAM/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Պատրաստ է"</string>
- <string name="episode_format" msgid="5985513854870276591">"Ե<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>՝ դրվ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Ե <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>՝ դրվ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Դրվ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Ե<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>՝ դրվ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Դրվ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ե<xliff:g id="SEASONNUMBER">%2$s</xliff:g>՝ Դրվ. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Դրվ. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-in/strings.xml b/common/res/values-in/strings.xml
index 7435341c..da4b8203 100644
--- a/common/res/values-in/strings.xml
+++ b/common/res/values-in/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Selesai"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-is-rIS/strings.xml b/common/res/values-is-rIS/strings.xml
index f699ea19..47529403 100644
--- a/common/res/values-is-rIS/strings.xml
+++ b/common/res/values-is-rIS/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Lokið"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Þ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Þ.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. þáttur"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Þ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Þ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S.<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Þ. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Þ. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-it/strings.xml b/common/res/values-it/strings.xml
index 48a7751b..f61e02f7 100644
--- a/common/res/values-it/strings.xml
+++ b/common/res/values-it/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Fine"</string>
- <string name="episode_format" msgid="5985513854870276591">"Stag. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Punt. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Stagione <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, puntata <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Stag. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: punt. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Punt. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Stag. <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: punt. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Punt. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-iw/strings.xml b/common/res/values-iw/strings.xml
index b0e49d7f..7ad220ad 100644
--- a/common/res/values-iw/strings.xml
+++ b/common/res/values-iw/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"סיום"</string>
- <string name="episode_format" msgid="5985513854870276591">"עונה <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: פרק <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"עונה <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: פרק <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"פרק <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"עונה<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: פרק <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"פרק <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> עונה <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: פרק <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> פרק <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ja/strings.xml b/common/res/values-ja/strings.xml
index d5f072f3..682fd0d8 100644
--- a/common/res/values-ja/strings.xml
+++ b/common/res/values-ja/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"完了"</string>
- <string name="episode_format" msgid="5985513854870276591">"シーズン <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: エピソード <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>「<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>」"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"シーズン <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: エピソード <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"エピソード <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"シーズン <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: エピソード <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>「<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>」"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"エピソード <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>「<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>」"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>、シーズン <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: エピソード <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>、エピソード <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ka-rGE/strings.xml b/common/res/values-ka-rGE/strings.xml
index b209520a..3c7062ff 100644
--- a/common/res/values-ka-rGE/strings.xml
+++ b/common/res/values-ka-rGE/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"მზადაა"</string>
- <string name="episode_format" msgid="5985513854870276591">"სეზ. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, ეპ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"სეზ. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ეპ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ეპ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"სეზ. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, ეპ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> — <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ეპ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> — <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: სეზ. <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, ეპ. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: სეზ. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-kk-rKZ/strings.xml b/common/res/values-kk-rKZ/strings.xml
index 5f732dc0..12de7d34 100644
--- a/common/res/values-kk-rKZ/strings.xml
+++ b/common/res/values-kk-rKZ/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Орындалды"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-маусым, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-эпизод: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-маусым, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-серия"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-серия"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-маусым: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-серия, \"<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\""</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-серия, \"<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>\""</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="SEASONNUMBER">%2$s</xliff:g>-маусым, <xliff:g id="EPISODENUMBER">%3$s</xliff:g>-серия"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="EPISODENUMBER">%2$s</xliff:g>-серия"</string>
</resources>
diff --git a/common/res/values-km-rKH/strings.xml b/common/res/values-km-rKH/strings.xml
index 0a83185a..b8353897 100644
--- a/common/res/values-km-rKH/strings.xml
+++ b/common/res/values-km-rKH/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"រួចរាល់"</string>
- <string name="episode_format" msgid="5985513854870276591">"រដូវកាលទី <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>៖ វគ្គ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"រដូវកាល<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>៖ ភាគ<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ភាគ៖ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"រដូវកាលទី <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>៖ វគ្គ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"វគ្គ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> រដូវ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>៖ ភាគ <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ភាគ <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-kn-rIN/strings.xml b/common/res/values-kn-rIN/strings.xml
index 27821741..7cb096b7 100644
--- a/common/res/values-kn-rIN/strings.xml
+++ b/common/res/values-kn-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"ಮುಗಿದಿದೆ"</string>
- <string name="episode_format" msgid="5985513854870276591">"ಸೀ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ಸಂಚಿಕೆ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"ಕಾಲ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>ಭಾಗ<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ಭಾಗ<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"ಸೀ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ಸಂ. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ಸಂ. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ಸೀ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ಸಂ. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ಸಂ. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ko/strings.xml b/common/res/values-ko/strings.xml
index e5ca8d69..923831f3 100644
--- a/common/res/values-ko/strings.xml
+++ b/common/res/values-ko/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"완료"</string>
- <string name="episode_format" msgid="5985513854870276591">"시즌 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: 에피소드 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"시즌 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: 에피소드 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"에피소드 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"시즌 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: 에피소드 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> \'<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\'"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"에피소드 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> \'<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>\'"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> 시즌 <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: 에피소드 <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> 에피소드 <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ky-rKG/strings.xml b/common/res/values-ky-rKG/strings.xml
index 333232af..8bdfadde 100644
--- a/common/res/values-ky-rKG/strings.xml
+++ b/common/res/values-ky-rKG/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Бүттү"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-м.: Эп. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-мезгил: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-серия"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-серия"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"С<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g> <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-серия"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_TITLE">%2$s</xliff:g> <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-серия"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>-эпизод"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="EPISODENUMBER">%2$s</xliff:g>-эпизод"</string>
</resources>
diff --git a/common/res/values-lo-rLA/strings.xml b/common/res/values-lo-rLA/strings.xml
index a448b0b8..a6dad515 100644
--- a/common/res/values-lo-rLA/strings.xml
+++ b/common/res/values-lo-rLA/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"ສຳເລັດແລ້ວ"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ຕອນ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-lt/strings.xml b/common/res/values-lt/strings.xml
index 46e4adef..6d6c0ee8 100644
--- a/common/res/values-lt/strings.xml
+++ b/common/res/values-lt/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Atlikta"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> sezonas: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> serija „<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>“"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> sezonas: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> serija"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> serija"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> sezonas: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> serija „<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>“"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> serija „<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>“"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"Programos „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ <xliff:g id="SEASONNUMBER">%2$s</xliff:g> sezonas: <xliff:g id="EPISODENUMBER">%3$s</xliff:g> serija"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"Programos „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ <xliff:g id="EPISODENUMBER">%2$s</xliff:g> serija"</string>
</resources>
diff --git a/common/res/values-lv/strings.xml b/common/res/values-lv/strings.xml
index 0b2c91d3..f0366a48 100644
--- a/common/res/values-lv/strings.xml
+++ b/common/res/values-lv/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Gatavs"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona, <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. sērija “<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>”"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sez., <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. sēr."</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. sēr."</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. sērija “<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>”"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. sērija “<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>”"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. sezona, <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. sērija"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>: <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. sērija"</string>
</resources>
diff --git a/common/res/values-mk-rMK/strings.xml b/common/res/values-mk-rMK/strings.xml
index 406bd745..73045d3d 100644
--- a/common/res/values-mk-rMK/strings.xml
+++ b/common/res/values-mk-rMK/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Готово"</string>
- <string name="episode_format" msgid="5985513854870276591">"Сез. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Еп. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Сез.<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Еп.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Еп.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Сез. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Еп. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Еп. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Сез.<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Еп.. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Еп. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ml-rIN/strings.xml b/common/res/values-ml-rIN/strings.xml
index 5b40e844..07727684 100644
--- a/common/res/values-ml-rIN/strings.xml
+++ b/common/res/values-ml-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"പൂർത്തിയായി"</string>
- <string name="episode_format" msgid="5985513854870276591">"സീസൺ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: എപ്പിസോഡ് <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"സീസൺ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: എപ്പി.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"എപ്പി.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"സീസൺ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: എപ്പിസോഡ് <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"എപ്പിസോഡ് <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> സീരിയൽ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: എപ്പിസോഡ് <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> എപ്പിസോഡ് <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-mn-rMN/strings.xml b/common/res/values-mn-rMN/strings.xml
index 3a6295b0..ff1552e0 100644
--- a/common/res/values-mn-rMN/strings.xml
+++ b/common/res/values-mn-rMN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Дууссан"</string>
- <string name="episode_format" msgid="5985513854870276591">"Бүлэг<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Анги. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Бүлэг<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Цуврал.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Анги.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Бүлэг<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Анги. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Анги. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Бүлэг<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Анги. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Анги. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-mr-rIN/strings.xml b/common/res/values-mr-rIN/strings.xml
index 2709733e..adc669ae 100644
--- a/common/res/values-mr-rIN/strings.xml
+++ b/common/res/values-mr-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"पूर्ण झाले"</string>
- <string name="episode_format" msgid="5985513854870276591">"हंगाम<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: भाग. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"हंगाम<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: भाग<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"भाग<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"हंगाम<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: भाग. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"भाग. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> सत्र<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: भाग <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> भाग <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ms-rMY/strings.xml b/common/res/values-ms-rMY/strings.xml
index c0372b30..06eb6173 100644
--- a/common/res/values-ms-rMY/strings.xml
+++ b/common/res/values-ms-rMY/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Selesai"</string>
- <string name="episode_format" msgid="5985513854870276591">"M<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"M<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"M<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-my-rMM/strings.xml b/common/res/values-my-rMM/strings.xml
index 6577fbed..977c4315 100644
--- a/common/res/values-my-rMM/strings.xml
+++ b/common/res/values-my-rMM/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"ပြီးပါပြီ"</string>
- <string name="episode_format" msgid="5985513854870276591">"ဇာတ်လမ်းတွဲ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>− အပိုင်းငယ် <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"အတွဲ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>− အပိုင်း<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"အပိုင်း <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"အတွဲ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>− အပိုင်း <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"အပိုင်း <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> အတွဲ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>− အပိုင်း <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> အပိုင်း <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-nb/strings.xml b/common/res/values-nb/strings.xml
index e9bf0493..8344a76b 100644
--- a/common/res/values-nb/strings.xml
+++ b/common/res/values-nb/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Ferdig"</string>
- <string name="episode_format" msgid="5985513854870276591">"Sesong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Sesong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> episode <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Episode <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Sesong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: episode <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Episode <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Sesong <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Episode <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Episode <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ne-rNP/strings.xml b/common/res/values-ne-rNP/strings.xml
index 265ec91d..4f3d24c1 100644
--- a/common/res/values-ne-rNP/strings.xml
+++ b/common/res/values-ne-rNP/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"सम्पन्न भयो"</string>
- <string name="episode_format" msgid="5985513854870276591">"सिजन <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"सिजन <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"एपिसोड <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"सिजन <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: एपिसोड <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"एपिसोड <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> सिजन <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: एपिसोड <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> एपिसोड <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-nl/strings.xml b/common/res/values-nl/strings.xml
index cc3ee7eb..4e5a1011 100644
--- a/common/res/values-nl/strings.xml
+++ b/common/res/values-nl/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Gereed"</string>
- <string name="episode_format" msgid="5985513854870276591">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: afl. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> afl. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Afl. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: afl. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Afl. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Afl. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Afl. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-pl/strings.xml b/common/res/values-pl/strings.xml
index ddcd5614..5161e3ba 100644
--- a/common/res/values-pl/strings.xml
+++ b/common/res/values-pl/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Gotowe"</string>
- <string name="episode_format" msgid="5985513854870276591">"Sez. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, odc. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Sez. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: odc. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Odc. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Sez. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, odc. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Odc. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – sez. <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, odc. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, odc. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-pt-rPT/strings.xml b/common/res/values-pt-rPT/strings.xml
index b08d7084..badaae27 100644
--- a/common/res/values-pt-rPT/strings.xml
+++ b/common/res/values-pt-rPT/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Concluído"</string>
- <string name="episode_format" msgid="5985513854870276591">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"T. <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> T<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-pt/strings.xml b/common/res/values-pt/strings.xml
index a6d69e48..0fc3e097 100644
--- a/common/res/values-pt/strings.xml
+++ b/common/res/values-pt/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Concluído"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"T<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> T<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ro/strings.xml b/common/res/values-ro/strings.xml
index 5cb24634..ae6fc497 100644
--- a/common/res/values-ro/strings.xml
+++ b/common/res/values-ro/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Terminat"</string>
- <string name="episode_format" msgid="5985513854870276591">"Sezonul <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodul <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Sezonul <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodul <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Episodul <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Sezonul <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, episodul <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Episodul <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, sezonul <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, episodul <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, episodul <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ru/strings.xml b/common/res/values-ru/strings.xml
index 52e06816..53c341aa 100644
--- a/common/res/values-ru/strings.xml
+++ b/common/res/values-ru/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Готово"</string>
- <string name="episode_format" msgid="5985513854870276591">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: серия <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, \"<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\""</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, серия <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Серия <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: серия <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>, \"<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\""</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Серия <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>, \"<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>\""</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, сезон <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, серия <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, серия <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-si-rLK/strings.xml b/common/res/values-si-rLK/strings.xml
index 4b62ae21..85fc1f94 100644
--- a/common/res/values-si-rLK/strings.xml
+++ b/common/res/values-si-rLK/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"නිමයි"</string>
- <string name="episode_format" msgid="5985513854870276591">"වාරය<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: කථාංගය <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"වාරය<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>කථාංගය<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"කථාංගය <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"වාරය<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: කථාංගය <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"කථාංගය <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> වාරය<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: කථාංගය. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> කථාංගය. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-sk/strings.xml b/common/res/values-sk/strings.xml
index aa0345ff..1d1a673f 100644
--- a/common/res/values-sk/strings.xml
+++ b/common/res/values-sk/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Hotovo"</string>
- <string name="episode_format" msgid="5985513854870276591">"S <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"E<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. sezóna: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. epizóda"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. epizóda"</string>
</resources>
diff --git a/common/res/values-sl/strings.xml b/common/res/values-sl/strings.xml
index 06e4218a..26ec614d 100644
--- a/common/res/values-sl/strings.xml
+++ b/common/res/values-sl/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Končano"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona – <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. epizoda: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. epizoda"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. epizoda"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona – <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. epizoda: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. epizoda: <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. sezona: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. epizoda"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. epizoda"</string>
</resources>
diff --git a/common/res/values-sr/strings.xml b/common/res/values-sr/strings.xml
index 780d096e..ef7f9ee5 100644
--- a/common/res/values-sr/strings.xml
+++ b/common/res/values-sr/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Готово"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. серијал: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. епизода, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Серијал: <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Епизода: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. епизода"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. серијал: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. епизода, <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. епизода, <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="SEASONNUMBER">%2$s</xliff:g>. серијал: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. епизода"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. епизода"</string>
</resources>
diff --git a/common/res/values-sv/strings.xml b/common/res/values-sv/strings.xml
index 4cf53a0c..9911a0de 100644
--- a/common/res/values-sv/strings.xml
+++ b/common/res/values-sv/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Klar"</string>
- <string name="episode_format" msgid="5985513854870276591">"Säsong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: avsnitt <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Säsong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>, avsnitt <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Avsnitt <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Säsong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: avsnitt <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Avsnitt <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> – <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Säsong<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: avsnitt <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> avsnitt. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-sw/strings.xml b/common/res/values-sw/strings.xml
index 7ad2f1e5..7d44cedf 100644
--- a/common/res/values-sw/strings.xml
+++ b/common/res/values-sw/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Nimemaliza"</string>
- <string name="episode_format" msgid="5985513854870276591">"Msimu wa <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Kipindi cha <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Msimu wa <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Kipindi cha <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Kipindi cha <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Msimu wa <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Kipindi cha <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Kipindi cha <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>Msimu wa <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Kipindi cha <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Kipindi cha <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ta-rIN/strings.xml b/common/res/values-ta-rIN/strings.xml
index fb7b541a..bc2eed62 100644
--- a/common/res/values-ta-rIN/strings.xml
+++ b/common/res/values-ta-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"முடிந்தது"</string>
- <string name="episode_format" msgid="5985513854870276591">"சீ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: எபி. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"சீ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: எபி.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"எபி.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"சீ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: எபி. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"எபி. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> சீ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: எபி. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> எபி. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-te-rIN/strings.xml b/common/res/values-te-rIN/strings.xml
index be10c428..80df229d 100644
--- a/common/res/values-te-rIN/strings.xml
+++ b/common/res/values-te-rIN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"పూర్తయింది"</string>
- <string name="episode_format" msgid="5985513854870276591">"సీ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ఎపి. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"సీ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ఎపి.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ఎపి.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"సీ<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ఎపి. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ఎపి. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> సీ<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ఎపి. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ఎపి. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-th/strings.xml b/common/res/values-th/strings.xml
index 3acaefd0..5ff9f1ff 100644
--- a/common/res/values-th/strings.xml
+++ b/common/res/values-th/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"เสร็จสิ้น"</string>
- <string name="episode_format" msgid="5985513854870276591">"ซีซัน <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ตอนที่ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"ซีซัน <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ตอนที่ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ตอนที่ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"ซีซัน <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ตอนที่ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ตอนที่ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ซีซัน <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ตอน <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ตอน <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-tl/strings.xml b/common/res/values-tl/strings.xml
index 0e176018..e6b8bbbc 100644
--- a/common/res/values-tl/strings.xml
+++ b/common/res/values-tl/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Tapos Na"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-tr/strings.xml b/common/res/values-tr/strings.xml
index 63000a1d..c25c834f 100644
--- a/common/res/values-tr/strings.xml
+++ b/common/res/values-tr/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Bitti"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Böl. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Böl.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Böl.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>. Bölüm <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>. Bölüm <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="SEASONNUMBER">%2$s</xliff:g>.S: <xliff:g id="EPISODENUMBER">%3$s</xliff:g>. Böl."</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> <xliff:g id="EPISODENUMBER">%2$s</xliff:g>. Böl."</string>
</resources>
diff --git a/common/res/values-uk/strings.xml b/common/res/values-uk/strings.xml
index b229340b..9b67cf4a 100644
--- a/common/res/values-uk/strings.xml
+++ b/common/res/values-uk/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Готово"</string>
- <string name="episode_format" msgid="5985513854870276591">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: серія <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> \"<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\""</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: серія <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Серія <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: серія <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> \"<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>\""</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Серія <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> \"<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>\""</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"\"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\": сезон <xliff:g id="SEASONNUMBER">%2$s</xliff:g>, серія <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"\"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\": серія <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-ur-rPK/strings.xml b/common/res/values-ur-rPK/strings.xml
index 0baab923..b04fb3c3 100644
--- a/common/res/values-ur-rPK/strings.xml
+++ b/common/res/values-ur-rPK/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"ہو گیا"</string>
- <string name="episode_format" msgid="5985513854870276591">"سیزن <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: قسط <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"سیزن<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ایپی سوڈ۔<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"ایپی سوڈ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"سیزن <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: ایپی سوڈ <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"ایپی سوڈ <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> سیزن <xliff:g id="SEASONNUMBER">%2$s</xliff:g>: ایپی سوڈ <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ایپی سوڈ <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-uz-rUZ/strings.xml b/common/res/values-uz-rUZ/strings.xml
index d595a5ff..ffa1cf9c 100644
--- a/common/res/values-uz-rUZ/strings.xml
+++ b/common/res/values-uz-rUZ/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Tayyor"</string>
- <string name="episode_format" msgid="5985513854870276591">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-fasl <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-qism: <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-fasl: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-qism"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-qism"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-fasl: <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>-qism – “<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>”"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>-qism – “<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>”"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="SEASONNUMBER">%2$s</xliff:g>-fasl <xliff:g id="EPISODENUMBER">%3$s</xliff:g>-qism"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, <xliff:g id="EPISODENUMBER">%2$s</xliff:g>-qism"</string>
</resources>
diff --git a/common/res/values-vi/strings.xml b/common/res/values-vi/strings.xml
index bad8efcb..2852bb10 100644
--- a/common/res/values-vi/strings.xml
+++ b/common/res/values-vi/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Xong"</string>
- <string name="episode_format" msgid="5985513854870276591">"Phần <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Tập <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"Phần<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Tập<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Tập<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"Phần <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Tập <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Tập <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> P<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Tập <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Tập <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values-zh-rCN/strings.xml b/common/res/values-zh-rCN/strings.xml
index 0865cb50..25e13379 100644
--- a/common/res/values-zh-rCN/strings.xml
+++ b/common/res/values-zh-rCN/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"完成"</string>
- <string name="episode_format" msgid="5985513854870276591">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集《<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>》"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集:<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集:<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="SEASONNUMBER">%2$s</xliff:g> 季:第 <xliff:g id="EPISODENUMBER">%3$s</xliff:g> 集"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="EPISODENUMBER">%2$s</xliff:g> 集"</string>
</resources>
diff --git a/common/res/values-zh-rHK/strings.xml b/common/res/values-zh-rHK/strings.xml
index d8e8a030..ed323c6a 100644
--- a/common/res/values-zh-rHK/strings.xml
+++ b/common/res/values-zh-rHK/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"完成"</string>
- <string name="episode_format" msgid="5985513854870276591">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集 <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集 <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集 <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="SEASONNUMBER">%2$s</xliff:g> 季:第 <xliff:g id="EPISODENUMBER">%3$s</xliff:g> 集"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="EPISODENUMBER">%2$s</xliff:g> 集"</string>
</resources>
diff --git a/common/res/values-zh-rTW/strings.xml b/common/res/values-zh-rTW/strings.xml
index 4c318bc1..25e13379 100644
--- a/common/res/values-zh-rTW/strings.xml
+++ b/common/res/values-zh-rTW/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"完成"</string>
- <string name="episode_format" msgid="5985513854870276591">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集「<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>」"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季:第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季第 <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> 集:<xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"第 <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> 集:<xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="SEASONNUMBER">%2$s</xliff:g> 季:第 <xliff:g id="EPISODENUMBER">%3$s</xliff:g> 集"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》第 <xliff:g id="EPISODENUMBER">%2$s</xliff:g> 集"</string>
</resources>
diff --git a/common/res/values-zu/strings.xml b/common/res/values-zu/strings.xml
index 138dca92..4574ac01 100644
--- a/common/res/values-zu/strings.xml
+++ b/common/res/values-zu/strings.xml
@@ -18,5 +18,10 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done" msgid="298287050387266501">"Kwenziwe"</string>
- <string name="episode_format" msgid="5985513854870276591">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_number_format" msgid="6040735693510854344">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep.<xliff:g id="EPISODE_NUMBER">%2$s</xliff:g>"</string>
+ <string name="display_episode_number_format_no_season_number" msgid="8393554269654325741">"Ep.<xliff:g id="EPISODE_NUMBER">%1$s</xliff:g>"</string>
+ <string name="display_episode_title_format" msgid="5041103178918130554">"S<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>: Ep. <xliff:g id="EPISODE_NUMBER">%2$s</xliff:g> <xliff:g id="EPISODE_TITLE">%3$s</xliff:g>"</string>
+ <string name="display_episode_title_format_no_season_number" msgid="4558449786705748989">"Ep. <xliff:g id="EPISODE_NUMBER">%1$s</xliff:g> <xliff:g id="EPISODE_TITLE">%2$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number" msgid="5708628769757639737">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> S<xliff:g id="SEASONNUMBER">%2$s</xliff:g>: Ep. <xliff:g id="EPISODENUMBER">%3$s</xliff:g>"</string>
+ <string name="program_title_with_episode_number_no_season" msgid="8299170840696856426">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> Ep. <xliff:g id="EPISODENUMBER">%2$s</xliff:g>"</string>
</resources>
diff --git a/common/res/values/dimens.xml b/common/res/values/dimens.xml
index 4d8286cd..9d6e0e67 100644
--- a/common/res/values/dimens.xml
+++ b/common/res/values/dimens.xml
@@ -26,7 +26,7 @@
<dimen name="setup_done_button_container_width">138dp</dimen>
<dimen name="setup_guidedactions_selector_margin_start">24dp</dimen>
<dimen name="setup_guidedactions_selector_margin_end">24dp</dimen>
- <dimen name="setup_guidedactions_selector_margin_top">190dp</dimen>
+ <dimen name="setup_guidedactions_selector_margin_top">220dp</dimen>
<dimen name="setup_guidedactions_item_container_padding_start">40dp</dimen>
<dimen name="setup_guidedactions_item_container_padding_end">40dp</dimen>
<dimen name="setup_guidedactions_vertical_padding">12dp</dimen>
diff --git a/common/res/values/strings.xml b/common/res/values/strings.xml
index 0d1d3514..e5b9b625 100644
--- a/common/res/values/strings.xml
+++ b/common/res/values/strings.xml
@@ -17,6 +17,16 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="action_text_done">Done</string>
- <!-- The episode title format displayed on the info banner. For example, "S1: Ep. 1 Winter is coming". -->
- <string name="episode_format">S<xliff:g id="season_number" example="1">%1$s</xliff:g>: Ep. <xliff:g id="episode_number" example="1">%2$s</xliff:g> <xliff:g id="episode_title" example="Winder is coming">%3$s</xliff:g></string>
+ <!-- The episode display format with season and episode number used in series details view. -->
+ <string name="display_episode_number_format">S<xliff:g id="season_number" example="1">%1$s</xliff:g>: Ep.<xliff:g id="episode_number" example="1">%2$s</xliff:g></string>
+ <!-- The episode display format with episode number used in series details view. -->
+ <string name="display_episode_number_format_no_season_number">Ep.<xliff:g id="episode_number" example="1">%1$s</xliff:g></string>
+ <!-- The episode title format displayed on the info banner. For example, "S1: Ep. 1 Winter is coming". -->
+ <string name="display_episode_title_format">S<xliff:g id="season_number" example="1">%1$s</xliff:g>: Ep. <xliff:g id="episode_number" example="1">%2$s</xliff:g> <xliff:g id="episode_title" example="Winter is Coming">%3$s</xliff:g></string>
+ <!-- The episode title format displayed on the info banner when the season number is not available. For example, "Ep. 1807 Headline News". -->
+ <string name="display_episode_title_format_no_season_number">Ep. <xliff:g id="episode_number" example="1807">%1$s</xliff:g> <xliff:g id="episode_title" example="Headline News">%2$s</xliff:g></string>
+ <!-- Program title with season and episode number used in DVR card views. -->
+ <string name="program_title_with_episode_number"><xliff:g id="programName" example="Big bang theory">%1$s</xliff:g> S<xliff:g id="seasonNumber" example="1">%2$s</xliff:g>: Ep. <xliff:g id="episodeNumber" example="12">%3$s</xliff:g></string>
+ <!-- Program title with episode number used in DVR card views. -->
+ <string name="program_title_with_episode_number_no_season"><xliff:g id="programName" example="Big bang theory">%1$s</xliff:g> Ep. <xliff:g id="episodeNumber" example="12">%2$s</xliff:g></string>
</resources>
diff --git a/common/src/com/android/tv/common/CollectionUtils.java b/common/src/com/android/tv/common/CollectionUtils.java
index f81e51a5..300ad8f2 100644
--- a/common/src/com/android/tv/common/CollectionUtils.java
+++ b/common/src/com/android/tv/common/CollectionUtils.java
@@ -16,7 +16,12 @@
package com.android.tv.common;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
/**
* Static utilities for collections
@@ -42,4 +47,55 @@ public class CollectionUtils {
}
return result;
}
+
+ /**
+ * Unions the two collections and returns the unified list.
+ * <p>
+ * The elements is not compared with hashcode() or equals(). Comparator is used for the equality
+ * check.
+ */
+ public static <T> List<T> union(Collection<T> originals, Collection<T> toAdds,
+ Comparator<T> comparator) {
+ List<T> result = new ArrayList<>(originals);
+ Collections.sort(result, comparator);
+ List<T> resultToAdd = new ArrayList<>();
+ for (T toAdd : toAdds) {
+ if (Collections.binarySearch(result, toAdd, comparator) < 0) {
+ resultToAdd.add(toAdd);
+ }
+ }
+ result.addAll(resultToAdd);
+ return result;
+ }
+
+ /**
+ * Subtracts the elements from the original collection.
+ */
+ public static <T> List<T> subtract(Collection<T> originals, T[] toSubtracts,
+ Comparator<T> comparator) {
+ List<T> result = new ArrayList<>(originals);
+ Collections.sort(result, comparator);
+ for (T toSubtract : toSubtracts) {
+ int index = Collections.binarySearch(result, toSubtract, comparator);
+ if (index >= 0) {
+ result.remove(index);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Returns {@code true} if the two specified collections have common elements.
+ */
+ public static <T> boolean containsAny(Collection<T> c1, Collection<T> c2,
+ Comparator<T> comparator) {
+ List<T> contains = new ArrayList<>(c1);
+ Collections.sort(contains, comparator);
+ for (T iterate : c2) {
+ if (Collections.binarySearch(contains, iterate, comparator) >= 0) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/common/src/com/android/tv/common/SharedPreferencesUtils.java b/common/src/com/android/tv/common/SharedPreferencesUtils.java
index 38daa963..fb3d9b56 100644
--- a/common/src/com/android/tv/common/SharedPreferencesUtils.java
+++ b/common/src/com/android/tv/common/SharedPreferencesUtils.java
@@ -28,9 +28,13 @@ public final class SharedPreferencesUtils {
public static final String SHARED_PREF_FEATURES = "sharePreferencesFeatures";
public static final String SHARED_PREF_BROWSABLE = "browsable_shared_preference";
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_RECURRING_RUNNER = "sharedPreferencesRecurringRunner";
+ public static final String SHARED_PREF_EPG = "epg_preferences";
+ public static final String SHARED_PREF_SERIES_RECORDINGS = "seriesRecordings";
private static boolean sInitializeCalled;
@@ -40,7 +44,7 @@ public final class SharedPreferencesUtils {
* Call {@link Context#getSharedPreferences(String, int)} as early as possible to avoid the ANR
* due to the file loading.
*/
- public static synchronized void initialize(final Context context) {
+ public static synchronized void initialize(final Context context, final Runnable postTask) {
if (!sInitializeCalled) {
sInitializeCalled = true;
new AsyncTask<Void, Void, Void>() {
@@ -50,12 +54,22 @@ public final class SharedPreferencesUtils {
context.getSharedPreferences(SHARED_PREF_FEATURES, Context.MODE_PRIVATE);
context.getSharedPreferences(SHARED_PREF_BROWSABLE, Context.MODE_PRIVATE);
context.getSharedPreferences(SHARED_PREF_WATCHED_HISTORY, Context.MODE_PRIVATE);
+ context.getSharedPreferences(SHARED_PREF_DVR_WATCHED_POSITION,
+ Context.MODE_PRIVATE);
context.getSharedPreferences(SHARED_PREF_AUDIO_CAPABILITIES,
Context.MODE_PRIVATE);
context.getSharedPreferences(SHARED_PREF_RECURRING_RUNNER,
Context.MODE_PRIVATE);
+ context.getSharedPreferences(SHARED_PREF_EPG, Context.MODE_PRIVATE);
+ context.getSharedPreferences(SHARED_PREF_SERIES_RECORDINGS,
+ Context.MODE_PRIVATE);
return null;
}
+
+ @Override
+ protected void onPostExecute(Void result) {
+ postTask.run();
+ }
}.execute();
}
}
diff --git a/common/src/com/android/tv/common/SoftPreconditions.java b/common/src/com/android/tv/common/SoftPreconditions.java
index 9b7713f6..823c42ff 100644
--- a/common/src/com/android/tv/common/SoftPreconditions.java
+++ b/common/src/com/android/tv/common/SoftPreconditions.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.BuildConfig;
import com.android.tv.common.feature.Feature;
/**
@@ -43,12 +42,14 @@ public final class SoftPreconditions {
* @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.
+ * @return the evaluation result of the boolean expression
* @throws IllegalArgumentException if {@code expression} is true
*/
- public static void checkArgument(final boolean expression, String tag, String msg) {
+ public static boolean checkArgument(final boolean expression, String tag, String msg) {
if (!expression) {
warn(tag, "Illegal argument", msg, new IllegalArgumentException(msg));
}
+ return expression;
}
/**
@@ -56,10 +57,12 @@ public final class SoftPreconditions {
* method is not true.
*
* @param expression a boolean expression
+ * @return the evaluation result of the boolean expression
* @throws IllegalArgumentException if {@code expression} is true
*/
- public static void checkArgument(final boolean expression) {
+ public static boolean checkArgument(final boolean expression) {
checkArgument(expression, null, null);
+ return expression;
}
/**
@@ -98,12 +101,14 @@ public final class SoftPreconditions {
* @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.
+ * @return the evaluation result of the boolean expression
* @throws IllegalStateException if {@code expression} is true
*/
- public static void checkState(final boolean expression, String tag, String msg) {
+ public static boolean checkState(final boolean expression, String tag, String msg) {
if (!expression) {
warn(tag, "Illegal State", msg, new IllegalStateException(msg));
}
+ return expression;
}
/**
@@ -111,10 +116,12 @@ public final class SoftPreconditions {
* instance, but not involving any parameters to the calling method is not true.
*
* @param expression a boolean expression
+ * @return the evaluation result of the boolean expression
* @throws IllegalStateException if {@code expression} is true
*/
- public static void checkState(final boolean expression) {
+ public static boolean checkState(final boolean expression) {
checkState(expression, null, null);
+ return expression;
}
/**
diff --git a/common/src/com/android/tv/common/TvContentRatingCache.java b/common/src/com/android/tv/common/TvContentRatingCache.java
index 7ea86287..5694cda7 100644
--- a/common/src/com/android/tv/common/TvContentRatingCache.java
+++ b/common/src/com/android/tv/common/TvContentRatingCache.java
@@ -39,7 +39,7 @@ public final class TvContentRatingCache implements MemoryManageable {
private final static TvContentRatingCache INSTANCE = new TvContentRatingCache();
- public final static TvContentRatingCache getInstance() {
+ public static TvContentRatingCache getInstance() {
return INSTANCE;
}
diff --git a/common/src/com/android/tv/common/feature/CommonFeatures.java b/common/src/com/android/tv/common/feature/CommonFeatures.java
index 9925833f..d47aa603 100644
--- a/common/src/com/android/tv/common/feature/CommonFeatures.java
+++ b/common/src/com/android/tv/common/feature/CommonFeatures.java
@@ -16,7 +16,7 @@
package com.android.tv.common.feature;
-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.OR;
import static com.android.tv.common.feature.TestableFeature.createTestableFeature;
@@ -30,14 +30,26 @@ public class CommonFeatures {
* DVR
*
* <p>See <a href="https://goto.google.com/atv-dvr-onepager">go/atv-dvr-onepager</a>
+ *
+ * DVR API is introduced in N, it only works when app runs as a system app.
+ */
+ public static final TestableFeature DVR = createTestableFeature(
+ AND(OR(Sdk.N_PRE_2_OR_HIGHER, Sdk.AT_LEAST_N), SystemAppFeature.SYSTEM_APP_FEATURE));
+
+ /**
+ * ENABLE_RECORDING_REGARDLESS_OF_STORAGE_STATUS
+ *
+ * Enables dvr recording regardless of storage status.
*/
- public static TestableFeature DVR = createTestableFeature(
- OR(ENG_ONLY_FEATURE, Sdk.N_PRE_2_OR_HIGHER));
+ public static final Feature FORCE_RECORDING_UNTIL_NO_SPACE =
+ new PropertyFeature("force_recording_until_no_space", false);
/**
* USE_SW_CODEC_FOR_SD
*
* Prefer software based codec for SD channels.
*/
- public static Feature USE_SW_CODEC_FOR_SD = new PropertyFeature("use_sw_codec_for_sd", true);
+ 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/EngOnlyFeature.java b/common/src/com/android/tv/common/feature/EngOnlyFeature.java
index 14d2b49b..9fc39d9f 100644
--- a/common/src/com/android/tv/common/feature/EngOnlyFeature.java
+++ b/common/src/com/android/tv/common/feature/EngOnlyFeature.java
@@ -24,7 +24,7 @@ import com.android.tv.common.BuildConfig;
* A feature that is only available on {@link BuildConfig#ENG} builds.
*/
public final class EngOnlyFeature implements Feature {
- public static Feature ENG_ONLY_FEATURE = new EngOnlyFeature();
+ public static final Feature ENG_ONLY_FEATURE = new EngOnlyFeature();
private EngOnlyFeature() { }
diff --git a/common/src/com/android/tv/common/feature/Sdk.java b/common/src/com/android/tv/common/feature/Sdk.java
index 268eaea7..46a681f8 100644
--- a/common/src/com/android/tv/common/feature/Sdk.java
+++ b/common/src/com/android/tv/common/feature/Sdk.java
@@ -25,7 +25,7 @@ import android.support.v4.os.BuildCompat;
*/
public class Sdk {
- public static Feature N_PRE_2_OR_HIGHER =
+ public static final Feature N_PRE_2_OR_HIGHER =
new SdkPreviewVersionFeature(Build.VERSION_CODES.M, 2, true);
private static class SdkPreviewVersionFeature implements Feature {
@@ -56,7 +56,7 @@ public class Sdk {
}
}
- public static Feature AT_LEAST_N = new Feature() {
+ public static final Feature AT_LEAST_N = new Feature() {
@Override
public boolean isEnabled(Context context) {
return BuildCompat.isAtLeastN();
diff --git a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
index 4d3a70a8..a4a79b38 100644
--- a/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
+++ b/common/src/com/android/tv/common/feature/SharedPreferencesFeature.java
@@ -29,9 +29,9 @@ public final class SharedPreferencesFeature implements Feature {
private static final String TAG = "SharedPrefFeature";
private static final boolean DEBUG = false;
- private String mKey;
+ private final String mKey;
private boolean mEnabled;
- private boolean mDefaultValue;
+ private final boolean mDefaultValue;
private SharedPreferences mSharedPreferences;
private final Feature mBaseFeature;
diff --git a/common/src/com/android/tv/common/feature/SystemAppFeature.java b/common/src/com/android/tv/common/feature/SystemAppFeature.java
new file mode 100644
index 00000000..79fd32f3
--- /dev/null
+++ b/common/src/com/android/tv/common/feature/SystemAppFeature.java
@@ -0,0 +1,34 @@
+/*
+ * 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.feature;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+
+/**
+ * A feature that is for system App.
+ */
+public final class SystemAppFeature implements Feature {
+ public static final Feature SYSTEM_APP_FEATURE = new SystemAppFeature();
+
+ private SystemAppFeature() { }
+
+ @Override
+ public boolean isEnabled(Context context) {
+ return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+}
diff --git a/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java
index 15b38f02..392d489f 100644
--- a/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java
+++ b/common/src/com/android/tv/common/ui/setup/OnActionClickListener.java
@@ -16,15 +16,20 @@
package com.android.tv.common.ui.setup;
+import android.os.Bundle;
+
/**
* A listener for the action click.
*/
public interface OnActionClickListener {
/**
* Called when the action is clicked.
+ * <p>
+ * The method should return {@code true} if the action is handled, otherwise {@code false}.
*
- * @param category action category.
- * @param id action id.
+ * @param category The action category.
+ * @param id The action id.
+ * @param params The parameter for the action.
*/
- void onActionClick(String category, int id);
+ boolean onActionClick(String category, int id, Bundle params);
}
diff --git a/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java
index 0f44ce06..7ee06faf 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupActionHelper.java
@@ -17,6 +17,8 @@
package com.android.tv.common.ui.setup;
import android.app.Fragment;
+import android.os.Bundle;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
@@ -24,47 +26,60 @@ import android.view.View.OnClickListener;
* Helper class for the execution in the fragment.
*/
public class SetupActionHelper {
+ private static final String TAG = "SetupActionHelper";
+
/**
- * Executes the action of the given {@code actionId}.
+ * Executes the action.
*/
- public static void onActionClick(Fragment fragment, String category, int actionId) {
- OnActionClickListener listener = null;
- if (fragment instanceof SetupFragment) {
- listener = ((SetupFragment) fragment).getOnActionClickListener();
- }
- if (listener == null && fragment.getActivity() instanceof OnActionClickListener) {
- listener = (OnActionClickListener) fragment.getActivity();
- }
- if (listener != null) {
- listener.onActionClick(category, actionId);
+ public static boolean onActionClick(Fragment fragment, String category, int actionId) {
+ return onActionClick(fragment, category, actionId, null);
+ }
+
+ /**
+ * Executes the action.
+ */
+ public static boolean onActionClick(Fragment fragment, String category, int actionId,
+ Bundle params) {
+ if (fragment.getActivity() instanceof OnActionClickListener) {
+ return ((OnActionClickListener) fragment.getActivity()).onActionClick(category,
+ actionId, params);
}
+ Log.e(TAG, "Activity can't handle the action: {category=" + category + ", actionId="
+ + actionId + ", params=" + params + "}");
+ return false;
}
/**
* Creates an {@link OnClickListener} to handle the action.
*/
- public static OnClickListener createOnClickListenerForAction(OnActionClickListener listener,
- String category, int actionId) {
- return new OnActionClickListenerForAction(listener, category, actionId);
+ public static OnClickListener createOnClickListenerForAction(Fragment fragment, String category,
+ int actionId, Bundle params) {
+ return new OnActionClickListenerForAction(fragment, category, actionId, params);
}
+ /**
+ * The {@link OnClickListener} for the view.
+ * <p>
+ * Note that this class should be used only for the views in the {@code mFragment} to avoid the
+ * leak of mFragment.
+ */
private static class OnActionClickListenerForAction implements OnClickListener {
- private final OnActionClickListener mListener;
+ private final Fragment mFragment;
private final String mCategory;
private final int mActionId;
+ private final Bundle mParams;
- OnActionClickListenerForAction(OnActionClickListener listener, String category,
- int actionId) {
- mListener = listener;
+ OnActionClickListenerForAction(Fragment fragment, String category, int actionId,
+ Bundle params) {
+ mFragment = fragment;
mCategory = category;
mActionId = actionId;
+ mParams = params;
}
@Override
public void onClick(View v) {
- if (mListener != null) {
- mListener.onActionClick(mCategory, mActionId);
- }
+ SetupActionHelper.onActionClick(mFragment, mCategory, mActionId, mParams);
}
}
diff --git a/common/src/com/android/tv/common/ui/setup/SetupActivity.java b/common/src/com/android/tv/common/ui/setup/SetupActivity.java
index 8c7b1b8e..2b381a6e 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupActivity.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupActivity.java
@@ -49,6 +49,7 @@ public abstract class SetupActivity extends Activity implements OnActionClickLis
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ SetupAnimationHelper.initialize(this);
setContentView(R.layout.activity_setup);
mFragmentTransitionDuration = getResources().getInteger(
R.integer.setup_fragment_transition_duration);
@@ -129,19 +130,26 @@ public abstract class SetupActivity extends Activity implements OnActionClickLis
}
@Override
- public void onActionClick(String category, int actionId) {
+ public boolean onActionClick(String category, int actionId, Bundle params) {
if (mHandler.hasMessages(MSG_EXECUTE_ACTION)) {
- return;
+ return false;
}
- executeAction(category, actionId);
+ return executeAction(category, actionId, params);
}
protected void executeActionWithDelay(Runnable action, int delayMs) {
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_EXECUTE_ACTION, action), delayMs);
}
- // Override this method if the inherited class wants to handle the action.
- protected void executeAction(String category, int actionId) { }
+ /**
+ * Override this method if the inherited class wants to handle the action.
+ * <p>
+ * The override method should return {@code true} if the action is handled, otherwise
+ * {@code false}.
+ */
+ protected boolean executeAction(String category, int actionId, Bundle params) {
+ return false;
+ }
/**
* Returns the duration of the shared element transition.
diff --git a/common/src/com/android/tv/common/ui/setup/SetupFragment.java b/common/src/com/android/tv/common/ui/setup/SetupFragment.java
index df7256d3..d2b9d7c8 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupFragment.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupFragment.java
@@ -47,11 +47,9 @@ public abstract class SetupFragment extends Fragment {
public static final int FRAGMENT_REENTER_TRANSITION = FRAGMENT_ENTER_TRANSITION << 2;
public static final int FRAGMENT_RETURN_TRANSITION = FRAGMENT_ENTER_TRANSITION << 3;
- private OnActionClickListener mOnActionClickListener;
-
private boolean mEnterTransitionRunning;
- private TransitionListener mTransitionListener = new TransitionListener() {
+ private final TransitionListener mTransitionListener = new TransitionListener() {
@Override
public void onTransitionStart(Transition transition) {
mEnterTransitionRunning = true;
@@ -103,20 +101,6 @@ public abstract class SetupFragment extends Fragment {
}
/**
- * Returns action click listener.
- */
- public OnActionClickListener getOnActionClickListener() {
- return mOnActionClickListener;
- }
-
- /**
- * Sets action click listener.
- */
- public void setOnActionClickListener(OnActionClickListener onActionClickListener) {
- mOnActionClickListener = onActionClickListener;
- }
-
- /**
* Returns the layout resource ID for this fragment.
*/
abstract protected int getLayoutResourceId();
@@ -130,8 +114,12 @@ public abstract class SetupFragment extends Fragment {
});
}
- protected void onActionClick(String category, int actionId) {
- SetupActionHelper.onActionClick(this, category, actionId);
+ protected boolean onActionClick(String category, int actionId) {
+ return SetupActionHelper.onActionClick(this, category, actionId);
+ }
+
+ protected boolean onActionClick(String category, int actionId, Bundle params) {
+ return SetupActionHelper.onActionClick(this, category, actionId, params);
}
@Override
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 aa912a97..bcaefec9 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupGuidedStepFragment.java
@@ -57,9 +57,7 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
R.dimen.setup_done_button_container_width);
// Guided actions list
View list = view.findViewById(R.id.guidedactions_list);
- View list2 = view.findViewById(R.id.guidedactions_list2);
- MarginLayoutParams marginLayoutParams = (MarginLayoutParams) view.findViewById(
- R.id.guidedactions_list).getLayoutParams();
+ MarginLayoutParams marginLayoutParams = (MarginLayoutParams) list.getLayoutParams();
// Use content view to check layout direction while view is being created.
if (getResources().getConfiguration().getLayoutDirection()
== View.LAYOUT_DIRECTION_LTR) {
@@ -74,6 +72,9 @@ public abstract class SetupGuidedStepFragment extends GuidedStepFragment {
}
// gridView Alignment
VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView();
+ // Workaround of b/28274171
+ // TODO: Remove the following line once b/28274171 is resolved.
+ gridView.setFocusable(true);
int offset = getResources().getDimensionPixelOffset(
R.dimen.setup_guidedactions_selector_margin_top);
gridView.setWindowAlignmentOffset(offset);
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 fea9bf4a..63247481 100644
--- a/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java
+++ b/common/src/com/android/tv/common/ui/setup/SetupMultiPaneFragment.java
@@ -17,6 +17,8 @@
package com.android.tv.common.ui.setup;
import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -28,15 +30,27 @@ import com.android.tv.common.R;
* A fragment for channel source info/setup.
*/
public abstract class SetupMultiPaneFragment extends SetupFragment {
+ private static final String TAG = "SetupMultiPaneFragment";
+ private static final boolean DEBUG = false;
+
public static final int ACTION_DONE = Integer.MAX_VALUE;
+ private static final String CONTENT_FRAGMENT_TAG = "content_fragment";
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
+ if (DEBUG) {
+ Log.d(TAG, "onCreateView(" + inflater + ", " + container + ", " + savedInstanceState
+ + ")");
+ }
View view = super.onCreateView(inflater, container, savedInstanceState);
- SetupGuidedStepFragment contentFragment = onCreateContentFragment();
- getChildFragmentManager().beginTransaction()
- .replace(R.id.guided_step_fragment_container, contentFragment).commit();
+ if (savedInstanceState == null) {
+ SetupGuidedStepFragment contentFragment = onCreateContentFragment();
+ getChildFragmentManager().beginTransaction()
+ .replace(R.id.guided_step_fragment_container, contentFragment,
+ CONTENT_FRAGMENT_TAG).commit();
+ }
if (needsDoneButton()) {
setOnClickAction(view.findViewById(R.id.button_done), getActionCategory(), ACTION_DONE);
} else {
@@ -64,6 +78,12 @@ public abstract class SetupMultiPaneFragment extends SetupFragment {
abstract protected SetupGuidedStepFragment onCreateContentFragment();
+ @Nullable
+ protected SetupGuidedStepFragment getContentFragment() {
+ return (SetupGuidedStepFragment) getChildFragmentManager()
+ .findFragmentByTag(CONTENT_FRAGMENT_TAG);
+ }
+
abstract protected String getActionCategory();
protected boolean needsDoneButton() {
diff --git a/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java b/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java
index 5c57d84d..e1a8e60c 100644
--- a/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java
+++ b/common/src/com/android/tv/common/ui/setup/animation/FadeAndShortSlide.java
@@ -90,7 +90,7 @@ public class FadeAndShortSlide extends Visibility {
private Visibility mFade = new Fade();
// TODO: Consider using TransitionPropagation.
- private int[] mParentIdsForDelay;
+ private final int[] mParentIdsForDelay;
private int mDistance = DEFAULT_DISTANCE;
public FadeAndShortSlide() {
diff --git a/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java b/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java
index 0c5849ea..d98138a2 100644
--- a/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java
+++ b/common/src/com/android/tv/common/ui/setup/animation/SetupAnimationHelper.java
@@ -49,6 +49,9 @@ public final class SetupAnimationHelper {
* Load initial parameters. This method should be called before using this class.
*/
public static void initialize(Context context) {
+ if (sInitialized) {
+ return;
+ }
sFragmentTransitionDuration = context.getResources()
.getInteger(R.integer.setup_fragment_transition_duration);
sFragmentTransitionLongDistance = context.getResources()
@@ -66,7 +69,7 @@ public final class SetupAnimationHelper {
public static class TransitionBuilder {
private int mSlideEdge = Gravity.START;
- private int mDistance = sFragmentTransitionLongDistance;
+ private final int mDistance = sFragmentTransitionLongDistance;
private long mDuration = sFragmentTransitionDuration;
private int[] mParentIdForDelay;
private int[] mExcludeIds;
diff --git a/usbtuner/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
index b12b9260..b12b9260 100644
--- a/usbtuner/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
diff --git a/usbtuner/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
index e799ea14..e799ea14 100644
--- a/usbtuner/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
diff --git a/usbtuner/jni/Android.mk b/jni/Android.mk
index 684830c9..684830c9 100644
--- a/usbtuner/jni/Android.mk
+++ b/jni/Android.mk
diff --git a/usbtuner/jni/DvbManager.cpp b/jni/DvbManager.cpp
index fef756e3..aa4ed530 100644
--- a/usbtuner/jni/DvbManager.cpp
+++ b/jni/DvbManager.cpp
@@ -42,9 +42,10 @@ DvbManager::DvbManager(JNIEnv *env, jobject)
mDemuxFd(-1),
mDvrFd(-1),
mPatFilterFd(-1),
- mFeHasLock(false) {
+ mFeHasLock(false),
+ mHasPendingTune(false) {
jclass clazz = env->FindClass(
- "com/android/usbtuner/TunerHal");
+ "com/android/tv/tuner/TunerHal");
mOpenDvbFrontEndMethodID = env->GetMethodID(
clazz, "openDvbFrontEndFd", "()I");
mOpenDvbDemuxMethodID = env->GetMethodID(
@@ -58,10 +59,17 @@ DvbManager::~DvbManager() {
}
bool DvbManager::isFeLocked() {
- struct dvb_frontend_event kevent;
- memset(&kevent, 0, sizeof(kevent));
- if (ioctl(mFeFd, FE_READ_STATUS, &kevent.status) == 0) {
- return (kevent.status & FE_HAS_LOCK);
+ struct pollfd pollFd;
+ pollFd.fd = mFeFd;
+ pollFd.events = POLLIN;
+ pollFd.revents = 0;
+ int poll_result = poll(&pollFd, NUM_POLLFDS, FE_POLL_TIMEOUT_MS);
+ if (poll_result > 0 && (pollFd.revents & POLLIN)) {
+ struct dvb_frontend_event kevent;
+ memset(&kevent, 0, sizeof(kevent));
+ if (ioctl(mFeFd, FE_GET_EVENT, &kevent) == 0) {
+ return (kevent.status & FE_HAS_LOCK);
+ }
}
return false;
}
@@ -82,6 +90,9 @@ int DvbManager::tune(JNIEnv *env, jobject thiz,
return -1;
}
+ if (mHasPendingTune) {
+ return -1;
+ }
if (openDvbFe(env, thiz) != 0) {
return -1;
}
@@ -104,8 +115,12 @@ int DvbManager::tune(JNIEnv *env, jobject thiz,
int lockSuccessCount = 0;
double tuneClock = currentTimeMillis();
while (currentTimeMillis() - tuneClock < timeout_ms) {
- usleep(FE_LOCK_CHECK_INTERNAL_US);
-
+ if (mHasPendingTune) {
+ // Return 0 here since we already call FE_SET_FRONTEND, and return due to having pending
+ // tune request. And the frontend setting could be successful.
+ mFeHasLock = true;
+ return 0;
+ }
bool lockStatus = isFeLocked();
if (lockStatus) {
lockSuccessCount++;
@@ -186,6 +201,10 @@ int DvbManager::startTsPidFilter(JNIEnv *env, jobject thiz, int pid, int filterT
return 0;
}
+ if (mHasPendingTune) {
+ return -1;
+ }
+
int demuxFd;
if ((demuxFd = openDvbDemuxFromSystemApi(env, thiz)) < 0) {
ALOGD("Can't open DEMUX file : %s", strerror(errno));
@@ -237,6 +256,8 @@ void DvbManager::closeAllDvbPidFilter() {
close(it->second);
}
mPidFilters.clear();
+ // Close mDvrFd to make sure there is not buffer from previous channel left.
+ closeDvbDvr();
}
void DvbManager::closePatFilter() {
@@ -312,3 +333,7 @@ int DvbManager::readTsStream(JNIEnv *env, jobject thiz,
}
return read(mDvrFd, tsBuffer, tsBufferSize);
}
+
+void DvbManager::setHasPendingTune(bool hasPendingTune) {
+ mHasPendingTune = hasPendingTune;
+}
diff --git a/usbtuner/jni/DvbManager.h b/jni/DvbManager.h
index c626335a..7475bd41 100644
--- a/usbtuner/jni/DvbManager.h
+++ b/jni/DvbManager.h
@@ -29,22 +29,25 @@ class DvbManager {
static const int FE_CONSECUTIVE_LOCK_SUCCESS_COUNT = 1;
static const int DVB_ERROR_RETRY_INTERVAL_MS = 100 * 1000;
static const int DVB_TUNE_STOP_DELAY_MS = 100 * 1000;
+ static const int FE_POLL_TIMEOUT_MS = 100;
static const int PAT_PID = 0;
static const int FILTER_TYPE_OTHER =
- com_android_usbtuner_TunerHal_FILTER_TYPE_OTHER;
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER;
static const int FILTER_TYPE_AUDIO =
- com_android_usbtuner_TunerHal_FILTER_TYPE_AUDIO;
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO;
static const int FILTER_TYPE_VIDEO =
- com_android_usbtuner_TunerHal_FILTER_TYPE_VIDEO;
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO;
static const int FILTER_TYPE_PCR =
- com_android_usbtuner_TunerHal_FILTER_TYPE_PCR;
+ com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR;
int mFeFd;
int mDemuxFd;
int mDvrFd;
int mPatFilterFd;
bool mFeHasLock;
+ // Flag for pending tune request. Used for canceling the current tune operation.
+ bool volatile mHasPendingTune;
std::map<int, int> mPidFilters;
Mutex mFilterLock;
jmethodID mOpenDvbFrontEndMethodID;
@@ -61,6 +64,7 @@ public:
uint8_t *tsBuffer, int tsBufferSize, int timeout_ms);
int startTsPidFilter(JNIEnv *env, jobject thiz, int pid, int filterType);
void closeAllDvbPidFilter();
+ void setHasPendingTune(bool hasPendingTune);
private:
int openDvbFe(JNIEnv *env, jobject thiz);
diff --git a/jni/gen_jni.sh b/jni/gen_jni.sh
new file mode 100755
index 00000000..aa52b248
--- /dev/null
+++ b/jni/gen_jni.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+javah -jni -classpath ../../bin/classes:../../../../../../prebuilts/sdk/current/android.jar -o tunertvinput_jni.h com.android.tv.tuner.TunerHal
diff --git a/usbtuner/jni/logging.h b/jni/logging.h
index af90961c..af90961c 100644
--- a/usbtuner/jni/logging.h
+++ b/jni/logging.h
diff --git a/usbtuner/jni/mutex.h b/jni/mutex.h
index 90527ae4..90527ae4 100644
--- a/usbtuner/jni/mutex.h
+++ b/jni/mutex.h
diff --git a/usbtuner/jni/tunertvinput_jni.cpp b/jni/tunertvinput_jni.cpp
index b72afbdb..bcbc4c29 100644
--- a/usbtuner/jni/tunertvinput_jni.cpp
+++ b/jni/tunertvinput_jni.cpp
@@ -33,12 +33,12 @@ static int sTotalBytesFetched = 0;
static std::map<jlong, DvbManager *> sDvbManagers;
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeFinalize
* Signature: (J)V
*/
JNIEXPORT void JNICALL
-Java_com_android_usbtuner_TunerHal_nativeFinalize
+Java_com_android_tv_tuner_TunerHal_nativeFinalize
(JNIEnv *, jobject, jlong deviceId) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
@@ -48,12 +48,12 @@ Java_com_android_usbtuner_TunerHal_nativeFinalize
}
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeTune
* Signature: (JILjava/lang/String;)Z
*/
JNIEXPORT jboolean JNICALL
-Java_com_android_usbtuner_TunerHal_nativeTune
+Java_com_android_tv_tuner_TunerHal_nativeTune
(JNIEnv *env, jobject thiz, jlong deviceId, jint frequency, jstring modulation, jint timeout_ms) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
DvbManager *dvbManager;
@@ -69,11 +69,11 @@ Java_com_android_usbtuner_TunerHal_nativeTune
}
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeCloseAllPidFilters
* Signature: (J)V
*/
-JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeCloseAllPidFilters
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters
(JNIEnv *, jobject, jlong deviceId) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
@@ -82,12 +82,12 @@ JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeCloseAllPidFilte
}
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeStopTune
* Signature: (J)V
*/
JNIEXPORT void JNICALL
-Java_com_android_usbtuner_TunerHal_nativeStopTune
+Java_com_android_tv_tuner_TunerHal_nativeStopTune
(JNIEnv *, jobject, jlong deviceId) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
@@ -96,12 +96,12 @@ Java_com_android_usbtuner_TunerHal_nativeStopTune
}
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeAddPidFilter
* Signature: (JII)V
*/
JNIEXPORT void JNICALL
-Java_com_android_usbtuner_TunerHal_nativeAddPidFilter
+Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter
(JNIEnv *env, jobject thiz, jlong deviceId, jint pid, jint filterType) {
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
if (it != sDvbManagers.end()) {
@@ -110,12 +110,12 @@ Java_com_android_usbtuner_TunerHal_nativeAddPidFilter
}
/*
- * Class: com_android_usbtuner_TunerHal
+ * Class: com_android_tv_tuner_TunerHal
* Method: nativeWriteInBuffer
* Signature: (J[BI)I
*/
JNIEXPORT jint JNICALL
-Java_com_android_usbtuner_TunerHal_nativeWriteInBuffer
+Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer
(JNIEnv *env, jobject thiz, jlong deviceId, jbyteArray javaBuffer, jint javaBufferSize) {
uint8_t tsBuffer[TS_PAYLOAD_SIZE];
std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
@@ -141,3 +141,17 @@ Java_com_android_usbtuner_TunerHal_nativeWriteInBuffer
env->SetByteArrayRegion(javaBuffer, 0, dataSize, (jbyte *) tsBuffer);
return dataSize;
}
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeSetHasPendingTune
+ * Signature: (JZ)V
+ */
+JNIEXPORT void JNICALL
+Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune
+(JNIEnv *env, jobject thiz, jlong deviceId, jboolean hasPendingTune) {
+ std::map<jlong, DvbManager *>::iterator it = sDvbManagers.find(deviceId);
+ if (it != sDvbManagers.end()) {
+ it->second->setHasPendingTune(hasPendingTune);
+ }
+}
diff --git a/jni/tunertvinput_jni.h b/jni/tunertvinput_jni.h
new file mode 100644
index 00000000..4ade29e4
--- /dev/null
+++ b/jni/tunertvinput_jni.h
@@ -0,0 +1,98 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class com_android_tv_tuner_TunerHal */
+
+#ifndef _Included_com_android_tv_tuner_TunerHal
+#define _Included_com_android_tv_tuner_TunerHal
+#ifdef __cplusplus
+extern "C" {
+#endif
+#undef com_android_tv_tuner_TunerHal_DEBUG
+#define com_android_tv_tuner_TunerHal_DEBUG 0L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_OTHER 0L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_AUDIO 1L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_VIDEO 2L
+#undef com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR
+#define com_android_tv_tuner_TunerHal_FILTER_TYPE_PCR 3L
+#undef com_android_tv_tuner_TunerHal_PID_PAT
+#define com_android_tv_tuner_TunerHal_PID_PAT 0L
+#undef com_android_tv_tuner_TunerHal_PID_ATSC_SI_BASE
+#define com_android_tv_tuner_TunerHal_PID_ATSC_SI_BASE 8187L
+#undef com_android_tv_tuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS
+#define com_android_tv_tuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS 2000L
+#undef com_android_tv_tuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS
+#define com_android_tv_tuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS 4000L
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeFinalize
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeFinalize
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeTune
+ * Signature: (JILjava/lang/String;I)Z
+ */
+JNIEXPORT jboolean JNICALL Java_com_android_tv_tuner_TunerHal_nativeTune
+ (JNIEnv *, jobject, jlong, jint, jstring, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeAddPidFilter
+ * Signature: (JII)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeAddPidFilter
+ (JNIEnv *, jobject, jlong, jint, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeCloseAllPidFilters
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeCloseAllPidFilters
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeStopTune
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeStopTune
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeWriteInBuffer
+ * Signature: (J[BI)I
+ */
+JNIEXPORT jint JNICALL Java_com_android_tv_tuner_TunerHal_nativeWriteInBuffer
+ (JNIEnv *, jobject, jlong, jbyteArray, jint);
+
+/*
+ * Class: com_android_tv_tuner_TunerHal
+ * Method: nativeSetHasPendingTune
+ * Signature: (JZ)V
+ */
+JNIEXPORT void JNICALL Java_com_android_tv_tuner_TunerHal_nativeSetHasPendingTune
+ (JNIEnv *, jobject, jlong, jboolean);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+/* Header for class com_android_tv_tuner_TunerHal_FilterType */
+
+#ifndef _Included_com_android_tv_tuner_TunerHal_FilterType
+#define _Included_com_android_tv_tuner_TunerHal_FilterType
+#ifdef __cplusplus
+extern "C" {
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
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/proguard.flags b/proguard.flags
index 067ccca3..6ffed3e2 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -20,7 +20,7 @@
-dontwarn android.support.**
-dontwarn com.ibm.icu.**
-dontwarn com.google.android.exoplayer.**
--dontwarn com.android.usbtuner.**
+-dontwarn com.android.tv.tuner.**
-dontwarn com.android.tv.dvr.**
# This is due to legacy API katniss is referencing. Seems safe.
@@ -28,12 +28,12 @@
-dontwarn com.google.android.common.**
# Keep the methods called from native code.
--keepclasseswithmembers class com.android.usbtuner.TunerHal {
+-keepclasseswithmembers class com.android.tv.tuner.TunerHal {
int openDvbFrontEndFd();
int openDvbDemuxFd();
int openDvbDvrFd();
}
--keepclasseswithmembers class com.android.usbtuner.*DataSource {
+-keepclasseswithmembers class com.android.tv.tuner.*DataSource {
int readAt(long, byte[], int, int);
long getSize();
void close();
@@ -50,3 +50,6 @@
-keepclasseswithmembers class * {
@android.support.annotation.VisibleForTesting <methods>;
}
+
+# Grpc used by epg via reflection
+-keep class io.grpc.internal.DnsNameResolverProvider
diff --git a/usbtuner/proto/channel.proto b/proto/channel.proto
index cc78fcd5..982a1aa1 100644
--- a/usbtuner/proto/channel.proto
+++ b/proto/channel.proto
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
-option java_package = "com.android.usbtuner.data";
+option java_package = "com.android.tv.tuner.data";
option java_outer_classname = "Channel";
import "track.proto";
diff --git a/usbtuner/proto/track.proto b/proto/track.proto
index e0ede950..62b8f271 100644
--- a/usbtuner/proto/track.proto
+++ b/proto/track.proto
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
-option java_package = "com.android.usbtuner.data";
+option java_package = "com.android.tv.tuner.data";
option java_outer_classname = "Track";
// Represents a AC3 audio track.
diff --git a/res/drawable-nodpi/program_guide_table_item_background_focused.9.png b/res/drawable-nodpi/program_guide_table_item_background_focused.9.png
index 7c69c49e..2d9ec9d8 100644
--- a/res/drawable-nodpi/program_guide_table_item_background_focused.9.png
+++ b/res/drawable-nodpi/program_guide_table_item_background_focused.9.png
Binary files differ
diff --git a/res/drawable-nodpi/program_guide_table_item_background_focused_enabled.9.png b/res/drawable-nodpi/program_guide_table_item_background_focused_enabled.9.png
index bb3a4a8d..cf67cf1e 100644
--- a/res/drawable-nodpi/program_guide_table_item_background_focused_enabled.9.png
+++ b/res/drawable-nodpi/program_guide_table_item_background_focused_enabled.9.png
Binary files differ
diff --git a/res/drawable-nodpi/program_guide_table_item_background_normal.9.png b/res/drawable-nodpi/program_guide_table_item_background_normal.9.png
index 0aa70f9f..685b2c1f 100644
--- a/res/drawable-nodpi/program_guide_table_item_background_normal.9.png
+++ b/res/drawable-nodpi/program_guide_table_item_background_normal.9.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_00.png b/res/drawable-xhdpi/arrow_blue_00.png
index 96ea4bdc..46a1219d 100644
--- a/res/drawable-xhdpi/arrow_blue_00.png
+++ b/res/drawable-xhdpi/arrow_blue_00.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_01.png b/res/drawable-xhdpi/arrow_blue_01.png
index 36a3ec1f..e195f402 100644
--- a/res/drawable-xhdpi/arrow_blue_01.png
+++ b/res/drawable-xhdpi/arrow_blue_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_02.png b/res/drawable-xhdpi/arrow_blue_02.png
index bca40975..91421fc5 100644
--- a/res/drawable-xhdpi/arrow_blue_02.png
+++ b/res/drawable-xhdpi/arrow_blue_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_03.png b/res/drawable-xhdpi/arrow_blue_03.png
index 00f0e51f..076296c3 100644
--- a/res/drawable-xhdpi/arrow_blue_03.png
+++ b/res/drawable-xhdpi/arrow_blue_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_04.png b/res/drawable-xhdpi/arrow_blue_04.png
index 6848dcee..98b7c9c1 100644
--- a/res/drawable-xhdpi/arrow_blue_04.png
+++ b/res/drawable-xhdpi/arrow_blue_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_05.png b/res/drawable-xhdpi/arrow_blue_05.png
index 3afd0ce3..a2793026 100644
--- a/res/drawable-xhdpi/arrow_blue_05.png
+++ b/res/drawable-xhdpi/arrow_blue_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_06.png b/res/drawable-xhdpi/arrow_blue_06.png
index b805f3b6..fe47e124 100644
--- a/res/drawable-xhdpi/arrow_blue_06.png
+++ b/res/drawable-xhdpi/arrow_blue_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_07.png b/res/drawable-xhdpi/arrow_blue_07.png
index 53f25dd1..54443476 100644
--- a/res/drawable-xhdpi/arrow_blue_07.png
+++ b/res/drawable-xhdpi/arrow_blue_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_08.png b/res/drawable-xhdpi/arrow_blue_08.png
index ca4191d9..79645ad1 100644
--- a/res/drawable-xhdpi/arrow_blue_08.png
+++ b/res/drawable-xhdpi/arrow_blue_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_09.png b/res/drawable-xhdpi/arrow_blue_09.png
index adea3674..4ae12fe8 100644
--- a/res/drawable-xhdpi/arrow_blue_09.png
+++ b/res/drawable-xhdpi/arrow_blue_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_10.png b/res/drawable-xhdpi/arrow_blue_10.png
index 342f8a3c..6b44f5c6 100644
--- a/res/drawable-xhdpi/arrow_blue_10.png
+++ b/res/drawable-xhdpi/arrow_blue_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_11.png b/res/drawable-xhdpi/arrow_blue_11.png
index 7758e3fd..b5e9c41c 100644
--- a/res/drawable-xhdpi/arrow_blue_11.png
+++ b/res/drawable-xhdpi/arrow_blue_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_12.png b/res/drawable-xhdpi/arrow_blue_12.png
index be85b4d4..12e9d411 100644
--- a/res/drawable-xhdpi/arrow_blue_12.png
+++ b/res/drawable-xhdpi/arrow_blue_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_13.png b/res/drawable-xhdpi/arrow_blue_13.png
index 4327fdbb..162a6903 100644
--- a/res/drawable-xhdpi/arrow_blue_13.png
+++ b/res/drawable-xhdpi/arrow_blue_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_14.png b/res/drawable-xhdpi/arrow_blue_14.png
index 2a1f95ab..8ba300a9 100644
--- a/res/drawable-xhdpi/arrow_blue_14.png
+++ b/res/drawable-xhdpi/arrow_blue_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_15.png b/res/drawable-xhdpi/arrow_blue_15.png
index ac2efad9..2df2906f 100644
--- a/res/drawable-xhdpi/arrow_blue_15.png
+++ b/res/drawable-xhdpi/arrow_blue_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_16.png b/res/drawable-xhdpi/arrow_blue_16.png
index 2f005c21..e9f62aae 100644
--- a/res/drawable-xhdpi/arrow_blue_16.png
+++ b/res/drawable-xhdpi/arrow_blue_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_17.png b/res/drawable-xhdpi/arrow_blue_17.png
index 3ecf08b7..f107edc8 100644
--- a/res/drawable-xhdpi/arrow_blue_17.png
+++ b/res/drawable-xhdpi/arrow_blue_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_18.png b/res/drawable-xhdpi/arrow_blue_18.png
index 1a4e5efc..3323ae3e 100644
--- a/res/drawable-xhdpi/arrow_blue_18.png
+++ b/res/drawable-xhdpi/arrow_blue_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_19.png b/res/drawable-xhdpi/arrow_blue_19.png
index a6958061..705f7d60 100644
--- a/res/drawable-xhdpi/arrow_blue_19.png
+++ b/res/drawable-xhdpi/arrow_blue_19.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_20.png b/res/drawable-xhdpi/arrow_blue_20.png
index e5b90d5a..52c14617 100644
--- a/res/drawable-xhdpi/arrow_blue_20.png
+++ b/res/drawable-xhdpi/arrow_blue_20.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_21.png b/res/drawable-xhdpi/arrow_blue_21.png
index d78b8499..716854fb 100644
--- a/res/drawable-xhdpi/arrow_blue_21.png
+++ b/res/drawable-xhdpi/arrow_blue_21.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_22.png b/res/drawable-xhdpi/arrow_blue_22.png
index ad9ce088..a0917371 100644
--- a/res/drawable-xhdpi/arrow_blue_22.png
+++ b/res/drawable-xhdpi/arrow_blue_22.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_23.png b/res/drawable-xhdpi/arrow_blue_23.png
index ec1860fb..7a0319b6 100644
--- a/res/drawable-xhdpi/arrow_blue_23.png
+++ b/res/drawable-xhdpi/arrow_blue_23.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_24.png b/res/drawable-xhdpi/arrow_blue_24.png
index dcc24816..6de55ad2 100644
--- a/res/drawable-xhdpi/arrow_blue_24.png
+++ b/res/drawable-xhdpi/arrow_blue_24.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_25.png b/res/drawable-xhdpi/arrow_blue_25.png
index 8df34eaf..2e3e3e31 100644
--- a/res/drawable-xhdpi/arrow_blue_25.png
+++ b/res/drawable-xhdpi/arrow_blue_25.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_26.png b/res/drawable-xhdpi/arrow_blue_26.png
index 24cf731b..52e3b943 100644
--- a/res/drawable-xhdpi/arrow_blue_26.png
+++ b/res/drawable-xhdpi/arrow_blue_26.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_27.png b/res/drawable-xhdpi/arrow_blue_27.png
index 2ca7ecc1..80912bef 100644
--- a/res/drawable-xhdpi/arrow_blue_27.png
+++ b/res/drawable-xhdpi/arrow_blue_27.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_28.png b/res/drawable-xhdpi/arrow_blue_28.png
index 495a23d2..3ea1a7c3 100644
--- a/res/drawable-xhdpi/arrow_blue_28.png
+++ b/res/drawable-xhdpi/arrow_blue_28.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_29.png b/res/drawable-xhdpi/arrow_blue_29.png
index c4b5e05b..d36743e1 100644
--- a/res/drawable-xhdpi/arrow_blue_29.png
+++ b/res/drawable-xhdpi/arrow_blue_29.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_30.png b/res/drawable-xhdpi/arrow_blue_30.png
index 5615b355..666c6b32 100644
--- a/res/drawable-xhdpi/arrow_blue_30.png
+++ b/res/drawable-xhdpi/arrow_blue_30.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_31.png b/res/drawable-xhdpi/arrow_blue_31.png
index 16cc053b..88da80fd 100644
--- a/res/drawable-xhdpi/arrow_blue_31.png
+++ b/res/drawable-xhdpi/arrow_blue_31.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_32.png b/res/drawable-xhdpi/arrow_blue_32.png
index ec2df776..63f0d508 100644
--- a/res/drawable-xhdpi/arrow_blue_32.png
+++ b/res/drawable-xhdpi/arrow_blue_32.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_33.png b/res/drawable-xhdpi/arrow_blue_33.png
index 34cdd2b1..607ed35b 100644
--- a/res/drawable-xhdpi/arrow_blue_33.png
+++ b/res/drawable-xhdpi/arrow_blue_33.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_34.png b/res/drawable-xhdpi/arrow_blue_34.png
index 1295daa0..92e7132a 100644
--- a/res/drawable-xhdpi/arrow_blue_34.png
+++ b/res/drawable-xhdpi/arrow_blue_34.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_35.png b/res/drawable-xhdpi/arrow_blue_35.png
index 627f2326..c76f825a 100644
--- a/res/drawable-xhdpi/arrow_blue_35.png
+++ b/res/drawable-xhdpi/arrow_blue_35.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_36.png b/res/drawable-xhdpi/arrow_blue_36.png
index 2153aeab..02740270 100644
--- a/res/drawable-xhdpi/arrow_blue_36.png
+++ b/res/drawable-xhdpi/arrow_blue_36.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_37.png b/res/drawable-xhdpi/arrow_blue_37.png
index 2b3c3066..492df97b 100644
--- a/res/drawable-xhdpi/arrow_blue_37.png
+++ b/res/drawable-xhdpi/arrow_blue_37.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_38.png b/res/drawable-xhdpi/arrow_blue_38.png
index 602accf5..733e547a 100644
--- a/res/drawable-xhdpi/arrow_blue_38.png
+++ b/res/drawable-xhdpi/arrow_blue_38.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_39.png b/res/drawable-xhdpi/arrow_blue_39.png
index d50eda53..6b39cb08 100644
--- a/res/drawable-xhdpi/arrow_blue_39.png
+++ b/res/drawable-xhdpi/arrow_blue_39.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_40.png b/res/drawable-xhdpi/arrow_blue_40.png
index c4467985..35716982 100644
--- a/res/drawable-xhdpi/arrow_blue_40.png
+++ b/res/drawable-xhdpi/arrow_blue_40.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_41.png b/res/drawable-xhdpi/arrow_blue_41.png
index 8095770a..a7013437 100644
--- a/res/drawable-xhdpi/arrow_blue_41.png
+++ b/res/drawable-xhdpi/arrow_blue_41.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_42.png b/res/drawable-xhdpi/arrow_blue_42.png
index 6ea5f257..3cf53241 100644
--- a/res/drawable-xhdpi/arrow_blue_42.png
+++ b/res/drawable-xhdpi/arrow_blue_42.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_43.png b/res/drawable-xhdpi/arrow_blue_43.png
index 085e588c..5e338758 100644
--- a/res/drawable-xhdpi/arrow_blue_43.png
+++ b/res/drawable-xhdpi/arrow_blue_43.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_44.png b/res/drawable-xhdpi/arrow_blue_44.png
index 1d6f9ebd..75ca12b2 100644
--- a/res/drawable-xhdpi/arrow_blue_44.png
+++ b/res/drawable-xhdpi/arrow_blue_44.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_45.png b/res/drawable-xhdpi/arrow_blue_45.png
index 19f40c2a..f48e275e 100644
--- a/res/drawable-xhdpi/arrow_blue_45.png
+++ b/res/drawable-xhdpi/arrow_blue_45.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_46.png b/res/drawable-xhdpi/arrow_blue_46.png
index 21c40cd2..27beb9bc 100644
--- a/res/drawable-xhdpi/arrow_blue_46.png
+++ b/res/drawable-xhdpi/arrow_blue_46.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_47.png b/res/drawable-xhdpi/arrow_blue_47.png
index 0e17879d..972f70dc 100644
--- a/res/drawable-xhdpi/arrow_blue_47.png
+++ b/res/drawable-xhdpi/arrow_blue_47.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_48.png b/res/drawable-xhdpi/arrow_blue_48.png
index e09a6ea1..ee67d479 100644
--- a/res/drawable-xhdpi/arrow_blue_48.png
+++ b/res/drawable-xhdpi/arrow_blue_48.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_49.png b/res/drawable-xhdpi/arrow_blue_49.png
index cd62e76c..2a2f909f 100644
--- a/res/drawable-xhdpi/arrow_blue_49.png
+++ b/res/drawable-xhdpi/arrow_blue_49.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_50.png b/res/drawable-xhdpi/arrow_blue_50.png
index 369bc2e5..2d0e85cf 100644
--- a/res/drawable-xhdpi/arrow_blue_50.png
+++ b/res/drawable-xhdpi/arrow_blue_50.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_51.png b/res/drawable-xhdpi/arrow_blue_51.png
index 37385c20..5a722324 100644
--- a/res/drawable-xhdpi/arrow_blue_51.png
+++ b/res/drawable-xhdpi/arrow_blue_51.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_52.png b/res/drawable-xhdpi/arrow_blue_52.png
index f9067125..95a5fe14 100644
--- a/res/drawable-xhdpi/arrow_blue_52.png
+++ b/res/drawable-xhdpi/arrow_blue_52.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_53.png b/res/drawable-xhdpi/arrow_blue_53.png
index 63bbe839..0f3880ac 100644
--- a/res/drawable-xhdpi/arrow_blue_53.png
+++ b/res/drawable-xhdpi/arrow_blue_53.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_54.png b/res/drawable-xhdpi/arrow_blue_54.png
index 19566f2d..0f0f6cb7 100644
--- a/res/drawable-xhdpi/arrow_blue_54.png
+++ b/res/drawable-xhdpi/arrow_blue_54.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_55.png b/res/drawable-xhdpi/arrow_blue_55.png
index 40fab462..8ae2cbdc 100644
--- a/res/drawable-xhdpi/arrow_blue_55.png
+++ b/res/drawable-xhdpi/arrow_blue_55.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_56.png b/res/drawable-xhdpi/arrow_blue_56.png
index 73711aac..8649c6e5 100644
--- a/res/drawable-xhdpi/arrow_blue_56.png
+++ b/res/drawable-xhdpi/arrow_blue_56.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_57.png b/res/drawable-xhdpi/arrow_blue_57.png
index 520aebee..7c2b79c9 100644
--- a/res/drawable-xhdpi/arrow_blue_57.png
+++ b/res/drawable-xhdpi/arrow_blue_57.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_58.png b/res/drawable-xhdpi/arrow_blue_58.png
index 39cdbc69..ee358066 100644
--- a/res/drawable-xhdpi/arrow_blue_58.png
+++ b/res/drawable-xhdpi/arrow_blue_58.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_59.png b/res/drawable-xhdpi/arrow_blue_59.png
index aa9f0ba7..26f14e5b 100644
--- a/res/drawable-xhdpi/arrow_blue_59.png
+++ b/res/drawable-xhdpi/arrow_blue_59.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_blue_60.png b/res/drawable-xhdpi/arrow_blue_60.png
index 96ea4bdc..46a1219d 100644
--- a/res/drawable-xhdpi/arrow_blue_60.png
+++ b/res/drawable-xhdpi/arrow_blue_60.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_180.png b/res/drawable-xhdpi/arrow_orange_180.png
index 96ea4bdc..46a1219d 100644
--- a/res/drawable-xhdpi/arrow_orange_180.png
+++ b/res/drawable-xhdpi/arrow_orange_180.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_181.png b/res/drawable-xhdpi/arrow_orange_181.png
index 15639947..f843d3a6 100644
--- a/res/drawable-xhdpi/arrow_orange_181.png
+++ b/res/drawable-xhdpi/arrow_orange_181.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_182.png b/res/drawable-xhdpi/arrow_orange_182.png
index aef1025d..7e626150 100644
--- a/res/drawable-xhdpi/arrow_orange_182.png
+++ b/res/drawable-xhdpi/arrow_orange_182.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_183.png b/res/drawable-xhdpi/arrow_orange_183.png
index fa644665..9e394fb7 100644
--- a/res/drawable-xhdpi/arrow_orange_183.png
+++ b/res/drawable-xhdpi/arrow_orange_183.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_184.png b/res/drawable-xhdpi/arrow_orange_184.png
index ebfd093c..f876774e 100644
--- a/res/drawable-xhdpi/arrow_orange_184.png
+++ b/res/drawable-xhdpi/arrow_orange_184.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_185.png b/res/drawable-xhdpi/arrow_orange_185.png
index 50d50236..6f881c24 100644
--- a/res/drawable-xhdpi/arrow_orange_185.png
+++ b/res/drawable-xhdpi/arrow_orange_185.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_186.png b/res/drawable-xhdpi/arrow_orange_186.png
index a14862ed..2a570507 100644
--- a/res/drawable-xhdpi/arrow_orange_186.png
+++ b/res/drawable-xhdpi/arrow_orange_186.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_187.png b/res/drawable-xhdpi/arrow_orange_187.png
index 21a00ee3..d4172258 100644
--- a/res/drawable-xhdpi/arrow_orange_187.png
+++ b/res/drawable-xhdpi/arrow_orange_187.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_188.png b/res/drawable-xhdpi/arrow_orange_188.png
index d8062abf..c4ce697b 100644
--- a/res/drawable-xhdpi/arrow_orange_188.png
+++ b/res/drawable-xhdpi/arrow_orange_188.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_189.png b/res/drawable-xhdpi/arrow_orange_189.png
index 35880017..a82623d1 100644
--- a/res/drawable-xhdpi/arrow_orange_189.png
+++ b/res/drawable-xhdpi/arrow_orange_189.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_190.png b/res/drawable-xhdpi/arrow_orange_190.png
index f0ba5735..1116527f 100644
--- a/res/drawable-xhdpi/arrow_orange_190.png
+++ b/res/drawable-xhdpi/arrow_orange_190.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_191.png b/res/drawable-xhdpi/arrow_orange_191.png
index 8b4f6e45..60620fcd 100644
--- a/res/drawable-xhdpi/arrow_orange_191.png
+++ b/res/drawable-xhdpi/arrow_orange_191.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_192.png b/res/drawable-xhdpi/arrow_orange_192.png
index 9ad8f726..3ac8d9bc 100644
--- a/res/drawable-xhdpi/arrow_orange_192.png
+++ b/res/drawable-xhdpi/arrow_orange_192.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_193.png b/res/drawable-xhdpi/arrow_orange_193.png
index eef2273c..db1eb6d7 100644
--- a/res/drawable-xhdpi/arrow_orange_193.png
+++ b/res/drawable-xhdpi/arrow_orange_193.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_194.png b/res/drawable-xhdpi/arrow_orange_194.png
index 0ca1b65d..3575e11e 100644
--- a/res/drawable-xhdpi/arrow_orange_194.png
+++ b/res/drawable-xhdpi/arrow_orange_194.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_195.png b/res/drawable-xhdpi/arrow_orange_195.png
index 7076b2f2..8fd0a369 100644
--- a/res/drawable-xhdpi/arrow_orange_195.png
+++ b/res/drawable-xhdpi/arrow_orange_195.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_196.png b/res/drawable-xhdpi/arrow_orange_196.png
index 2eb0222e..adc84811 100644
--- a/res/drawable-xhdpi/arrow_orange_196.png
+++ b/res/drawable-xhdpi/arrow_orange_196.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_197.png b/res/drawable-xhdpi/arrow_orange_197.png
index b3fb2de9..38a3b831 100644
--- a/res/drawable-xhdpi/arrow_orange_197.png
+++ b/res/drawable-xhdpi/arrow_orange_197.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_198.png b/res/drawable-xhdpi/arrow_orange_198.png
index c55b3776..638e4182 100644
--- a/res/drawable-xhdpi/arrow_orange_198.png
+++ b/res/drawable-xhdpi/arrow_orange_198.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_199.png b/res/drawable-xhdpi/arrow_orange_199.png
index 429f672c..439d710d 100644
--- a/res/drawable-xhdpi/arrow_orange_199.png
+++ b/res/drawable-xhdpi/arrow_orange_199.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_200.png b/res/drawable-xhdpi/arrow_orange_200.png
index 76147ae8..7c93e7ff 100644
--- a/res/drawable-xhdpi/arrow_orange_200.png
+++ b/res/drawable-xhdpi/arrow_orange_200.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_201.png b/res/drawable-xhdpi/arrow_orange_201.png
index dae66b75..7604ea5e 100644
--- a/res/drawable-xhdpi/arrow_orange_201.png
+++ b/res/drawable-xhdpi/arrow_orange_201.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_202.png b/res/drawable-xhdpi/arrow_orange_202.png
index de518c74..19994a04 100644
--- a/res/drawable-xhdpi/arrow_orange_202.png
+++ b/res/drawable-xhdpi/arrow_orange_202.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_203.png b/res/drawable-xhdpi/arrow_orange_203.png
index 38ab2ae4..1cbcc8ff 100644
--- a/res/drawable-xhdpi/arrow_orange_203.png
+++ b/res/drawable-xhdpi/arrow_orange_203.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_204.png b/res/drawable-xhdpi/arrow_orange_204.png
index e883d2a5..eeae18c8 100644
--- a/res/drawable-xhdpi/arrow_orange_204.png
+++ b/res/drawable-xhdpi/arrow_orange_204.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_205.png b/res/drawable-xhdpi/arrow_orange_205.png
index ecc1f4b9..4d0ca76d 100644
--- a/res/drawable-xhdpi/arrow_orange_205.png
+++ b/res/drawable-xhdpi/arrow_orange_205.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_206.png b/res/drawable-xhdpi/arrow_orange_206.png
index 49dd52b1..ca2ddbb5 100644
--- a/res/drawable-xhdpi/arrow_orange_206.png
+++ b/res/drawable-xhdpi/arrow_orange_206.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_207.png b/res/drawable-xhdpi/arrow_orange_207.png
index 474b4dfe..5a03de6d 100644
--- a/res/drawable-xhdpi/arrow_orange_207.png
+++ b/res/drawable-xhdpi/arrow_orange_207.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_208.png b/res/drawable-xhdpi/arrow_orange_208.png
index 738e4599..c371edcd 100644
--- a/res/drawable-xhdpi/arrow_orange_208.png
+++ b/res/drawable-xhdpi/arrow_orange_208.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_209.png b/res/drawable-xhdpi/arrow_orange_209.png
index d764a009..8892697e 100644
--- a/res/drawable-xhdpi/arrow_orange_209.png
+++ b/res/drawable-xhdpi/arrow_orange_209.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_210.png b/res/drawable-xhdpi/arrow_orange_210.png
index a129e019..4f836af7 100644
--- a/res/drawable-xhdpi/arrow_orange_210.png
+++ b/res/drawable-xhdpi/arrow_orange_210.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_211.png b/res/drawable-xhdpi/arrow_orange_211.png
index 8166909d..b0900065 100644
--- a/res/drawable-xhdpi/arrow_orange_211.png
+++ b/res/drawable-xhdpi/arrow_orange_211.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_212.png b/res/drawable-xhdpi/arrow_orange_212.png
index 3a2463bb..9d4d92fd 100644
--- a/res/drawable-xhdpi/arrow_orange_212.png
+++ b/res/drawable-xhdpi/arrow_orange_212.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_213.png b/res/drawable-xhdpi/arrow_orange_213.png
index 15b17ef1..0cce209a 100644
--- a/res/drawable-xhdpi/arrow_orange_213.png
+++ b/res/drawable-xhdpi/arrow_orange_213.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_214.png b/res/drawable-xhdpi/arrow_orange_214.png
index b945ccf0..35957014 100644
--- a/res/drawable-xhdpi/arrow_orange_214.png
+++ b/res/drawable-xhdpi/arrow_orange_214.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_215.png b/res/drawable-xhdpi/arrow_orange_215.png
index 94e3379c..d08c2896 100644
--- a/res/drawable-xhdpi/arrow_orange_215.png
+++ b/res/drawable-xhdpi/arrow_orange_215.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_216.png b/res/drawable-xhdpi/arrow_orange_216.png
index 1ff40753..9a0231de 100644
--- a/res/drawable-xhdpi/arrow_orange_216.png
+++ b/res/drawable-xhdpi/arrow_orange_216.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_217.png b/res/drawable-xhdpi/arrow_orange_217.png
index d19fe4e4..91fe5366 100644
--- a/res/drawable-xhdpi/arrow_orange_217.png
+++ b/res/drawable-xhdpi/arrow_orange_217.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_218.png b/res/drawable-xhdpi/arrow_orange_218.png
index 2804ee31..ae9cd6ce 100644
--- a/res/drawable-xhdpi/arrow_orange_218.png
+++ b/res/drawable-xhdpi/arrow_orange_218.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_219.png b/res/drawable-xhdpi/arrow_orange_219.png
index a6c33676..70723d95 100644
--- a/res/drawable-xhdpi/arrow_orange_219.png
+++ b/res/drawable-xhdpi/arrow_orange_219.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_220.png b/res/drawable-xhdpi/arrow_orange_220.png
index 97f2f6fb..699bb862 100644
--- a/res/drawable-xhdpi/arrow_orange_220.png
+++ b/res/drawable-xhdpi/arrow_orange_220.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_221.png b/res/drawable-xhdpi/arrow_orange_221.png
index bfb808a2..6ab0b07f 100644
--- a/res/drawable-xhdpi/arrow_orange_221.png
+++ b/res/drawable-xhdpi/arrow_orange_221.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_222.png b/res/drawable-xhdpi/arrow_orange_222.png
index 087446ea..ed86933e 100644
--- a/res/drawable-xhdpi/arrow_orange_222.png
+++ b/res/drawable-xhdpi/arrow_orange_222.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_223.png b/res/drawable-xhdpi/arrow_orange_223.png
index 3eaf81f2..59bb7760 100644
--- a/res/drawable-xhdpi/arrow_orange_223.png
+++ b/res/drawable-xhdpi/arrow_orange_223.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_224.png b/res/drawable-xhdpi/arrow_orange_224.png
index e5d173d0..606608aa 100644
--- a/res/drawable-xhdpi/arrow_orange_224.png
+++ b/res/drawable-xhdpi/arrow_orange_224.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_225.png b/res/drawable-xhdpi/arrow_orange_225.png
index 4eab8f89..3f0638ac 100644
--- a/res/drawable-xhdpi/arrow_orange_225.png
+++ b/res/drawable-xhdpi/arrow_orange_225.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_226.png b/res/drawable-xhdpi/arrow_orange_226.png
index 3354eb9e..2abb186b 100644
--- a/res/drawable-xhdpi/arrow_orange_226.png
+++ b/res/drawable-xhdpi/arrow_orange_226.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_227.png b/res/drawable-xhdpi/arrow_orange_227.png
index 8de9b894..3ee5f45d 100644
--- a/res/drawable-xhdpi/arrow_orange_227.png
+++ b/res/drawable-xhdpi/arrow_orange_227.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_228.png b/res/drawable-xhdpi/arrow_orange_228.png
index 8718c4e4..a40f48e0 100644
--- a/res/drawable-xhdpi/arrow_orange_228.png
+++ b/res/drawable-xhdpi/arrow_orange_228.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_229.png b/res/drawable-xhdpi/arrow_orange_229.png
index 834ae57c..dd0fac79 100644
--- a/res/drawable-xhdpi/arrow_orange_229.png
+++ b/res/drawable-xhdpi/arrow_orange_229.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_230.png b/res/drawable-xhdpi/arrow_orange_230.png
index c06cb457..397e36f7 100644
--- a/res/drawable-xhdpi/arrow_orange_230.png
+++ b/res/drawable-xhdpi/arrow_orange_230.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_231.png b/res/drawable-xhdpi/arrow_orange_231.png
index c38edb86..ef61d8cd 100644
--- a/res/drawable-xhdpi/arrow_orange_231.png
+++ b/res/drawable-xhdpi/arrow_orange_231.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_232.png b/res/drawable-xhdpi/arrow_orange_232.png
index c3a036a7..5d75f753 100644
--- a/res/drawable-xhdpi/arrow_orange_232.png
+++ b/res/drawable-xhdpi/arrow_orange_232.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_233.png b/res/drawable-xhdpi/arrow_orange_233.png
index 7cd3abe4..d95d6226 100644
--- a/res/drawable-xhdpi/arrow_orange_233.png
+++ b/res/drawable-xhdpi/arrow_orange_233.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_234.png b/res/drawable-xhdpi/arrow_orange_234.png
index 8e886ad7..d6e034d6 100644
--- a/res/drawable-xhdpi/arrow_orange_234.png
+++ b/res/drawable-xhdpi/arrow_orange_234.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_235.png b/res/drawable-xhdpi/arrow_orange_235.png
index 54031a24..297e04bd 100644
--- a/res/drawable-xhdpi/arrow_orange_235.png
+++ b/res/drawable-xhdpi/arrow_orange_235.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_236.png b/res/drawable-xhdpi/arrow_orange_236.png
index d39bdd21..62d1223f 100644
--- a/res/drawable-xhdpi/arrow_orange_236.png
+++ b/res/drawable-xhdpi/arrow_orange_236.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_237.png b/res/drawable-xhdpi/arrow_orange_237.png
index 5e20da64..e473441e 100644
--- a/res/drawable-xhdpi/arrow_orange_237.png
+++ b/res/drawable-xhdpi/arrow_orange_237.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_238.png b/res/drawable-xhdpi/arrow_orange_238.png
index f0e19b2f..af4c831c 100644
--- a/res/drawable-xhdpi/arrow_orange_238.png
+++ b/res/drawable-xhdpi/arrow_orange_238.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_239.png b/res/drawable-xhdpi/arrow_orange_239.png
index edaf237b..8e82c050 100644
--- a/res/drawable-xhdpi/arrow_orange_239.png
+++ b/res/drawable-xhdpi/arrow_orange_239.png
Binary files differ
diff --git a/res/drawable-xhdpi/arrow_orange_240.png b/res/drawable-xhdpi/arrow_orange_240.png
index 96ea4bdc..46a1219d 100644
--- a/res/drawable-xhdpi/arrow_orange_240.png
+++ b/res/drawable-xhdpi/arrow_orange_240.png
Binary files differ
diff --git a/res/drawable-xhdpi/banner.png b/res/drawable-xhdpi/banner.png
index 95049156..57dbb05e 100644
--- a/res/drawable-xhdpi/banner.png
+++ b/res/drawable-xhdpi/banner.png
Binary files differ
diff --git a/res/drawable-xhdpi/bg_protection.png b/res/drawable-xhdpi/bg_protection.png
index e3226520..02df25ae 100644
--- a/res/drawable-xhdpi/bg_protection.png
+++ b/res/drawable-xhdpi/bg_protection.png
Binary files differ
diff --git a/res/drawable-xhdpi/cloud01.png b/res/drawable-xhdpi/cloud01.png
index eec4ea96..2bb6a2aa 100644
--- a/res/drawable-xhdpi/cloud01.png
+++ b/res/drawable-xhdpi/cloud01.png
Binary files differ
diff --git a/res/drawable-xhdpi/cloud02.png b/res/drawable-xhdpi/cloud02.png
index 0ec6bf15..35c97466 100644
--- a/res/drawable-xhdpi/cloud02.png
+++ b/res/drawable-xhdpi/cloud02.png
Binary files differ
diff --git a/res/drawable-xhdpi/default_now_card.png b/res/drawable-xhdpi/default_now_card.png
index 96cc99c9..95deb5b3 100644
--- a/res/drawable-xhdpi/default_now_card.png
+++ b/res/drawable-xhdpi/default_now_card.png
Binary files differ
diff --git a/res/drawable-xhdpi/dvr_default_poster.png b/res/drawable-xhdpi/dvr_default_poster.png
new file mode 100644
index 00000000..683a693d
--- /dev/null
+++ b/res/drawable-xhdpi/dvr_default_poster.png
Binary files differ
diff --git a/res/drawable-xhdpi/dvr_default_program_art.png b/res/drawable-xhdpi/dvr_default_program_art.png
index e0ae149f..6a8d68ee 100644
--- a/res/drawable-xhdpi/dvr_default_program_art.png
+++ b/res/drawable-xhdpi/dvr_default_program_art.png
Binary files differ
diff --git a/res/drawable-xhdpi/dvr_full_schedule.png b/res/drawable-xhdpi/dvr_full_schedule.png
new file mode 100644
index 00000000..e9f59ad4
--- /dev/null
+++ b/res/drawable-xhdpi/dvr_full_schedule.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_channel_guide.png b/res/drawable-xhdpi/ic_channel_guide.png
index 28f3ef8e..526b2f6e 100644
--- a/res/drawable-xhdpi/ic_channel_guide.png
+++ b/res/drawable-xhdpi/ic_channel_guide.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_check_circle_white_48dp.png b/res/drawable-xhdpi/ic_check_circle_white_48dp.png
new file mode 100644
index 00000000..a1cf83e6
--- /dev/null
+++ b/res/drawable-xhdpi/ic_check_circle_white_48dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_delete_32dp.png b/res/drawable-xhdpi/ic_delete_32dp.png
new file mode 100644
index 00000000..b3e9754c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_delete_32dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_developer_mode_tv_white_48dp.png b/res/drawable-xhdpi/ic_developer_mode_tv_white_48dp.png
new file mode 100755
index 00000000..ab2949b7
--- /dev/null
+++ b/res/drawable-xhdpi/ic_developer_mode_tv_white_48dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_draggable_white.png b/res/drawable-xhdpi/ic_draggable_white.png
new file mode 100644
index 00000000..37d69506
--- /dev/null
+++ b/res/drawable-xhdpi/ic_draggable_white.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dragging_grey.png b/res/drawable-xhdpi/ic_dragging_grey.png
new file mode 100644
index 00000000..5ddb2ad4
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dragging_grey.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dvr.png b/res/drawable-xhdpi/ic_dvr.png
index c8c84f37..347db044 100644
--- a/res/drawable-xhdpi/ic_dvr.png
+++ b/res/drawable-xhdpi/ic_dvr.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dvr_cancel.png b/res/drawable-xhdpi/ic_dvr_cancel.png
new file mode 100644
index 00000000..bc761c70
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dvr_cancel.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dvr_cancel_32dp.png b/res/drawable-xhdpi/ic_dvr_cancel_32dp.png
new file mode 100644
index 00000000..339247ef
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dvr_cancel_32dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dvr_cancel_large.png b/res/drawable-xhdpi/ic_dvr_cancel_large.png
new file mode 100644
index 00000000..f3686d05
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dvr_cancel_large.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_dvr_delete.png b/res/drawable-xhdpi/ic_dvr_delete.png
new file mode 100644
index 00000000..bcdca673
--- /dev/null
+++ b/res/drawable-xhdpi/ic_dvr_delete.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_error_recording.png b/res/drawable-xhdpi/ic_error_recording.png
new file mode 100644
index 00000000..5878c3b3
--- /dev/null
+++ b/res/drawable-xhdpi/ic_error_recording.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_error_white_48dp.png b/res/drawable-xhdpi/ic_error_white_48dp.png
new file mode 100644
index 00000000..e8e8ab5a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_error_white_48dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_fresh.png b/res/drawable-xhdpi/ic_fresh.png
new file mode 100644
index 00000000..c1bc9583
--- /dev/null
+++ b/res/drawable-xhdpi/ic_fresh.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_guide_lock.png b/res/drawable-xhdpi/ic_guide_lock.png
index bc2b526a..e36bd12d 100644
--- a/res/drawable-xhdpi/ic_guide_lock.png
+++ b/res/drawable-xhdpi/ic_guide_lock.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher.png b/res/drawable-xhdpi/ic_launcher.png
index 6b092ce7..7f4eb10d 100644
--- a/res/drawable-xhdpi/ic_launcher.png
+++ b/res/drawable-xhdpi/ic_launcher.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_launcher_s.png b/res/drawable-xhdpi/ic_launcher_s.png
index b5808345..8fe7fd59 100644
--- a/res/drawable-xhdpi/ic_launcher_s.png
+++ b/res/drawable-xhdpi/ic_launcher_s.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_message_lock.png b/res/drawable-xhdpi/ic_message_lock.png
index b39748c0..96d0af49 100644
--- a/res/drawable-xhdpi/ic_message_lock.png
+++ b/res/drawable-xhdpi/ic_message_lock.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_message_lock_no_permission.png b/res/drawable-xhdpi/ic_message_lock_no_permission.png
index 4d53726b..bb996971 100644
--- a/res/drawable-xhdpi/ic_message_lock_no_permission.png
+++ b/res/drawable-xhdpi/ic_message_lock_no_permission.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_message_lock_preview.png b/res/drawable-xhdpi/ic_message_lock_preview.png
index 8c828b40..69a5eedf 100644
--- a/res/drawable-xhdpi/ic_message_lock_preview.png
+++ b/res/drawable-xhdpi/ic_message_lock_preview.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_input.png b/res/drawable-xhdpi/ic_pip_option_input.png
index 2638b67b..47c5006f 100644
--- a/res/drawable-xhdpi/ic_pip_option_input.png
+++ b/res/drawable-xhdpi/ic_pip_option_input.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_layout1.png b/res/drawable-xhdpi/ic_pip_option_layout1.png
index ade3cfc5..14b2602a 100644
--- a/res/drawable-xhdpi/ic_pip_option_layout1.png
+++ b/res/drawable-xhdpi/ic_pip_option_layout1.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_layout2.png b/res/drawable-xhdpi/ic_pip_option_layout2.png
index 1a59e474..e5d77278 100644
--- a/res/drawable-xhdpi/ic_pip_option_layout2.png
+++ b/res/drawable-xhdpi/ic_pip_option_layout2.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_layout3.png b/res/drawable-xhdpi/ic_pip_option_layout3.png
index f43a57ed..dfe110d0 100644
--- a/res/drawable-xhdpi/ic_pip_option_layout3.png
+++ b/res/drawable-xhdpi/ic_pip_option_layout3.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_layout4.png b/res/drawable-xhdpi/ic_pip_option_layout4.png
index bdf3f065..8ab5fa45 100644
--- a/res/drawable-xhdpi/ic_pip_option_layout4.png
+++ b/res/drawable-xhdpi/ic_pip_option_layout4.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_layout5.png b/res/drawable-xhdpi/ic_pip_option_layout5.png
index 4868c9f0..d6b53641 100644
--- a/res/drawable-xhdpi/ic_pip_option_layout5.png
+++ b/res/drawable-xhdpi/ic_pip_option_layout5.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_size.png b/res/drawable-xhdpi/ic_pip_option_size.png
index f7e32591..96fb0b0c 100644
--- a/res/drawable-xhdpi/ic_pip_option_size.png
+++ b/res/drawable-xhdpi/ic_pip_option_size.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_swap.png b/res/drawable-xhdpi/ic_pip_option_swap.png
index fd9d8895..fa2088ed 100644
--- a/res/drawable-xhdpi/ic_pip_option_swap.png
+++ b/res/drawable-xhdpi/ic_pip_option_swap.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_pip_option_swap_audio.png b/res/drawable-xhdpi/ic_pip_option_swap_audio.png
index 8f62ab0c..a5f5431b 100644
--- a/res/drawable-xhdpi/ic_pip_option_swap_audio.png
+++ b/res/drawable-xhdpi/ic_pip_option_swap_audio.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_playstore.png b/res/drawable-xhdpi/ic_playstore.png
deleted file mode 100644
index 6b092ce7..00000000
--- a/res/drawable-xhdpi/ic_playstore.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_recent_thumbnail_default.png b/res/drawable-xhdpi/ic_recent_thumbnail_default.png
index 9604888b..7007ee31 100644
--- a/res/drawable-xhdpi/ic_recent_thumbnail_default.png
+++ b/res/drawable-xhdpi/ic_recent_thumbnail_default.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_record_start.png b/res/drawable-xhdpi/ic_record_start.png
new file mode 100644
index 00000000..53e3f03f
--- /dev/null
+++ b/res/drawable-xhdpi/ic_record_start.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_record_start_white.png b/res/drawable-xhdpi/ic_record_start_white.png
deleted file mode 100644
index 591b54a5..00000000
--- a/res/drawable-xhdpi/ic_record_start_white.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-xhdpi/ic_record_stop.png b/res/drawable-xhdpi/ic_record_stop.png
index 52393366..5ad9aa25 100644
--- a/res/drawable-xhdpi/ic_record_stop.png
+++ b/res/drawable-xhdpi/ic_record_stop.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_recorded_program.png b/res/drawable-xhdpi/ic_recorded_program.png
new file mode 100644
index 00000000..fe22714e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_recorded_program.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_recording_program.png b/res/drawable-xhdpi/ic_recording_program.png
new file mode 100644
index 00000000..c9900e45
--- /dev/null
+++ b/res/drawable-xhdpi/ic_recording_program.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_related_actor.png b/res/drawable-xhdpi/ic_related_actor.png
index c4d7037f..9b726b93 100644
--- a/res/drawable-xhdpi/ic_related_actor.png
+++ b/res/drawable-xhdpi/ic_related_actor.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_related_search.png b/res/drawable-xhdpi/ic_related_search.png
index 8443cfe0..aa5cd0d2 100644
--- a/res/drawable-xhdpi/ic_related_search.png
+++ b/res/drawable-xhdpi/ic_related_search.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_sad_cloud.png b/res/drawable-xhdpi/ic_sad_cloud.png
index af9e19d7..c20d03a4 100644
--- a/res/drawable-xhdpi/ic_sad_cloud.png
+++ b/res/drawable-xhdpi/ic_sad_cloud.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_schedule_32dp.png b/res/drawable-xhdpi/ic_schedule_32dp.png
new file mode 100644
index 00000000..b3e4bb5a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_schedule_32dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_scheduled_recording.png b/res/drawable-xhdpi/ic_scheduled_recording.png
new file mode 100644
index 00000000..520823a2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_scheduled_recording.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_scheduled_white.png b/res/drawable-xhdpi/ic_scheduled_white.png
new file mode 100644
index 00000000..49778def
--- /dev/null
+++ b/res/drawable-xhdpi/ic_scheduled_white.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_settings.png b/res/drawable-xhdpi/ic_settings.png
index 85ae13c0..75c65b7f 100644
--- a/res/drawable-xhdpi/ic_settings.png
+++ b/res/drawable-xhdpi/ic_settings.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_setup_antenna.png b/res/drawable-xhdpi/ic_setup_antenna.png
index 1f9e0673..bb6d416e 100644
--- a/res/drawable-xhdpi/ic_setup_antenna.png
+++ b/res/drawable-xhdpi/ic_setup_antenna.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_setup_channels.png b/res/drawable-xhdpi/ic_setup_channels.png
index ee9e63ee..03ff8501 100644
--- a/res/drawable-xhdpi/ic_setup_channels.png
+++ b/res/drawable-xhdpi/ic_setup_channels.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_store.png b/res/drawable-xhdpi/ic_store.png
index 6b092ce7..767b8b64 100644
--- a/res/drawable-xhdpi/ic_store.png
+++ b/res/drawable-xhdpi/ic_store.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_aspect.png b/res/drawable-xhdpi/ic_tvoption_aspect.png
index 526908f8..618af666 100644
--- a/res/drawable-xhdpi/ic_tvoption_aspect.png
+++ b/res/drawable-xhdpi/ic_tvoption_aspect.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_cc.png b/res/drawable-xhdpi/ic_tvoption_cc.png
index 2c7ce075..0354f610 100644
--- a/res/drawable-xhdpi/ic_tvoption_cc.png
+++ b/res/drawable-xhdpi/ic_tvoption_cc.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_channel_sources.png b/res/drawable-xhdpi/ic_tvoption_channel_sources.png
index f5df5bcd..29be7c49 100644
--- a/res/drawable-xhdpi/ic_tvoption_channel_sources.png
+++ b/res/drawable-xhdpi/ic_tvoption_channel_sources.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_multi_track.png b/res/drawable-xhdpi/ic_tvoption_multi_track.png
index ef06dff0..d1aff333 100644
--- a/res/drawable-xhdpi/ic_tvoption_multi_track.png
+++ b/res/drawable-xhdpi/ic_tvoption_multi_track.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_pip.png b/res/drawable-xhdpi/ic_tvoption_pip.png
index 59b972e1..0f78d834 100644
--- a/res/drawable-xhdpi/ic_tvoption_pip.png
+++ b/res/drawable-xhdpi/ic_tvoption_pip.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvoption_pip_off.png b/res/drawable-xhdpi/ic_tvoption_pip_off.png
index d3a8e7a5..6001677b 100644
--- a/res/drawable-xhdpi/ic_tvoption_pip_off.png
+++ b/res/drawable-xhdpi/ic_tvoption_pip_off.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_000.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_000.png
index 4590e526..67c8b5e4 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_000.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_000.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_001.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_001.png
index b6b6a456..44cc2f39 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_001.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_001.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_002.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_002.png
index 5338ab0d..1d764f8c 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_002.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_002.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_003.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_003.png
index 3e9344f6..c4e0044f 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_003.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_003.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_004.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_004.png
index 5913b6b5..283e1000 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_004.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_004.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_005.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_005.png
index 6875c757..d908a379 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_005.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_005.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_006.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_006.png
index d9aaf992..aaa0800e 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_006.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_006.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_007.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_007.png
index 1ad3fdb9..056b5521 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_007.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_007.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_008.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_008.png
index 37b41c05..b6e58ccc 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_008.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_008.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_009.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_009.png
index 68ac8099..3634be7e 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_009.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_009.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_010.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_010.png
index 7efbe4fa..af1c0d56 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_010.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_010.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_011.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_011.png
index 3a52cf11..aae87470 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_011.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_011.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_012.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_012.png
index f7a9cfa9..bbd2f88d 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_012.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_012.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_013.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_013.png
index b4745445..2b85890b 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_013.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_013.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_014.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_014.png
index 91f39f58..7f792140 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_014.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_014.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_015.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_015.png
index d75e729c..84ef5807 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_015.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_off_015.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_000.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_000.png
index d2a0111a..f715ccc8 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_000.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_000.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_001.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_001.png
index a752b8ab..26795600 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_001.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_001.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_002.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_002.png
index e5031ce4..2749526f 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_002.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_002.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_003.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_003.png
index 444f764b..a3aa00aa 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_003.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_003.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_004.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_004.png
index 6ae843b8..603166b9 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_004.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_004.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_005.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_005.png
index ea85bdec..572dacbf 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_005.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_005.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_006.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_006.png
index 0ac66a6a..e65a0a6d 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_006.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_006.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_007.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_007.png
index f528f9c4..f06b1c13 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_007.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_007.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_008.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_008.png
index aa66a36f..5e2d15a6 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_008.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_008.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_009.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_009.png
index 2e40391c..e10651d5 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_009.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_009.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_010.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_010.png
index 4bd0f44d..36efe51d 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_010.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_010.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_011.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_011.png
index a9ef8429..049007c2 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_011.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_011.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_012.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_012.png
index b0bc8da3..7a9ace53 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_012.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_012.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_013.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_013.png
index c0688d01..8069a5d4 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_013.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_013.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_014.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_014.png
index 5fd53fac..fe3ca479 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_014.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_014.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_015.png b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_015.png
index 8310681e..fd5111ee 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_015.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_lock_to_on_015.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_tvsidepanel_partial_locked.png b/res/drawable-xhdpi/ic_tvsidepanel_partial_locked.png
index 7c8dc1d0..0997a2a4 100644
--- a/res/drawable-xhdpi/ic_tvsidepanel_partial_locked.png
+++ b/res/drawable-xhdpi/ic_tvsidepanel_partial_locked.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_warning_gray600_36dp.png b/res/drawable-xhdpi/ic_warning_gray600_36dp.png
new file mode 100644
index 00000000..7c08b8f8
--- /dev/null
+++ b/res/drawable-xhdpi/ic_warning_gray600_36dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_warning_white_12dp.png b/res/drawable-xhdpi/ic_warning_white_12dp.png
new file mode 100644
index 00000000..7123470a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_warning_white_12dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_warning_white_18dp.png b/res/drawable-xhdpi/ic_warning_white_18dp.png
new file mode 100644
index 00000000..1e69e397
--- /dev/null
+++ b/res/drawable-xhdpi/ic_warning_white_18dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_warning_white_32dp.png b/res/drawable-xhdpi/ic_warning_white_32dp.png
new file mode 100644
index 00000000..f5267b5a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_warning_white_32dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_warning_white_96dp.png b/res/drawable-xhdpi/ic_warning_white_96dp.png
new file mode 100644
index 00000000..de684e4e
--- /dev/null
+++ b/res/drawable-xhdpi/ic_warning_white_96dp.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_remote.png b/res/drawable-xhdpi/ic_welcome_remote.png
index e4dee093..1a46d3f6 100644
--- a/res/drawable-xhdpi/ic_welcome_remote.png
+++ b/res/drawable-xhdpi/ic_welcome_remote.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_000.png b/res/drawable-xhdpi/ic_welcome_ripple_000.png
index 3a895e06..c4aac06c 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_000.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_000.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_001.png b/res/drawable-xhdpi/ic_welcome_ripple_001.png
index 04b1d4b3..6b11f82d 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_001.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_001.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_002.png b/res/drawable-xhdpi/ic_welcome_ripple_002.png
index 7e9ecf26..a8831bbf 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_002.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_002.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_003.png b/res/drawable-xhdpi/ic_welcome_ripple_003.png
index 25c2ce5c..65eaa5af 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_003.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_003.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_004.png b/res/drawable-xhdpi/ic_welcome_ripple_004.png
index e18936c4..9cfcce52 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_004.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_004.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_005.png b/res/drawable-xhdpi/ic_welcome_ripple_005.png
index 70c54176..28564500 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_005.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_005.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_006.png b/res/drawable-xhdpi/ic_welcome_ripple_006.png
index 29b290c6..5312045c 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_006.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_006.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_007.png b/res/drawable-xhdpi/ic_welcome_ripple_007.png
index 28c91fe4..25b0aadd 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_007.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_007.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_008.png b/res/drawable-xhdpi/ic_welcome_ripple_008.png
index 52e13c0a..3a1b5852 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_008.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_008.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_009.png b/res/drawable-xhdpi/ic_welcome_ripple_009.png
index b7dc9eb0..c279671e 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_009.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_009.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_010.png b/res/drawable-xhdpi/ic_welcome_ripple_010.png
index 6bc277b0..6513aec3 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_010.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_010.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_011.png b/res/drawable-xhdpi/ic_welcome_ripple_011.png
index 88ec07b6..fef25e60 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_011.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_011.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_012.png b/res/drawable-xhdpi/ic_welcome_ripple_012.png
index 11c9b354..d38643fb 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_012.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_012.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_013.png b/res/drawable-xhdpi/ic_welcome_ripple_013.png
index ba7d171e..514e4158 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_013.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_013.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_014.png b/res/drawable-xhdpi/ic_welcome_ripple_014.png
index 7e35807b..cd3670fb 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_014.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_014.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_015.png b/res/drawable-xhdpi/ic_welcome_ripple_015.png
index e666d09c..1a149bfd 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_015.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_015.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_016.png b/res/drawable-xhdpi/ic_welcome_ripple_016.png
index ed575d24..2933c7b9 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_016.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_016.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_017.png b/res/drawable-xhdpi/ic_welcome_ripple_017.png
index 796de58f..b270c000 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_017.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_017.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_018.png b/res/drawable-xhdpi/ic_welcome_ripple_018.png
index b771578a..c2e84552 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_018.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_018.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_019.png b/res/drawable-xhdpi/ic_welcome_ripple_019.png
index 11caa031..f88d98f3 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_019.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_019.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_020.png b/res/drawable-xhdpi/ic_welcome_ripple_020.png
index ccb44f97..e35edd02 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_020.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_020.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_021.png b/res/drawable-xhdpi/ic_welcome_ripple_021.png
index 3e28479a..3ac9033e 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_021.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_021.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_022.png b/res/drawable-xhdpi/ic_welcome_ripple_022.png
index b23e9b68..fa08dd82 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_022.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_022.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_023.png b/res/drawable-xhdpi/ic_welcome_ripple_023.png
index ff245dba..f843499d 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_023.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_023.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_024.png b/res/drawable-xhdpi/ic_welcome_ripple_024.png
index 5e757cb4..af557d82 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_024.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_024.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_025.png b/res/drawable-xhdpi/ic_welcome_ripple_025.png
index f30e7442..e0a720d3 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_025.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_025.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_026.png b/res/drawable-xhdpi/ic_welcome_ripple_026.png
index cb91962c..380c8124 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_026.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_026.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_027.png b/res/drawable-xhdpi/ic_welcome_ripple_027.png
index d7cbafaa..2ed6ddc2 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_027.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_027.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_028.png b/res/drawable-xhdpi/ic_welcome_ripple_028.png
index e950fd02..ca74c3af 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_028.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_028.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_welcome_ripple_029.png b/res/drawable-xhdpi/ic_welcome_ripple_029.png
index f44d7588..f35566f7 100644
--- a/res/drawable-xhdpi/ic_welcome_ripple_029.png
+++ b/res/drawable-xhdpi/ic_welcome_ripple_029.png
Binary files differ
diff --git a/res/drawable-xhdpi/splash_logo.png b/res/drawable-xhdpi/splash_logo.png
index e0ae149f..6a8d68ee 100644
--- a/res/drawable-xhdpi/splash_logo.png
+++ b/res/drawable-xhdpi/splash_logo.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_01.png b/res/drawable-xhdpi/tv_1a_01.png
index d94b821f..ad8f256d 100644
--- a/res/drawable-xhdpi/tv_1a_01.png
+++ b/res/drawable-xhdpi/tv_1a_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_02.png b/res/drawable-xhdpi/tv_1a_02.png
index 63304e05..41dd0527 100644
--- a/res/drawable-xhdpi/tv_1a_02.png
+++ b/res/drawable-xhdpi/tv_1a_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_03.png b/res/drawable-xhdpi/tv_1a_03.png
index dd518d90..490081c3 100644
--- a/res/drawable-xhdpi/tv_1a_03.png
+++ b/res/drawable-xhdpi/tv_1a_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_04.png b/res/drawable-xhdpi/tv_1a_04.png
index 8ba3ec5e..20dd2b33 100644
--- a/res/drawable-xhdpi/tv_1a_04.png
+++ b/res/drawable-xhdpi/tv_1a_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_05.png b/res/drawable-xhdpi/tv_1a_05.png
index 9cadbdf6..2b2862ea 100644
--- a/res/drawable-xhdpi/tv_1a_05.png
+++ b/res/drawable-xhdpi/tv_1a_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_06.png b/res/drawable-xhdpi/tv_1a_06.png
index ba0da27c..eb31a31c 100644
--- a/res/drawable-xhdpi/tv_1a_06.png
+++ b/res/drawable-xhdpi/tv_1a_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_07.png b/res/drawable-xhdpi/tv_1a_07.png
index 38310d5f..b47fa761 100644
--- a/res/drawable-xhdpi/tv_1a_07.png
+++ b/res/drawable-xhdpi/tv_1a_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_08.png b/res/drawable-xhdpi/tv_1a_08.png
index a90858ab..b96c5816 100644
--- a/res/drawable-xhdpi/tv_1a_08.png
+++ b/res/drawable-xhdpi/tv_1a_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_09.png b/res/drawable-xhdpi/tv_1a_09.png
index 7d39f4a2..bd438bd0 100644
--- a/res/drawable-xhdpi/tv_1a_09.png
+++ b/res/drawable-xhdpi/tv_1a_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_10.png b/res/drawable-xhdpi/tv_1a_10.png
index 03019560..6842ca5f 100644
--- a/res/drawable-xhdpi/tv_1a_10.png
+++ b/res/drawable-xhdpi/tv_1a_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_11.png b/res/drawable-xhdpi/tv_1a_11.png
index 465c08dd..211274e7 100644
--- a/res/drawable-xhdpi/tv_1a_11.png
+++ b/res/drawable-xhdpi/tv_1a_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_12.png b/res/drawable-xhdpi/tv_1a_12.png
index e35437ab..00aea442 100644
--- a/res/drawable-xhdpi/tv_1a_12.png
+++ b/res/drawable-xhdpi/tv_1a_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_13.png b/res/drawable-xhdpi/tv_1a_13.png
index 7cfb2dbd..c39a78e4 100644
--- a/res/drawable-xhdpi/tv_1a_13.png
+++ b/res/drawable-xhdpi/tv_1a_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_14.png b/res/drawable-xhdpi/tv_1a_14.png
index acbc4a21..b90df8ff 100644
--- a/res/drawable-xhdpi/tv_1a_14.png
+++ b/res/drawable-xhdpi/tv_1a_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_15.png b/res/drawable-xhdpi/tv_1a_15.png
index cbb5467b..8d73ecca 100644
--- a/res/drawable-xhdpi/tv_1a_15.png
+++ b/res/drawable-xhdpi/tv_1a_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_16.png b/res/drawable-xhdpi/tv_1a_16.png
index 4fc38c84..029b4002 100644
--- a/res/drawable-xhdpi/tv_1a_16.png
+++ b/res/drawable-xhdpi/tv_1a_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_17.png b/res/drawable-xhdpi/tv_1a_17.png
index 3f7b0302..a65e97c1 100644
--- a/res/drawable-xhdpi/tv_1a_17.png
+++ b/res/drawable-xhdpi/tv_1a_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_18.png b/res/drawable-xhdpi/tv_1a_18.png
index d46e6605..91925ba4 100644
--- a/res/drawable-xhdpi/tv_1a_18.png
+++ b/res/drawable-xhdpi/tv_1a_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_19.png b/res/drawable-xhdpi/tv_1a_19.png
index 73931eef..81b5b327 100644
--- a/res/drawable-xhdpi/tv_1a_19.png
+++ b/res/drawable-xhdpi/tv_1a_19.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1a_20.png b/res/drawable-xhdpi/tv_1a_20.png
index d36eb6b9..1f429a16 100644
--- a/res/drawable-xhdpi/tv_1a_20.png
+++ b/res/drawable-xhdpi/tv_1a_20.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_01.png b/res/drawable-xhdpi/tv_1b_01.png
index a0baf098..d7307343 100644
--- a/res/drawable-xhdpi/tv_1b_01.png
+++ b/res/drawable-xhdpi/tv_1b_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_02.png b/res/drawable-xhdpi/tv_1b_02.png
index a0fc4a4f..b36e1f03 100644
--- a/res/drawable-xhdpi/tv_1b_02.png
+++ b/res/drawable-xhdpi/tv_1b_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_03.png b/res/drawable-xhdpi/tv_1b_03.png
index f5a7f3f9..b94fb62d 100644
--- a/res/drawable-xhdpi/tv_1b_03.png
+++ b/res/drawable-xhdpi/tv_1b_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_04.png b/res/drawable-xhdpi/tv_1b_04.png
index ce8d3e3e..4d8a11fc 100644
--- a/res/drawable-xhdpi/tv_1b_04.png
+++ b/res/drawable-xhdpi/tv_1b_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_05.png b/res/drawable-xhdpi/tv_1b_05.png
index 40cc9c36..080d401b 100644
--- a/res/drawable-xhdpi/tv_1b_05.png
+++ b/res/drawable-xhdpi/tv_1b_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_06.png b/res/drawable-xhdpi/tv_1b_06.png
index 8bfa6b35..079d83cb 100644
--- a/res/drawable-xhdpi/tv_1b_06.png
+++ b/res/drawable-xhdpi/tv_1b_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_07.png b/res/drawable-xhdpi/tv_1b_07.png
index 72be40d9..f5a936c0 100644
--- a/res/drawable-xhdpi/tv_1b_07.png
+++ b/res/drawable-xhdpi/tv_1b_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_08.png b/res/drawable-xhdpi/tv_1b_08.png
index 48e342cc..5d4d5ab7 100644
--- a/res/drawable-xhdpi/tv_1b_08.png
+++ b/res/drawable-xhdpi/tv_1b_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_09.png b/res/drawable-xhdpi/tv_1b_09.png
index b987b31c..2c4cb8c7 100644
--- a/res/drawable-xhdpi/tv_1b_09.png
+++ b/res/drawable-xhdpi/tv_1b_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_10.png b/res/drawable-xhdpi/tv_1b_10.png
index bc6c3d39..6fa0f22b 100644
--- a/res/drawable-xhdpi/tv_1b_10.png
+++ b/res/drawable-xhdpi/tv_1b_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_1b_11.png b/res/drawable-xhdpi/tv_1b_11.png
index d94b821f..ad8f256d 100644
--- a/res/drawable-xhdpi/tv_1b_11.png
+++ b/res/drawable-xhdpi/tv_1b_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_01.png b/res/drawable-xhdpi/tv_2a_01.png
index d94b821f..ad8f256d 100644
--- a/res/drawable-xhdpi/tv_2a_01.png
+++ b/res/drawable-xhdpi/tv_2a_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_02.png b/res/drawable-xhdpi/tv_2a_02.png
index 4ed5bbe7..071f41e9 100644
--- a/res/drawable-xhdpi/tv_2a_02.png
+++ b/res/drawable-xhdpi/tv_2a_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_03.png b/res/drawable-xhdpi/tv_2a_03.png
index 68f69ab3..d404c31c 100644
--- a/res/drawable-xhdpi/tv_2a_03.png
+++ b/res/drawable-xhdpi/tv_2a_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_04.png b/res/drawable-xhdpi/tv_2a_04.png
index f4247d9d..07d2367c 100644
--- a/res/drawable-xhdpi/tv_2a_04.png
+++ b/res/drawable-xhdpi/tv_2a_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_05.png b/res/drawable-xhdpi/tv_2a_05.png
index 1ada2991..f7c262bd 100644
--- a/res/drawable-xhdpi/tv_2a_05.png
+++ b/res/drawable-xhdpi/tv_2a_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_06.png b/res/drawable-xhdpi/tv_2a_06.png
index 14bb866e..32cf47c4 100644
--- a/res/drawable-xhdpi/tv_2a_06.png
+++ b/res/drawable-xhdpi/tv_2a_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_07.png b/res/drawable-xhdpi/tv_2a_07.png
index e6b456f0..87c5dff4 100644
--- a/res/drawable-xhdpi/tv_2a_07.png
+++ b/res/drawable-xhdpi/tv_2a_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_08.png b/res/drawable-xhdpi/tv_2a_08.png
index 019da08d..2e5de8af 100644
--- a/res/drawable-xhdpi/tv_2a_08.png
+++ b/res/drawable-xhdpi/tv_2a_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_09.png b/res/drawable-xhdpi/tv_2a_09.png
index 51d1cf2f..21c3ee6d 100644
--- a/res/drawable-xhdpi/tv_2a_09.png
+++ b/res/drawable-xhdpi/tv_2a_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_10.png b/res/drawable-xhdpi/tv_2a_10.png
index 8f799344..5d3daf78 100644
--- a/res/drawable-xhdpi/tv_2a_10.png
+++ b/res/drawable-xhdpi/tv_2a_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_11.png b/res/drawable-xhdpi/tv_2a_11.png
index 35363c8c..1b7740aa 100644
--- a/res/drawable-xhdpi/tv_2a_11.png
+++ b/res/drawable-xhdpi/tv_2a_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_12.png b/res/drawable-xhdpi/tv_2a_12.png
index 107f41c3..d8a26f00 100644
--- a/res/drawable-xhdpi/tv_2a_12.png
+++ b/res/drawable-xhdpi/tv_2a_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_13.png b/res/drawable-xhdpi/tv_2a_13.png
index a59ae3a2..f847a055 100644
--- a/res/drawable-xhdpi/tv_2a_13.png
+++ b/res/drawable-xhdpi/tv_2a_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_14.png b/res/drawable-xhdpi/tv_2a_14.png
index 8e526d0c..7503a74e 100644
--- a/res/drawable-xhdpi/tv_2a_14.png
+++ b/res/drawable-xhdpi/tv_2a_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_15.png b/res/drawable-xhdpi/tv_2a_15.png
index 3d333b10..a03145e6 100644
--- a/res/drawable-xhdpi/tv_2a_15.png
+++ b/res/drawable-xhdpi/tv_2a_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_16.png b/res/drawable-xhdpi/tv_2a_16.png
index 0630e7e4..a2a12002 100644
--- a/res/drawable-xhdpi/tv_2a_16.png
+++ b/res/drawable-xhdpi/tv_2a_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_17.png b/res/drawable-xhdpi/tv_2a_17.png
index 9931e1f6..40d0a1a4 100644
--- a/res/drawable-xhdpi/tv_2a_17.png
+++ b/res/drawable-xhdpi/tv_2a_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_18.png b/res/drawable-xhdpi/tv_2a_18.png
index ac9998ac..28546661 100644
--- a/res/drawable-xhdpi/tv_2a_18.png
+++ b/res/drawable-xhdpi/tv_2a_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2a_19.png b/res/drawable-xhdpi/tv_2a_19.png
index a5404366..0bdaff25 100644
--- a/res/drawable-xhdpi/tv_2a_19.png
+++ b/res/drawable-xhdpi/tv_2a_19.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_01.png b/res/drawable-xhdpi/tv_2b_01.png
index a5404366..0bdaff25 100644
--- a/res/drawable-xhdpi/tv_2b_01.png
+++ b/res/drawable-xhdpi/tv_2b_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_02.png b/res/drawable-xhdpi/tv_2b_02.png
index f36adabb..5c4468f1 100644
--- a/res/drawable-xhdpi/tv_2b_02.png
+++ b/res/drawable-xhdpi/tv_2b_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_03.png b/res/drawable-xhdpi/tv_2b_03.png
index e2992701..de7f1869 100644
--- a/res/drawable-xhdpi/tv_2b_03.png
+++ b/res/drawable-xhdpi/tv_2b_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_04.png b/res/drawable-xhdpi/tv_2b_04.png
index 38bca733..879749af 100644
--- a/res/drawable-xhdpi/tv_2b_04.png
+++ b/res/drawable-xhdpi/tv_2b_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_05.png b/res/drawable-xhdpi/tv_2b_05.png
index fb93b9e1..3ae765c6 100644
--- a/res/drawable-xhdpi/tv_2b_05.png
+++ b/res/drawable-xhdpi/tv_2b_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_06.png b/res/drawable-xhdpi/tv_2b_06.png
index a54982ac..2e8e3717 100644
--- a/res/drawable-xhdpi/tv_2b_06.png
+++ b/res/drawable-xhdpi/tv_2b_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_07.png b/res/drawable-xhdpi/tv_2b_07.png
index c34896c8..bf0e9950 100644
--- a/res/drawable-xhdpi/tv_2b_07.png
+++ b/res/drawable-xhdpi/tv_2b_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_08.png b/res/drawable-xhdpi/tv_2b_08.png
index 41ef5d85..87b6a0ef 100644
--- a/res/drawable-xhdpi/tv_2b_08.png
+++ b/res/drawable-xhdpi/tv_2b_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_09.png b/res/drawable-xhdpi/tv_2b_09.png
index a050801a..6729728e 100644
--- a/res/drawable-xhdpi/tv_2b_09.png
+++ b/res/drawable-xhdpi/tv_2b_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_10.png b/res/drawable-xhdpi/tv_2b_10.png
index f3588436..e9e2b90d 100644
--- a/res/drawable-xhdpi/tv_2b_10.png
+++ b/res/drawable-xhdpi/tv_2b_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_11.png b/res/drawable-xhdpi/tv_2b_11.png
index b4de188f..af266e08 100644
--- a/res/drawable-xhdpi/tv_2b_11.png
+++ b/res/drawable-xhdpi/tv_2b_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_12.png b/res/drawable-xhdpi/tv_2b_12.png
index fb6846cd..d000df07 100644
--- a/res/drawable-xhdpi/tv_2b_12.png
+++ b/res/drawable-xhdpi/tv_2b_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_13.png b/res/drawable-xhdpi/tv_2b_13.png
index 85f70bba..52d272f1 100644
--- a/res/drawable-xhdpi/tv_2b_13.png
+++ b/res/drawable-xhdpi/tv_2b_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_14.png b/res/drawable-xhdpi/tv_2b_14.png
index e3a45e85..8b140ffb 100644
--- a/res/drawable-xhdpi/tv_2b_14.png
+++ b/res/drawable-xhdpi/tv_2b_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_15.png b/res/drawable-xhdpi/tv_2b_15.png
index 316e56bd..134a6ea8 100644
--- a/res/drawable-xhdpi/tv_2b_15.png
+++ b/res/drawable-xhdpi/tv_2b_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_16.png b/res/drawable-xhdpi/tv_2b_16.png
index bdf61e0d..9ed3512f 100644
--- a/res/drawable-xhdpi/tv_2b_16.png
+++ b/res/drawable-xhdpi/tv_2b_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_17.png b/res/drawable-xhdpi/tv_2b_17.png
index e6c5e655..2cf798c8 100644
--- a/res/drawable-xhdpi/tv_2b_17.png
+++ b/res/drawable-xhdpi/tv_2b_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_18.png b/res/drawable-xhdpi/tv_2b_18.png
index 7e0243f7..1c230064 100644
--- a/res/drawable-xhdpi/tv_2b_18.png
+++ b/res/drawable-xhdpi/tv_2b_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2b_19.png b/res/drawable-xhdpi/tv_2b_19.png
index 37a1c18a..aaa882b3 100644
--- a/res/drawable-xhdpi/tv_2b_19.png
+++ b/res/drawable-xhdpi/tv_2b_19.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_01.png b/res/drawable-xhdpi/tv_2c_01.png
index b4d30c33..b76fdc85 100644
--- a/res/drawable-xhdpi/tv_2c_01.png
+++ b/res/drawable-xhdpi/tv_2c_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_02.png b/res/drawable-xhdpi/tv_2c_02.png
index ed5cae6c..edd3a578 100644
--- a/res/drawable-xhdpi/tv_2c_02.png
+++ b/res/drawable-xhdpi/tv_2c_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_03.png b/res/drawable-xhdpi/tv_2c_03.png
index 4fb5b0f0..61ede2d0 100644
--- a/res/drawable-xhdpi/tv_2c_03.png
+++ b/res/drawable-xhdpi/tv_2c_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_04.png b/res/drawable-xhdpi/tv_2c_04.png
index b7897fb0..8eb9b6e8 100644
--- a/res/drawable-xhdpi/tv_2c_04.png
+++ b/res/drawable-xhdpi/tv_2c_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_05.png b/res/drawable-xhdpi/tv_2c_05.png
index 737cbc76..99838c92 100644
--- a/res/drawable-xhdpi/tv_2c_05.png
+++ b/res/drawable-xhdpi/tv_2c_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_06.png b/res/drawable-xhdpi/tv_2c_06.png
index c125734a..57c2f469 100644
--- a/res/drawable-xhdpi/tv_2c_06.png
+++ b/res/drawable-xhdpi/tv_2c_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_07.png b/res/drawable-xhdpi/tv_2c_07.png
index d6ada32b..91024a62 100644
--- a/res/drawable-xhdpi/tv_2c_07.png
+++ b/res/drawable-xhdpi/tv_2c_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_08.png b/res/drawable-xhdpi/tv_2c_08.png
index 0b8ac55c..5d57f965 100644
--- a/res/drawable-xhdpi/tv_2c_08.png
+++ b/res/drawable-xhdpi/tv_2c_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_09.png b/res/drawable-xhdpi/tv_2c_09.png
index bbc06a45..2b3748fb 100644
--- a/res/drawable-xhdpi/tv_2c_09.png
+++ b/res/drawable-xhdpi/tv_2c_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_10.png b/res/drawable-xhdpi/tv_2c_10.png
index b6ab1c68..ee1a1e36 100644
--- a/res/drawable-xhdpi/tv_2c_10.png
+++ b/res/drawable-xhdpi/tv_2c_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_11.png b/res/drawable-xhdpi/tv_2c_11.png
index 360379fc..9b74ba74 100644
--- a/res/drawable-xhdpi/tv_2c_11.png
+++ b/res/drawable-xhdpi/tv_2c_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_12.png b/res/drawable-xhdpi/tv_2c_12.png
index c10c1011..a3f266cf 100644
--- a/res/drawable-xhdpi/tv_2c_12.png
+++ b/res/drawable-xhdpi/tv_2c_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_13.png b/res/drawable-xhdpi/tv_2c_13.png
index 355a154b..63a764c4 100644
--- a/res/drawable-xhdpi/tv_2c_13.png
+++ b/res/drawable-xhdpi/tv_2c_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_14.png b/res/drawable-xhdpi/tv_2c_14.png
index bb9e767c..1548a6e7 100644
--- a/res/drawable-xhdpi/tv_2c_14.png
+++ b/res/drawable-xhdpi/tv_2c_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_15.png b/res/drawable-xhdpi/tv_2c_15.png
index bcf63ea1..0ec6414d 100644
--- a/res/drawable-xhdpi/tv_2c_15.png
+++ b/res/drawable-xhdpi/tv_2c_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_2c_16.png b/res/drawable-xhdpi/tv_2c_16.png
index 8bc794d3..a30842dd 100644
--- a/res/drawable-xhdpi/tv_2c_16.png
+++ b/res/drawable-xhdpi/tv_2c_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_00.png b/res/drawable-xhdpi/tv_3a_00.png
index d94b821f..ad8f256d 100644
--- a/res/drawable-xhdpi/tv_3a_00.png
+++ b/res/drawable-xhdpi/tv_3a_00.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_01.png b/res/drawable-xhdpi/tv_3a_01.png
index 39e0c908..e018df51 100644
--- a/res/drawable-xhdpi/tv_3a_01.png
+++ b/res/drawable-xhdpi/tv_3a_01.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_02.png b/res/drawable-xhdpi/tv_3a_02.png
index 8df97bf0..e2b93c34 100644
--- a/res/drawable-xhdpi/tv_3a_02.png
+++ b/res/drawable-xhdpi/tv_3a_02.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_03.png b/res/drawable-xhdpi/tv_3a_03.png
index c9225bda..9ff35c11 100644
--- a/res/drawable-xhdpi/tv_3a_03.png
+++ b/res/drawable-xhdpi/tv_3a_03.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_04.png b/res/drawable-xhdpi/tv_3a_04.png
index 878fcc54..1dfcde8c 100644
--- a/res/drawable-xhdpi/tv_3a_04.png
+++ b/res/drawable-xhdpi/tv_3a_04.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_05.png b/res/drawable-xhdpi/tv_3a_05.png
index d262d331..d459755a 100644
--- a/res/drawable-xhdpi/tv_3a_05.png
+++ b/res/drawable-xhdpi/tv_3a_05.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_06.png b/res/drawable-xhdpi/tv_3a_06.png
index a13b2883..fa9ab2f8 100644
--- a/res/drawable-xhdpi/tv_3a_06.png
+++ b/res/drawable-xhdpi/tv_3a_06.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_07.png b/res/drawable-xhdpi/tv_3a_07.png
index 48968d29..a6f8b9b6 100644
--- a/res/drawable-xhdpi/tv_3a_07.png
+++ b/res/drawable-xhdpi/tv_3a_07.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_08.png b/res/drawable-xhdpi/tv_3a_08.png
index 7b1f0e88..41587036 100644
--- a/res/drawable-xhdpi/tv_3a_08.png
+++ b/res/drawable-xhdpi/tv_3a_08.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_09.png b/res/drawable-xhdpi/tv_3a_09.png
index fbf5549a..270f8d79 100644
--- a/res/drawable-xhdpi/tv_3a_09.png
+++ b/res/drawable-xhdpi/tv_3a_09.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_10.png b/res/drawable-xhdpi/tv_3a_10.png
index 8c6869b5..6124be57 100644
--- a/res/drawable-xhdpi/tv_3a_10.png
+++ b/res/drawable-xhdpi/tv_3a_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_11.png b/res/drawable-xhdpi/tv_3a_11.png
index 42d8c4f1..1da80d0e 100644
--- a/res/drawable-xhdpi/tv_3a_11.png
+++ b/res/drawable-xhdpi/tv_3a_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_12.png b/res/drawable-xhdpi/tv_3a_12.png
index 347de0ca..b601c99e 100644
--- a/res/drawable-xhdpi/tv_3a_12.png
+++ b/res/drawable-xhdpi/tv_3a_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_13.png b/res/drawable-xhdpi/tv_3a_13.png
index b6fb3944..3bbb774d 100644
--- a/res/drawable-xhdpi/tv_3a_13.png
+++ b/res/drawable-xhdpi/tv_3a_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_14.png b/res/drawable-xhdpi/tv_3a_14.png
index 99290c1d..22e17458 100644
--- a/res/drawable-xhdpi/tv_3a_14.png
+++ b/res/drawable-xhdpi/tv_3a_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_15.png b/res/drawable-xhdpi/tv_3a_15.png
index 63cfdd82..9bb72b52 100644
--- a/res/drawable-xhdpi/tv_3a_15.png
+++ b/res/drawable-xhdpi/tv_3a_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_16.png b/res/drawable-xhdpi/tv_3a_16.png
index 41368eb0..e59cbde2 100644
--- a/res/drawable-xhdpi/tv_3a_16.png
+++ b/res/drawable-xhdpi/tv_3a_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3a_17.png b/res/drawable-xhdpi/tv_3a_17.png
index 93a22121..3faad68e 100644
--- a/res/drawable-xhdpi/tv_3a_17.png
+++ b/res/drawable-xhdpi/tv_3a_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_100.png b/res/drawable-xhdpi/tv_3b_100.png
index 92d9583e..05dbb29c 100644
--- a/res/drawable-xhdpi/tv_3b_100.png
+++ b/res/drawable-xhdpi/tv_3b_100.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_101.png b/res/drawable-xhdpi/tv_3b_101.png
index 9ccc088d..f89d72c9 100644
--- a/res/drawable-xhdpi/tv_3b_101.png
+++ b/res/drawable-xhdpi/tv_3b_101.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_102.png b/res/drawable-xhdpi/tv_3b_102.png
index 673d449e..46acde77 100644
--- a/res/drawable-xhdpi/tv_3b_102.png
+++ b/res/drawable-xhdpi/tv_3b_102.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_103.png b/res/drawable-xhdpi/tv_3b_103.png
index 3d3301f6..872c1031 100644
--- a/res/drawable-xhdpi/tv_3b_103.png
+++ b/res/drawable-xhdpi/tv_3b_103.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_104.png b/res/drawable-xhdpi/tv_3b_104.png
index f43893d3..3a00f9eb 100644
--- a/res/drawable-xhdpi/tv_3b_104.png
+++ b/res/drawable-xhdpi/tv_3b_104.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_105.png b/res/drawable-xhdpi/tv_3b_105.png
index a3afd81d..df79a861 100644
--- a/res/drawable-xhdpi/tv_3b_105.png
+++ b/res/drawable-xhdpi/tv_3b_105.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_106.png b/res/drawable-xhdpi/tv_3b_106.png
index 70a24db0..3345459e 100644
--- a/res/drawable-xhdpi/tv_3b_106.png
+++ b/res/drawable-xhdpi/tv_3b_106.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_107.png b/res/drawable-xhdpi/tv_3b_107.png
index 447e5bb1..bdeab425 100644
--- a/res/drawable-xhdpi/tv_3b_107.png
+++ b/res/drawable-xhdpi/tv_3b_107.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_108.png b/res/drawable-xhdpi/tv_3b_108.png
index e3dc0938..7dd2e706 100644
--- a/res/drawable-xhdpi/tv_3b_108.png
+++ b/res/drawable-xhdpi/tv_3b_108.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_109.png b/res/drawable-xhdpi/tv_3b_109.png
index 4d7f43a6..f1442a63 100644
--- a/res/drawable-xhdpi/tv_3b_109.png
+++ b/res/drawable-xhdpi/tv_3b_109.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_110.png b/res/drawable-xhdpi/tv_3b_110.png
index c2e4a62b..b1dbe330 100644
--- a/res/drawable-xhdpi/tv_3b_110.png
+++ b/res/drawable-xhdpi/tv_3b_110.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_111.png b/res/drawable-xhdpi/tv_3b_111.png
index 1690677a..b4de10d4 100644
--- a/res/drawable-xhdpi/tv_3b_111.png
+++ b/res/drawable-xhdpi/tv_3b_111.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_112.png b/res/drawable-xhdpi/tv_3b_112.png
index e40c9dab..7df0c81a 100644
--- a/res/drawable-xhdpi/tv_3b_112.png
+++ b/res/drawable-xhdpi/tv_3b_112.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_113.png b/res/drawable-xhdpi/tv_3b_113.png
index c399e7fe..c3938240 100644
--- a/res/drawable-xhdpi/tv_3b_113.png
+++ b/res/drawable-xhdpi/tv_3b_113.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_114.png b/res/drawable-xhdpi/tv_3b_114.png
index 9361a147..e4e9b2fb 100644
--- a/res/drawable-xhdpi/tv_3b_114.png
+++ b/res/drawable-xhdpi/tv_3b_114.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_115.png b/res/drawable-xhdpi/tv_3b_115.png
index 68284401..40590fff 100644
--- a/res/drawable-xhdpi/tv_3b_115.png
+++ b/res/drawable-xhdpi/tv_3b_115.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_116.png b/res/drawable-xhdpi/tv_3b_116.png
index 6bee0908..c998384c 100644
--- a/res/drawable-xhdpi/tv_3b_116.png
+++ b/res/drawable-xhdpi/tv_3b_116.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_117.png b/res/drawable-xhdpi/tv_3b_117.png
index 6a76da18..fb93500e 100644
--- a/res/drawable-xhdpi/tv_3b_117.png
+++ b/res/drawable-xhdpi/tv_3b_117.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_118.png b/res/drawable-xhdpi/tv_3b_118.png
index ac862425..37b6f3b7 100644
--- a/res/drawable-xhdpi/tv_3b_118.png
+++ b/res/drawable-xhdpi/tv_3b_118.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_75.png b/res/drawable-xhdpi/tv_3b_75.png
index 93a22121..3faad68e 100644
--- a/res/drawable-xhdpi/tv_3b_75.png
+++ b/res/drawable-xhdpi/tv_3b_75.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_76.png b/res/drawable-xhdpi/tv_3b_76.png
index 386720fd..8a0b63de 100644
--- a/res/drawable-xhdpi/tv_3b_76.png
+++ b/res/drawable-xhdpi/tv_3b_76.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_77.png b/res/drawable-xhdpi/tv_3b_77.png
index f51f6b4a..a9eb028c 100644
--- a/res/drawable-xhdpi/tv_3b_77.png
+++ b/res/drawable-xhdpi/tv_3b_77.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_78.png b/res/drawable-xhdpi/tv_3b_78.png
index 70fdb5a5..4f0dd172 100644
--- a/res/drawable-xhdpi/tv_3b_78.png
+++ b/res/drawable-xhdpi/tv_3b_78.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_79.png b/res/drawable-xhdpi/tv_3b_79.png
index 08bc451e..0d5596a7 100644
--- a/res/drawable-xhdpi/tv_3b_79.png
+++ b/res/drawable-xhdpi/tv_3b_79.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_80.png b/res/drawable-xhdpi/tv_3b_80.png
index 6939974c..c4ac7d37 100644
--- a/res/drawable-xhdpi/tv_3b_80.png
+++ b/res/drawable-xhdpi/tv_3b_80.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_81.png b/res/drawable-xhdpi/tv_3b_81.png
index 01637e4c..93718a04 100644
--- a/res/drawable-xhdpi/tv_3b_81.png
+++ b/res/drawable-xhdpi/tv_3b_81.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_82.png b/res/drawable-xhdpi/tv_3b_82.png
index bedf8fbf..04c116fd 100644
--- a/res/drawable-xhdpi/tv_3b_82.png
+++ b/res/drawable-xhdpi/tv_3b_82.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_83.png b/res/drawable-xhdpi/tv_3b_83.png
index 33cada16..b63b7516 100644
--- a/res/drawable-xhdpi/tv_3b_83.png
+++ b/res/drawable-xhdpi/tv_3b_83.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_84.png b/res/drawable-xhdpi/tv_3b_84.png
index 6ae91d91..580f6bc7 100644
--- a/res/drawable-xhdpi/tv_3b_84.png
+++ b/res/drawable-xhdpi/tv_3b_84.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_85.png b/res/drawable-xhdpi/tv_3b_85.png
index 556a2476..360afa1c 100644
--- a/res/drawable-xhdpi/tv_3b_85.png
+++ b/res/drawable-xhdpi/tv_3b_85.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_86.png b/res/drawable-xhdpi/tv_3b_86.png
index 80f8e853..cdfcf5cc 100644
--- a/res/drawable-xhdpi/tv_3b_86.png
+++ b/res/drawable-xhdpi/tv_3b_86.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_87.png b/res/drawable-xhdpi/tv_3b_87.png
index 1e080a13..138d6d37 100644
--- a/res/drawable-xhdpi/tv_3b_87.png
+++ b/res/drawable-xhdpi/tv_3b_87.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_88.png b/res/drawable-xhdpi/tv_3b_88.png
index b854bbde..21562493 100644
--- a/res/drawable-xhdpi/tv_3b_88.png
+++ b/res/drawable-xhdpi/tv_3b_88.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_89.png b/res/drawable-xhdpi/tv_3b_89.png
index f08383dd..30a908c1 100644
--- a/res/drawable-xhdpi/tv_3b_89.png
+++ b/res/drawable-xhdpi/tv_3b_89.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_90.png b/res/drawable-xhdpi/tv_3b_90.png
index ed54ef0f..ac06bb4b 100644
--- a/res/drawable-xhdpi/tv_3b_90.png
+++ b/res/drawable-xhdpi/tv_3b_90.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_91.png b/res/drawable-xhdpi/tv_3b_91.png
index e5c197d2..19848516 100644
--- a/res/drawable-xhdpi/tv_3b_91.png
+++ b/res/drawable-xhdpi/tv_3b_91.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_92.png b/res/drawable-xhdpi/tv_3b_92.png
index 100dd819..dbf1012b 100644
--- a/res/drawable-xhdpi/tv_3b_92.png
+++ b/res/drawable-xhdpi/tv_3b_92.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_93.png b/res/drawable-xhdpi/tv_3b_93.png
index cf8909b3..fac169dc 100644
--- a/res/drawable-xhdpi/tv_3b_93.png
+++ b/res/drawable-xhdpi/tv_3b_93.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_94.png b/res/drawable-xhdpi/tv_3b_94.png
index 613157b4..55e4f48a 100644
--- a/res/drawable-xhdpi/tv_3b_94.png
+++ b/res/drawable-xhdpi/tv_3b_94.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_95.png b/res/drawable-xhdpi/tv_3b_95.png
index 9bab3a86..4196da12 100644
--- a/res/drawable-xhdpi/tv_3b_95.png
+++ b/res/drawable-xhdpi/tv_3b_95.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_96.png b/res/drawable-xhdpi/tv_3b_96.png
index 956adf4e..96d9eee3 100644
--- a/res/drawable-xhdpi/tv_3b_96.png
+++ b/res/drawable-xhdpi/tv_3b_96.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_97.png b/res/drawable-xhdpi/tv_3b_97.png
index ac703d32..82e92f23 100644
--- a/res/drawable-xhdpi/tv_3b_97.png
+++ b/res/drawable-xhdpi/tv_3b_97.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_98.png b/res/drawable-xhdpi/tv_3b_98.png
index 2522c668..8a6784fc 100644
--- a/res/drawable-xhdpi/tv_3b_98.png
+++ b/res/drawable-xhdpi/tv_3b_98.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_3b_99.png b/res/drawable-xhdpi/tv_3b_99.png
index f8d21d2f..5a308f91 100644
--- a/res/drawable-xhdpi/tv_3b_99.png
+++ b/res/drawable-xhdpi/tv_3b_99.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_1.png b/res/drawable-xhdpi/tv_5a_1.png
index 9cc9fa3e..14d6cb1b 100644
--- a/res/drawable-xhdpi/tv_5a_1.png
+++ b/res/drawable-xhdpi/tv_5a_1.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_10.png b/res/drawable-xhdpi/tv_5a_10.png
index 38b9d484..e1d28897 100644
--- a/res/drawable-xhdpi/tv_5a_10.png
+++ b/res/drawable-xhdpi/tv_5a_10.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_100.png b/res/drawable-xhdpi/tv_5a_100.png
index 8ed2652b..4815523c 100644
--- a/res/drawable-xhdpi/tv_5a_100.png
+++ b/res/drawable-xhdpi/tv_5a_100.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_101.png b/res/drawable-xhdpi/tv_5a_101.png
index 07e22d1b..a2e33138 100644
--- a/res/drawable-xhdpi/tv_5a_101.png
+++ b/res/drawable-xhdpi/tv_5a_101.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_102.png b/res/drawable-xhdpi/tv_5a_102.png
index cc24e4d0..7fc28355 100644
--- a/res/drawable-xhdpi/tv_5a_102.png
+++ b/res/drawable-xhdpi/tv_5a_102.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_103.png b/res/drawable-xhdpi/tv_5a_103.png
index 76a1924e..cf60b811 100644
--- a/res/drawable-xhdpi/tv_5a_103.png
+++ b/res/drawable-xhdpi/tv_5a_103.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_104.png b/res/drawable-xhdpi/tv_5a_104.png
index f5b47313..4d069b91 100644
--- a/res/drawable-xhdpi/tv_5a_104.png
+++ b/res/drawable-xhdpi/tv_5a_104.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_105.png b/res/drawable-xhdpi/tv_5a_105.png
index 23050cf8..5d92e53c 100644
--- a/res/drawable-xhdpi/tv_5a_105.png
+++ b/res/drawable-xhdpi/tv_5a_105.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_106.png b/res/drawable-xhdpi/tv_5a_106.png
index e2e80bf6..ed63632b 100644
--- a/res/drawable-xhdpi/tv_5a_106.png
+++ b/res/drawable-xhdpi/tv_5a_106.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_107.png b/res/drawable-xhdpi/tv_5a_107.png
index d992438d..828f0bda 100644
--- a/res/drawable-xhdpi/tv_5a_107.png
+++ b/res/drawable-xhdpi/tv_5a_107.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_108.png b/res/drawable-xhdpi/tv_5a_108.png
index 55ea31b0..e146476e 100644
--- a/res/drawable-xhdpi/tv_5a_108.png
+++ b/res/drawable-xhdpi/tv_5a_108.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_109.png b/res/drawable-xhdpi/tv_5a_109.png
index 176e044f..a2de015a 100644
--- a/res/drawable-xhdpi/tv_5a_109.png
+++ b/res/drawable-xhdpi/tv_5a_109.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_11.png b/res/drawable-xhdpi/tv_5a_11.png
index 44916dde..e15a4884 100644
--- a/res/drawable-xhdpi/tv_5a_11.png
+++ b/res/drawable-xhdpi/tv_5a_11.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_110.png b/res/drawable-xhdpi/tv_5a_110.png
index 2cad75ab..ba7a062a 100644
--- a/res/drawable-xhdpi/tv_5a_110.png
+++ b/res/drawable-xhdpi/tv_5a_110.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_111.png b/res/drawable-xhdpi/tv_5a_111.png
index 9ac668f0..9c73e146 100644
--- a/res/drawable-xhdpi/tv_5a_111.png
+++ b/res/drawable-xhdpi/tv_5a_111.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_112.png b/res/drawable-xhdpi/tv_5a_112.png
index e47141c8..ff25996a 100644
--- a/res/drawable-xhdpi/tv_5a_112.png
+++ b/res/drawable-xhdpi/tv_5a_112.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_113.png b/res/drawable-xhdpi/tv_5a_113.png
index bba837a9..e0f5976e 100644
--- a/res/drawable-xhdpi/tv_5a_113.png
+++ b/res/drawable-xhdpi/tv_5a_113.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_114.png b/res/drawable-xhdpi/tv_5a_114.png
index e9ae154e..6cbbe628 100644
--- a/res/drawable-xhdpi/tv_5a_114.png
+++ b/res/drawable-xhdpi/tv_5a_114.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_115.png b/res/drawable-xhdpi/tv_5a_115.png
index 02576883..91ee15f4 100644
--- a/res/drawable-xhdpi/tv_5a_115.png
+++ b/res/drawable-xhdpi/tv_5a_115.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_116.png b/res/drawable-xhdpi/tv_5a_116.png
index e5790b52..07773c43 100644
--- a/res/drawable-xhdpi/tv_5a_116.png
+++ b/res/drawable-xhdpi/tv_5a_116.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_117.png b/res/drawable-xhdpi/tv_5a_117.png
index 905c1f82..e380bb5b 100644
--- a/res/drawable-xhdpi/tv_5a_117.png
+++ b/res/drawable-xhdpi/tv_5a_117.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_118.png b/res/drawable-xhdpi/tv_5a_118.png
index 41368661..7b02a8ec 100644
--- a/res/drawable-xhdpi/tv_5a_118.png
+++ b/res/drawable-xhdpi/tv_5a_118.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_119.png b/res/drawable-xhdpi/tv_5a_119.png
index 1f18d2e7..5f6ecb25 100644
--- a/res/drawable-xhdpi/tv_5a_119.png
+++ b/res/drawable-xhdpi/tv_5a_119.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_12.png b/res/drawable-xhdpi/tv_5a_12.png
index fce782ab..3d781aff 100644
--- a/res/drawable-xhdpi/tv_5a_12.png
+++ b/res/drawable-xhdpi/tv_5a_12.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_120.png b/res/drawable-xhdpi/tv_5a_120.png
index 1f15afa9..ccb823ce 100644
--- a/res/drawable-xhdpi/tv_5a_120.png
+++ b/res/drawable-xhdpi/tv_5a_120.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_121.png b/res/drawable-xhdpi/tv_5a_121.png
index 774c7c01..e47d2c4c 100644
--- a/res/drawable-xhdpi/tv_5a_121.png
+++ b/res/drawable-xhdpi/tv_5a_121.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_122.png b/res/drawable-xhdpi/tv_5a_122.png
index b1423dca..6ef694ac 100644
--- a/res/drawable-xhdpi/tv_5a_122.png
+++ b/res/drawable-xhdpi/tv_5a_122.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_123.png b/res/drawable-xhdpi/tv_5a_123.png
index 39121f4f..587e8c98 100644
--- a/res/drawable-xhdpi/tv_5a_123.png
+++ b/res/drawable-xhdpi/tv_5a_123.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_124.png b/res/drawable-xhdpi/tv_5a_124.png
index 4cd4b2d0..d3ab882c 100644
--- a/res/drawable-xhdpi/tv_5a_124.png
+++ b/res/drawable-xhdpi/tv_5a_124.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_125.png b/res/drawable-xhdpi/tv_5a_125.png
index dfdcfa9e..ce153872 100644
--- a/res/drawable-xhdpi/tv_5a_125.png
+++ b/res/drawable-xhdpi/tv_5a_125.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_126.png b/res/drawable-xhdpi/tv_5a_126.png
index 843257af..5162e697 100644
--- a/res/drawable-xhdpi/tv_5a_126.png
+++ b/res/drawable-xhdpi/tv_5a_126.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_127.png b/res/drawable-xhdpi/tv_5a_127.png
index b476e46a..13bc2134 100644
--- a/res/drawable-xhdpi/tv_5a_127.png
+++ b/res/drawable-xhdpi/tv_5a_127.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_128.png b/res/drawable-xhdpi/tv_5a_128.png
index f3035b35..91be8872 100644
--- a/res/drawable-xhdpi/tv_5a_128.png
+++ b/res/drawable-xhdpi/tv_5a_128.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_129.png b/res/drawable-xhdpi/tv_5a_129.png
index 538eb014..49a4c942 100644
--- a/res/drawable-xhdpi/tv_5a_129.png
+++ b/res/drawable-xhdpi/tv_5a_129.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_13.png b/res/drawable-xhdpi/tv_5a_13.png
index e17b230c..a9c9bb53 100644
--- a/res/drawable-xhdpi/tv_5a_13.png
+++ b/res/drawable-xhdpi/tv_5a_13.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_130.png b/res/drawable-xhdpi/tv_5a_130.png
index 925495e8..8af38ca5 100644
--- a/res/drawable-xhdpi/tv_5a_130.png
+++ b/res/drawable-xhdpi/tv_5a_130.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_131.png b/res/drawable-xhdpi/tv_5a_131.png
index 9635a451..6bbc8018 100644
--- a/res/drawable-xhdpi/tv_5a_131.png
+++ b/res/drawable-xhdpi/tv_5a_131.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_132.png b/res/drawable-xhdpi/tv_5a_132.png
index 8b43bb56..9934e276 100644
--- a/res/drawable-xhdpi/tv_5a_132.png
+++ b/res/drawable-xhdpi/tv_5a_132.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_133.png b/res/drawable-xhdpi/tv_5a_133.png
index a19c7086..371e07a4 100644
--- a/res/drawable-xhdpi/tv_5a_133.png
+++ b/res/drawable-xhdpi/tv_5a_133.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_134.png b/res/drawable-xhdpi/tv_5a_134.png
index a751a957..3c1c219d 100644
--- a/res/drawable-xhdpi/tv_5a_134.png
+++ b/res/drawable-xhdpi/tv_5a_134.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_135.png b/res/drawable-xhdpi/tv_5a_135.png
index 31cc274e..15c0a48e 100644
--- a/res/drawable-xhdpi/tv_5a_135.png
+++ b/res/drawable-xhdpi/tv_5a_135.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_136.png b/res/drawable-xhdpi/tv_5a_136.png
index f3279a46..3c1ef38a 100644
--- a/res/drawable-xhdpi/tv_5a_136.png
+++ b/res/drawable-xhdpi/tv_5a_136.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_137.png b/res/drawable-xhdpi/tv_5a_137.png
index 8d790220..5d36c581 100644
--- a/res/drawable-xhdpi/tv_5a_137.png
+++ b/res/drawable-xhdpi/tv_5a_137.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_138.png b/res/drawable-xhdpi/tv_5a_138.png
index 6ab3d5cb..a731ef66 100644
--- a/res/drawable-xhdpi/tv_5a_138.png
+++ b/res/drawable-xhdpi/tv_5a_138.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_139.png b/res/drawable-xhdpi/tv_5a_139.png
index 909dff91..8958aa2c 100644
--- a/res/drawable-xhdpi/tv_5a_139.png
+++ b/res/drawable-xhdpi/tv_5a_139.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_14.png b/res/drawable-xhdpi/tv_5a_14.png
index 9bc86099..e2805814 100644
--- a/res/drawable-xhdpi/tv_5a_14.png
+++ b/res/drawable-xhdpi/tv_5a_14.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_140.png b/res/drawable-xhdpi/tv_5a_140.png
index 09775707..5fc33b72 100644
--- a/res/drawable-xhdpi/tv_5a_140.png
+++ b/res/drawable-xhdpi/tv_5a_140.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_141.png b/res/drawable-xhdpi/tv_5a_141.png
index 20fedcf6..c213b093 100644
--- a/res/drawable-xhdpi/tv_5a_141.png
+++ b/res/drawable-xhdpi/tv_5a_141.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_142.png b/res/drawable-xhdpi/tv_5a_142.png
index 2475ee01..d2d85077 100644
--- a/res/drawable-xhdpi/tv_5a_142.png
+++ b/res/drawable-xhdpi/tv_5a_142.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_143.png b/res/drawable-xhdpi/tv_5a_143.png
index 11eb54fa..9cf8e4e6 100644
--- a/res/drawable-xhdpi/tv_5a_143.png
+++ b/res/drawable-xhdpi/tv_5a_143.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_144.png b/res/drawable-xhdpi/tv_5a_144.png
index cc2d5003..8deb2cc6 100644
--- a/res/drawable-xhdpi/tv_5a_144.png
+++ b/res/drawable-xhdpi/tv_5a_144.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_145.png b/res/drawable-xhdpi/tv_5a_145.png
index 6916f6ed..895b0c0a 100644
--- a/res/drawable-xhdpi/tv_5a_145.png
+++ b/res/drawable-xhdpi/tv_5a_145.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_146.png b/res/drawable-xhdpi/tv_5a_146.png
index 5858da84..05fc7075 100644
--- a/res/drawable-xhdpi/tv_5a_146.png
+++ b/res/drawable-xhdpi/tv_5a_146.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_147.png b/res/drawable-xhdpi/tv_5a_147.png
index 2a027432..d78cde50 100644
--- a/res/drawable-xhdpi/tv_5a_147.png
+++ b/res/drawable-xhdpi/tv_5a_147.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_148.png b/res/drawable-xhdpi/tv_5a_148.png
index e3a1c3f8..4a32382d 100644
--- a/res/drawable-xhdpi/tv_5a_148.png
+++ b/res/drawable-xhdpi/tv_5a_148.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_149.png b/res/drawable-xhdpi/tv_5a_149.png
index 0f1ec7bc..8473ab38 100644
--- a/res/drawable-xhdpi/tv_5a_149.png
+++ b/res/drawable-xhdpi/tv_5a_149.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_15.png b/res/drawable-xhdpi/tv_5a_15.png
index 02b2dd2e..1b798e33 100644
--- a/res/drawable-xhdpi/tv_5a_15.png
+++ b/res/drawable-xhdpi/tv_5a_15.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_150.png b/res/drawable-xhdpi/tv_5a_150.png
index ece4ebcc..62d469c8 100644
--- a/res/drawable-xhdpi/tv_5a_150.png
+++ b/res/drawable-xhdpi/tv_5a_150.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_151.png b/res/drawable-xhdpi/tv_5a_151.png
index b58cd0a8..8535b479 100644
--- a/res/drawable-xhdpi/tv_5a_151.png
+++ b/res/drawable-xhdpi/tv_5a_151.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_152.png b/res/drawable-xhdpi/tv_5a_152.png
index c4f82ab8..4c48dcdf 100644
--- a/res/drawable-xhdpi/tv_5a_152.png
+++ b/res/drawable-xhdpi/tv_5a_152.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_153.png b/res/drawable-xhdpi/tv_5a_153.png
index 32dbc075..491b1702 100644
--- a/res/drawable-xhdpi/tv_5a_153.png
+++ b/res/drawable-xhdpi/tv_5a_153.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_154.png b/res/drawable-xhdpi/tv_5a_154.png
index 64c12438..2eeadefd 100644
--- a/res/drawable-xhdpi/tv_5a_154.png
+++ b/res/drawable-xhdpi/tv_5a_154.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_155.png b/res/drawable-xhdpi/tv_5a_155.png
index 512b61c8..56b79721 100644
--- a/res/drawable-xhdpi/tv_5a_155.png
+++ b/res/drawable-xhdpi/tv_5a_155.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_156.png b/res/drawable-xhdpi/tv_5a_156.png
index 3b88a6c9..27e17f36 100644
--- a/res/drawable-xhdpi/tv_5a_156.png
+++ b/res/drawable-xhdpi/tv_5a_156.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_157.png b/res/drawable-xhdpi/tv_5a_157.png
index a6efdc3d..345501ce 100644
--- a/res/drawable-xhdpi/tv_5a_157.png
+++ b/res/drawable-xhdpi/tv_5a_157.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_158.png b/res/drawable-xhdpi/tv_5a_158.png
index 7e8e2895..17938dbc 100644
--- a/res/drawable-xhdpi/tv_5a_158.png
+++ b/res/drawable-xhdpi/tv_5a_158.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_159.png b/res/drawable-xhdpi/tv_5a_159.png
index ece0a2e6..16f2c6ef 100644
--- a/res/drawable-xhdpi/tv_5a_159.png
+++ b/res/drawable-xhdpi/tv_5a_159.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_16.png b/res/drawable-xhdpi/tv_5a_16.png
index 1c698441..c613f64f 100644
--- a/res/drawable-xhdpi/tv_5a_16.png
+++ b/res/drawable-xhdpi/tv_5a_16.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_160.png b/res/drawable-xhdpi/tv_5a_160.png
index 6e0104ff..8276e924 100644
--- a/res/drawable-xhdpi/tv_5a_160.png
+++ b/res/drawable-xhdpi/tv_5a_160.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_161.png b/res/drawable-xhdpi/tv_5a_161.png
index d48b5af3..fcfa08a5 100644
--- a/res/drawable-xhdpi/tv_5a_161.png
+++ b/res/drawable-xhdpi/tv_5a_161.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_162.png b/res/drawable-xhdpi/tv_5a_162.png
index 7723103f..45e6840f 100644
--- a/res/drawable-xhdpi/tv_5a_162.png
+++ b/res/drawable-xhdpi/tv_5a_162.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_163.png b/res/drawable-xhdpi/tv_5a_163.png
index 18b048ee..3eb76cbb 100644
--- a/res/drawable-xhdpi/tv_5a_163.png
+++ b/res/drawable-xhdpi/tv_5a_163.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_164.png b/res/drawable-xhdpi/tv_5a_164.png
index eee70024..d8f4f219 100644
--- a/res/drawable-xhdpi/tv_5a_164.png
+++ b/res/drawable-xhdpi/tv_5a_164.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_165.png b/res/drawable-xhdpi/tv_5a_165.png
index 1f81c761..15d7a056 100644
--- a/res/drawable-xhdpi/tv_5a_165.png
+++ b/res/drawable-xhdpi/tv_5a_165.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_166.png b/res/drawable-xhdpi/tv_5a_166.png
index 1bc5513e..1f2e8298 100644
--- a/res/drawable-xhdpi/tv_5a_166.png
+++ b/res/drawable-xhdpi/tv_5a_166.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_167.png b/res/drawable-xhdpi/tv_5a_167.png
index 95f60956..64e0c38e 100644
--- a/res/drawable-xhdpi/tv_5a_167.png
+++ b/res/drawable-xhdpi/tv_5a_167.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_168.png b/res/drawable-xhdpi/tv_5a_168.png
index d4647df7..0917f531 100644
--- a/res/drawable-xhdpi/tv_5a_168.png
+++ b/res/drawable-xhdpi/tv_5a_168.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_169.png b/res/drawable-xhdpi/tv_5a_169.png
index 98401ba8..9ed66682 100644
--- a/res/drawable-xhdpi/tv_5a_169.png
+++ b/res/drawable-xhdpi/tv_5a_169.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_17.png b/res/drawable-xhdpi/tv_5a_17.png
index 1c6af939..5a9d4b02 100644
--- a/res/drawable-xhdpi/tv_5a_17.png
+++ b/res/drawable-xhdpi/tv_5a_17.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_170.png b/res/drawable-xhdpi/tv_5a_170.png
index 10dd5b06..f4d37883 100644
--- a/res/drawable-xhdpi/tv_5a_170.png
+++ b/res/drawable-xhdpi/tv_5a_170.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_171.png b/res/drawable-xhdpi/tv_5a_171.png
index 37a66d13..3ec0de0b 100644
--- a/res/drawable-xhdpi/tv_5a_171.png
+++ b/res/drawable-xhdpi/tv_5a_171.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_172.png b/res/drawable-xhdpi/tv_5a_172.png
index 8d492a15..d514c014 100644
--- a/res/drawable-xhdpi/tv_5a_172.png
+++ b/res/drawable-xhdpi/tv_5a_172.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_173.png b/res/drawable-xhdpi/tv_5a_173.png
index 70af1a45..3ac3776d 100644
--- a/res/drawable-xhdpi/tv_5a_173.png
+++ b/res/drawable-xhdpi/tv_5a_173.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_174.png b/res/drawable-xhdpi/tv_5a_174.png
index 8ddeca3a..151370d3 100644
--- a/res/drawable-xhdpi/tv_5a_174.png
+++ b/res/drawable-xhdpi/tv_5a_174.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_175.png b/res/drawable-xhdpi/tv_5a_175.png
index e65e6bc2..ebdd1b9c 100644
--- a/res/drawable-xhdpi/tv_5a_175.png
+++ b/res/drawable-xhdpi/tv_5a_175.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_176.png b/res/drawable-xhdpi/tv_5a_176.png
index b40d9b3b..77ad4e8c 100644
--- a/res/drawable-xhdpi/tv_5a_176.png
+++ b/res/drawable-xhdpi/tv_5a_176.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_177.png b/res/drawable-xhdpi/tv_5a_177.png
index 403234a6..a3c892fd 100644
--- a/res/drawable-xhdpi/tv_5a_177.png
+++ b/res/drawable-xhdpi/tv_5a_177.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_178.png b/res/drawable-xhdpi/tv_5a_178.png
index 2687abd8..b6c6fded 100644
--- a/res/drawable-xhdpi/tv_5a_178.png
+++ b/res/drawable-xhdpi/tv_5a_178.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_179.png b/res/drawable-xhdpi/tv_5a_179.png
index 137d697b..f3e643c7 100644
--- a/res/drawable-xhdpi/tv_5a_179.png
+++ b/res/drawable-xhdpi/tv_5a_179.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_18.png b/res/drawable-xhdpi/tv_5a_18.png
index 977bbe50..7f28c5d4 100644
--- a/res/drawable-xhdpi/tv_5a_18.png
+++ b/res/drawable-xhdpi/tv_5a_18.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_180.png b/res/drawable-xhdpi/tv_5a_180.png
index d2fc5656..821768ed 100644
--- a/res/drawable-xhdpi/tv_5a_180.png
+++ b/res/drawable-xhdpi/tv_5a_180.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_181.png b/res/drawable-xhdpi/tv_5a_181.png
index 145f92ec..6d2a1cbe 100644
--- a/res/drawable-xhdpi/tv_5a_181.png
+++ b/res/drawable-xhdpi/tv_5a_181.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_182.png b/res/drawable-xhdpi/tv_5a_182.png
index 24b78db1..65ad16f9 100644
--- a/res/drawable-xhdpi/tv_5a_182.png
+++ b/res/drawable-xhdpi/tv_5a_182.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_183.png b/res/drawable-xhdpi/tv_5a_183.png
index 36ab2cea..a8a043a8 100644
--- a/res/drawable-xhdpi/tv_5a_183.png
+++ b/res/drawable-xhdpi/tv_5a_183.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_184.png b/res/drawable-xhdpi/tv_5a_184.png
index bc6a5ea1..a52a749d 100644
--- a/res/drawable-xhdpi/tv_5a_184.png
+++ b/res/drawable-xhdpi/tv_5a_184.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_185.png b/res/drawable-xhdpi/tv_5a_185.png
index 926adde7..4304a690 100644
--- a/res/drawable-xhdpi/tv_5a_185.png
+++ b/res/drawable-xhdpi/tv_5a_185.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_186.png b/res/drawable-xhdpi/tv_5a_186.png
index 36418764..9871d55c 100644
--- a/res/drawable-xhdpi/tv_5a_186.png
+++ b/res/drawable-xhdpi/tv_5a_186.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_187.png b/res/drawable-xhdpi/tv_5a_187.png
index ca07a19c..4653cc1f 100644
--- a/res/drawable-xhdpi/tv_5a_187.png
+++ b/res/drawable-xhdpi/tv_5a_187.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_188.png b/res/drawable-xhdpi/tv_5a_188.png
index 1c9ecdea..08f44331 100644
--- a/res/drawable-xhdpi/tv_5a_188.png
+++ b/res/drawable-xhdpi/tv_5a_188.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_189.png b/res/drawable-xhdpi/tv_5a_189.png
index 1147f390..002e3521 100644
--- a/res/drawable-xhdpi/tv_5a_189.png
+++ b/res/drawable-xhdpi/tv_5a_189.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_19.png b/res/drawable-xhdpi/tv_5a_19.png
index 7bfad09d..90c0704e 100644
--- a/res/drawable-xhdpi/tv_5a_19.png
+++ b/res/drawable-xhdpi/tv_5a_19.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_190.png b/res/drawable-xhdpi/tv_5a_190.png
index 71b00ec1..f4ca0c90 100644
--- a/res/drawable-xhdpi/tv_5a_190.png
+++ b/res/drawable-xhdpi/tv_5a_190.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_191.png b/res/drawable-xhdpi/tv_5a_191.png
index 9c19b818..534cbdbe 100644
--- a/res/drawable-xhdpi/tv_5a_191.png
+++ b/res/drawable-xhdpi/tv_5a_191.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_192.png b/res/drawable-xhdpi/tv_5a_192.png
index 0da98bf1..7b5937d3 100644
--- a/res/drawable-xhdpi/tv_5a_192.png
+++ b/res/drawable-xhdpi/tv_5a_192.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_193.png b/res/drawable-xhdpi/tv_5a_193.png
index 030df5ab..bf00c5e8 100644
--- a/res/drawable-xhdpi/tv_5a_193.png
+++ b/res/drawable-xhdpi/tv_5a_193.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_194.png b/res/drawable-xhdpi/tv_5a_194.png
index 6e424508..2e6348e3 100644
--- a/res/drawable-xhdpi/tv_5a_194.png
+++ b/res/drawable-xhdpi/tv_5a_194.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_195.png b/res/drawable-xhdpi/tv_5a_195.png
index d2c5c3f0..035a229e 100644
--- a/res/drawable-xhdpi/tv_5a_195.png
+++ b/res/drawable-xhdpi/tv_5a_195.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_196.png b/res/drawable-xhdpi/tv_5a_196.png
index 8f273f36..32cbd20f 100644
--- a/res/drawable-xhdpi/tv_5a_196.png
+++ b/res/drawable-xhdpi/tv_5a_196.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_197.png b/res/drawable-xhdpi/tv_5a_197.png
index 6408bffe..7ce50b64 100644
--- a/res/drawable-xhdpi/tv_5a_197.png
+++ b/res/drawable-xhdpi/tv_5a_197.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_198.png b/res/drawable-xhdpi/tv_5a_198.png
index ed5383a4..8ad657f9 100644
--- a/res/drawable-xhdpi/tv_5a_198.png
+++ b/res/drawable-xhdpi/tv_5a_198.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_199.png b/res/drawable-xhdpi/tv_5a_199.png
index 80435ca4..e035151d 100644
--- a/res/drawable-xhdpi/tv_5a_199.png
+++ b/res/drawable-xhdpi/tv_5a_199.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_2.png b/res/drawable-xhdpi/tv_5a_2.png
index 89da06ff..63e56934 100644
--- a/res/drawable-xhdpi/tv_5a_2.png
+++ b/res/drawable-xhdpi/tv_5a_2.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_20.png b/res/drawable-xhdpi/tv_5a_20.png
index 198beeb2..e96b0235 100644
--- a/res/drawable-xhdpi/tv_5a_20.png
+++ b/res/drawable-xhdpi/tv_5a_20.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_200.png b/res/drawable-xhdpi/tv_5a_200.png
index 1f64389f..8f198461 100644
--- a/res/drawable-xhdpi/tv_5a_200.png
+++ b/res/drawable-xhdpi/tv_5a_200.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_201.png b/res/drawable-xhdpi/tv_5a_201.png
index 2e662da6..b03b04e4 100644
--- a/res/drawable-xhdpi/tv_5a_201.png
+++ b/res/drawable-xhdpi/tv_5a_201.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_202.png b/res/drawable-xhdpi/tv_5a_202.png
index 47bee69c..7da5d815 100644
--- a/res/drawable-xhdpi/tv_5a_202.png
+++ b/res/drawable-xhdpi/tv_5a_202.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_203.png b/res/drawable-xhdpi/tv_5a_203.png
index 02ef3b46..77eaaf63 100644
--- a/res/drawable-xhdpi/tv_5a_203.png
+++ b/res/drawable-xhdpi/tv_5a_203.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_204.png b/res/drawable-xhdpi/tv_5a_204.png
index fc6bee1c..30a32018 100644
--- a/res/drawable-xhdpi/tv_5a_204.png
+++ b/res/drawable-xhdpi/tv_5a_204.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_205.png b/res/drawable-xhdpi/tv_5a_205.png
index 8b2830e2..a9e91ffa 100644
--- a/res/drawable-xhdpi/tv_5a_205.png
+++ b/res/drawable-xhdpi/tv_5a_205.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_206.png b/res/drawable-xhdpi/tv_5a_206.png
index 79092421..9e02950a 100644
--- a/res/drawable-xhdpi/tv_5a_206.png
+++ b/res/drawable-xhdpi/tv_5a_206.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_207.png b/res/drawable-xhdpi/tv_5a_207.png
index 8158112f..1a928157 100644
--- a/res/drawable-xhdpi/tv_5a_207.png
+++ b/res/drawable-xhdpi/tv_5a_207.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_208.png b/res/drawable-xhdpi/tv_5a_208.png
index bb9cd2ef..babffa54 100644
--- a/res/drawable-xhdpi/tv_5a_208.png
+++ b/res/drawable-xhdpi/tv_5a_208.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_209.png b/res/drawable-xhdpi/tv_5a_209.png
index bc4895db..bef3cd49 100644
--- a/res/drawable-xhdpi/tv_5a_209.png
+++ b/res/drawable-xhdpi/tv_5a_209.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_21.png b/res/drawable-xhdpi/tv_5a_21.png
index 90da19a6..fc40e7a2 100644
--- a/res/drawable-xhdpi/tv_5a_21.png
+++ b/res/drawable-xhdpi/tv_5a_21.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_210.png b/res/drawable-xhdpi/tv_5a_210.png
index b076fa0b..5a7e118a 100644
--- a/res/drawable-xhdpi/tv_5a_210.png
+++ b/res/drawable-xhdpi/tv_5a_210.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_211.png b/res/drawable-xhdpi/tv_5a_211.png
index 425b056a..f302b612 100644
--- a/res/drawable-xhdpi/tv_5a_211.png
+++ b/res/drawable-xhdpi/tv_5a_211.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_212.png b/res/drawable-xhdpi/tv_5a_212.png
index 7114ac8c..e8a80ea4 100644
--- a/res/drawable-xhdpi/tv_5a_212.png
+++ b/res/drawable-xhdpi/tv_5a_212.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_213.png b/res/drawable-xhdpi/tv_5a_213.png
index 2fc84caf..816d777c 100644
--- a/res/drawable-xhdpi/tv_5a_213.png
+++ b/res/drawable-xhdpi/tv_5a_213.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_214.png b/res/drawable-xhdpi/tv_5a_214.png
index 44d5bc01..a5f3d015 100644
--- a/res/drawable-xhdpi/tv_5a_214.png
+++ b/res/drawable-xhdpi/tv_5a_214.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_215.png b/res/drawable-xhdpi/tv_5a_215.png
index 80c0edaf..c621033f 100644
--- a/res/drawable-xhdpi/tv_5a_215.png
+++ b/res/drawable-xhdpi/tv_5a_215.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_216.png b/res/drawable-xhdpi/tv_5a_216.png
index 18c9228e..9733b9d6 100644
--- a/res/drawable-xhdpi/tv_5a_216.png
+++ b/res/drawable-xhdpi/tv_5a_216.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_217.png b/res/drawable-xhdpi/tv_5a_217.png
index f6455864..a50e4078 100644
--- a/res/drawable-xhdpi/tv_5a_217.png
+++ b/res/drawable-xhdpi/tv_5a_217.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_218.png b/res/drawable-xhdpi/tv_5a_218.png
index 4efeb59d..0419d7ea 100644
--- a/res/drawable-xhdpi/tv_5a_218.png
+++ b/res/drawable-xhdpi/tv_5a_218.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_219.png b/res/drawable-xhdpi/tv_5a_219.png
index b5bb59e2..2c8b96cd 100644
--- a/res/drawable-xhdpi/tv_5a_219.png
+++ b/res/drawable-xhdpi/tv_5a_219.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_22.png b/res/drawable-xhdpi/tv_5a_22.png
index d825b30d..0a46fe4c 100644
--- a/res/drawable-xhdpi/tv_5a_22.png
+++ b/res/drawable-xhdpi/tv_5a_22.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_220.png b/res/drawable-xhdpi/tv_5a_220.png
index b6738f44..c8660d67 100644
--- a/res/drawable-xhdpi/tv_5a_220.png
+++ b/res/drawable-xhdpi/tv_5a_220.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_221.png b/res/drawable-xhdpi/tv_5a_221.png
index f5707003..6d5568b9 100644
--- a/res/drawable-xhdpi/tv_5a_221.png
+++ b/res/drawable-xhdpi/tv_5a_221.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_222.png b/res/drawable-xhdpi/tv_5a_222.png
index 148d0fc8..092862f4 100644
--- a/res/drawable-xhdpi/tv_5a_222.png
+++ b/res/drawable-xhdpi/tv_5a_222.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_223.png b/res/drawable-xhdpi/tv_5a_223.png
index ca8a17c9..4d1086ae 100644
--- a/res/drawable-xhdpi/tv_5a_223.png
+++ b/res/drawable-xhdpi/tv_5a_223.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_224.png b/res/drawable-xhdpi/tv_5a_224.png
index ff478637..dad1878c 100644
--- a/res/drawable-xhdpi/tv_5a_224.png
+++ b/res/drawable-xhdpi/tv_5a_224.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_23.png b/res/drawable-xhdpi/tv_5a_23.png
index 229f0540..563e6d2c 100644
--- a/res/drawable-xhdpi/tv_5a_23.png
+++ b/res/drawable-xhdpi/tv_5a_23.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_24.png b/res/drawable-xhdpi/tv_5a_24.png
index 3033d442..650375fd 100644
--- a/res/drawable-xhdpi/tv_5a_24.png
+++ b/res/drawable-xhdpi/tv_5a_24.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_25.png b/res/drawable-xhdpi/tv_5a_25.png
index cab95c71..946a586a 100644
--- a/res/drawable-xhdpi/tv_5a_25.png
+++ b/res/drawable-xhdpi/tv_5a_25.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_26.png b/res/drawable-xhdpi/tv_5a_26.png
index e773785d..463f4b41 100644
--- a/res/drawable-xhdpi/tv_5a_26.png
+++ b/res/drawable-xhdpi/tv_5a_26.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_27.png b/res/drawable-xhdpi/tv_5a_27.png
index 64ebf81a..150fc898 100644
--- a/res/drawable-xhdpi/tv_5a_27.png
+++ b/res/drawable-xhdpi/tv_5a_27.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_28.png b/res/drawable-xhdpi/tv_5a_28.png
index 5e5c8e9c..407c1c66 100644
--- a/res/drawable-xhdpi/tv_5a_28.png
+++ b/res/drawable-xhdpi/tv_5a_28.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_29.png b/res/drawable-xhdpi/tv_5a_29.png
index 8cfcdea3..e13eaba4 100644
--- a/res/drawable-xhdpi/tv_5a_29.png
+++ b/res/drawable-xhdpi/tv_5a_29.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_3.png b/res/drawable-xhdpi/tv_5a_3.png
index 8fc7be9a..1382addc 100644
--- a/res/drawable-xhdpi/tv_5a_3.png
+++ b/res/drawable-xhdpi/tv_5a_3.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_30.png b/res/drawable-xhdpi/tv_5a_30.png
index f7ce5616..48688fa0 100644
--- a/res/drawable-xhdpi/tv_5a_30.png
+++ b/res/drawable-xhdpi/tv_5a_30.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_31.png b/res/drawable-xhdpi/tv_5a_31.png
index 29810aea..4e1fd2cc 100644
--- a/res/drawable-xhdpi/tv_5a_31.png
+++ b/res/drawable-xhdpi/tv_5a_31.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_32.png b/res/drawable-xhdpi/tv_5a_32.png
index 28e1abec..c9a757f0 100644
--- a/res/drawable-xhdpi/tv_5a_32.png
+++ b/res/drawable-xhdpi/tv_5a_32.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_33.png b/res/drawable-xhdpi/tv_5a_33.png
index 5da41c32..328cb2a0 100644
--- a/res/drawable-xhdpi/tv_5a_33.png
+++ b/res/drawable-xhdpi/tv_5a_33.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_34.png b/res/drawable-xhdpi/tv_5a_34.png
index ac068b1e..563ffbdf 100644
--- a/res/drawable-xhdpi/tv_5a_34.png
+++ b/res/drawable-xhdpi/tv_5a_34.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_35.png b/res/drawable-xhdpi/tv_5a_35.png
index 6f0bf74b..2a554bea 100644
--- a/res/drawable-xhdpi/tv_5a_35.png
+++ b/res/drawable-xhdpi/tv_5a_35.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_36.png b/res/drawable-xhdpi/tv_5a_36.png
index 8ef2bbe0..8a1572ec 100644
--- a/res/drawable-xhdpi/tv_5a_36.png
+++ b/res/drawable-xhdpi/tv_5a_36.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_37.png b/res/drawable-xhdpi/tv_5a_37.png
index ba5ce380..f95f14fa 100644
--- a/res/drawable-xhdpi/tv_5a_37.png
+++ b/res/drawable-xhdpi/tv_5a_37.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_38.png b/res/drawable-xhdpi/tv_5a_38.png
index fd1fcbd8..02ee5669 100644
--- a/res/drawable-xhdpi/tv_5a_38.png
+++ b/res/drawable-xhdpi/tv_5a_38.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_39.png b/res/drawable-xhdpi/tv_5a_39.png
index 08d591cd..8910fc00 100644
--- a/res/drawable-xhdpi/tv_5a_39.png
+++ b/res/drawable-xhdpi/tv_5a_39.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_4.png b/res/drawable-xhdpi/tv_5a_4.png
index c64431ba..0530c69c 100644
--- a/res/drawable-xhdpi/tv_5a_4.png
+++ b/res/drawable-xhdpi/tv_5a_4.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_40.png b/res/drawable-xhdpi/tv_5a_40.png
index 266dc292..84c02967 100644
--- a/res/drawable-xhdpi/tv_5a_40.png
+++ b/res/drawable-xhdpi/tv_5a_40.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_41.png b/res/drawable-xhdpi/tv_5a_41.png
index 5faefaff..867d64e7 100644
--- a/res/drawable-xhdpi/tv_5a_41.png
+++ b/res/drawable-xhdpi/tv_5a_41.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_42.png b/res/drawable-xhdpi/tv_5a_42.png
index 93aa1049..9fc75557 100644
--- a/res/drawable-xhdpi/tv_5a_42.png
+++ b/res/drawable-xhdpi/tv_5a_42.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_43.png b/res/drawable-xhdpi/tv_5a_43.png
index e0bcfc79..e87f8950 100644
--- a/res/drawable-xhdpi/tv_5a_43.png
+++ b/res/drawable-xhdpi/tv_5a_43.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_44.png b/res/drawable-xhdpi/tv_5a_44.png
index 111a642a..46c6480a 100644
--- a/res/drawable-xhdpi/tv_5a_44.png
+++ b/res/drawable-xhdpi/tv_5a_44.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_45.png b/res/drawable-xhdpi/tv_5a_45.png
index 535480fa..52f5a9dd 100644
--- a/res/drawable-xhdpi/tv_5a_45.png
+++ b/res/drawable-xhdpi/tv_5a_45.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_46.png b/res/drawable-xhdpi/tv_5a_46.png
index 60e13657..59caf0b4 100644
--- a/res/drawable-xhdpi/tv_5a_46.png
+++ b/res/drawable-xhdpi/tv_5a_46.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_47.png b/res/drawable-xhdpi/tv_5a_47.png
index f5e9789b..0a1e6e2d 100644
--- a/res/drawable-xhdpi/tv_5a_47.png
+++ b/res/drawable-xhdpi/tv_5a_47.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_48.png b/res/drawable-xhdpi/tv_5a_48.png
index 80b1049e..e4a0b400 100644
--- a/res/drawable-xhdpi/tv_5a_48.png
+++ b/res/drawable-xhdpi/tv_5a_48.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_49.png b/res/drawable-xhdpi/tv_5a_49.png
index ecc35dd8..adb5a834 100644
--- a/res/drawable-xhdpi/tv_5a_49.png
+++ b/res/drawable-xhdpi/tv_5a_49.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_5.png b/res/drawable-xhdpi/tv_5a_5.png
index 7e034db0..8b13e614 100644
--- a/res/drawable-xhdpi/tv_5a_5.png
+++ b/res/drawable-xhdpi/tv_5a_5.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_50.png b/res/drawable-xhdpi/tv_5a_50.png
index 2fa70004..2f6d214e 100644
--- a/res/drawable-xhdpi/tv_5a_50.png
+++ b/res/drawable-xhdpi/tv_5a_50.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_51.png b/res/drawable-xhdpi/tv_5a_51.png
index 352edda3..7733da0a 100644
--- a/res/drawable-xhdpi/tv_5a_51.png
+++ b/res/drawable-xhdpi/tv_5a_51.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_52.png b/res/drawable-xhdpi/tv_5a_52.png
index c05beba5..3d7f6336 100644
--- a/res/drawable-xhdpi/tv_5a_52.png
+++ b/res/drawable-xhdpi/tv_5a_52.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_53.png b/res/drawable-xhdpi/tv_5a_53.png
index af91dfc9..7b7529fd 100644
--- a/res/drawable-xhdpi/tv_5a_53.png
+++ b/res/drawable-xhdpi/tv_5a_53.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_54.png b/res/drawable-xhdpi/tv_5a_54.png
index 5c75f718..0e4b9bf7 100644
--- a/res/drawable-xhdpi/tv_5a_54.png
+++ b/res/drawable-xhdpi/tv_5a_54.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_55.png b/res/drawable-xhdpi/tv_5a_55.png
index 6178c59f..b0378990 100644
--- a/res/drawable-xhdpi/tv_5a_55.png
+++ b/res/drawable-xhdpi/tv_5a_55.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_56.png b/res/drawable-xhdpi/tv_5a_56.png
index f3d72c4d..b85e9687 100644
--- a/res/drawable-xhdpi/tv_5a_56.png
+++ b/res/drawable-xhdpi/tv_5a_56.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_57.png b/res/drawable-xhdpi/tv_5a_57.png
index f4df992c..6baa56d5 100644
--- a/res/drawable-xhdpi/tv_5a_57.png
+++ b/res/drawable-xhdpi/tv_5a_57.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_58.png b/res/drawable-xhdpi/tv_5a_58.png
index 2dd2f581..1dd6d001 100644
--- a/res/drawable-xhdpi/tv_5a_58.png
+++ b/res/drawable-xhdpi/tv_5a_58.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_59.png b/res/drawable-xhdpi/tv_5a_59.png
index 158faadd..7a3060a3 100644
--- a/res/drawable-xhdpi/tv_5a_59.png
+++ b/res/drawable-xhdpi/tv_5a_59.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_6.png b/res/drawable-xhdpi/tv_5a_6.png
index f75b91e6..7ca6df84 100644
--- a/res/drawable-xhdpi/tv_5a_6.png
+++ b/res/drawable-xhdpi/tv_5a_6.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_60.png b/res/drawable-xhdpi/tv_5a_60.png
index 215605a7..637c6f13 100644
--- a/res/drawable-xhdpi/tv_5a_60.png
+++ b/res/drawable-xhdpi/tv_5a_60.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_61.png b/res/drawable-xhdpi/tv_5a_61.png
index 368e96e1..1b765930 100644
--- a/res/drawable-xhdpi/tv_5a_61.png
+++ b/res/drawable-xhdpi/tv_5a_61.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_62.png b/res/drawable-xhdpi/tv_5a_62.png
index a2d4abde..c2579cba 100644
--- a/res/drawable-xhdpi/tv_5a_62.png
+++ b/res/drawable-xhdpi/tv_5a_62.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_63.png b/res/drawable-xhdpi/tv_5a_63.png
index f8049b44..9fbd3061 100644
--- a/res/drawable-xhdpi/tv_5a_63.png
+++ b/res/drawable-xhdpi/tv_5a_63.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_64.png b/res/drawable-xhdpi/tv_5a_64.png
index 0bc47374..d3c0c613 100644
--- a/res/drawable-xhdpi/tv_5a_64.png
+++ b/res/drawable-xhdpi/tv_5a_64.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_65.png b/res/drawable-xhdpi/tv_5a_65.png
index ac9324f2..51ae5ea5 100644
--- a/res/drawable-xhdpi/tv_5a_65.png
+++ b/res/drawable-xhdpi/tv_5a_65.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_66.png b/res/drawable-xhdpi/tv_5a_66.png
index c4417604..040c7c98 100644
--- a/res/drawable-xhdpi/tv_5a_66.png
+++ b/res/drawable-xhdpi/tv_5a_66.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_67.png b/res/drawable-xhdpi/tv_5a_67.png
index 0506e37e..c42232d8 100644
--- a/res/drawable-xhdpi/tv_5a_67.png
+++ b/res/drawable-xhdpi/tv_5a_67.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_68.png b/res/drawable-xhdpi/tv_5a_68.png
index 17978c4f..9c5c2031 100644
--- a/res/drawable-xhdpi/tv_5a_68.png
+++ b/res/drawable-xhdpi/tv_5a_68.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_69.png b/res/drawable-xhdpi/tv_5a_69.png
index 4c47cb8a..ce310728 100644
--- a/res/drawable-xhdpi/tv_5a_69.png
+++ b/res/drawable-xhdpi/tv_5a_69.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_7.png b/res/drawable-xhdpi/tv_5a_7.png
index a013bdc5..791481f0 100644
--- a/res/drawable-xhdpi/tv_5a_7.png
+++ b/res/drawable-xhdpi/tv_5a_7.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_70.png b/res/drawable-xhdpi/tv_5a_70.png
index 126e6a3d..baaf3c20 100644
--- a/res/drawable-xhdpi/tv_5a_70.png
+++ b/res/drawable-xhdpi/tv_5a_70.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_71.png b/res/drawable-xhdpi/tv_5a_71.png
index 1af44e22..4ea413d7 100644
--- a/res/drawable-xhdpi/tv_5a_71.png
+++ b/res/drawable-xhdpi/tv_5a_71.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_72.png b/res/drawable-xhdpi/tv_5a_72.png
index 23b19648..1c4fbe63 100644
--- a/res/drawable-xhdpi/tv_5a_72.png
+++ b/res/drawable-xhdpi/tv_5a_72.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_73.png b/res/drawable-xhdpi/tv_5a_73.png
index 873d43b3..1bc9d343 100644
--- a/res/drawable-xhdpi/tv_5a_73.png
+++ b/res/drawable-xhdpi/tv_5a_73.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_74.png b/res/drawable-xhdpi/tv_5a_74.png
index b81c61fa..cf850749 100644
--- a/res/drawable-xhdpi/tv_5a_74.png
+++ b/res/drawable-xhdpi/tv_5a_74.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_75.png b/res/drawable-xhdpi/tv_5a_75.png
index 336d5e81..9628e04c 100644
--- a/res/drawable-xhdpi/tv_5a_75.png
+++ b/res/drawable-xhdpi/tv_5a_75.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_76.png b/res/drawable-xhdpi/tv_5a_76.png
index 3f9bd07f..4c3515e6 100644
--- a/res/drawable-xhdpi/tv_5a_76.png
+++ b/res/drawable-xhdpi/tv_5a_76.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_77.png b/res/drawable-xhdpi/tv_5a_77.png
index 4659b925..23e883e2 100644
--- a/res/drawable-xhdpi/tv_5a_77.png
+++ b/res/drawable-xhdpi/tv_5a_77.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_78.png b/res/drawable-xhdpi/tv_5a_78.png
index 5ca27e6e..2d92ff4a 100644
--- a/res/drawable-xhdpi/tv_5a_78.png
+++ b/res/drawable-xhdpi/tv_5a_78.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_79.png b/res/drawable-xhdpi/tv_5a_79.png
index a033cab0..1f5af668 100644
--- a/res/drawable-xhdpi/tv_5a_79.png
+++ b/res/drawable-xhdpi/tv_5a_79.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_8.png b/res/drawable-xhdpi/tv_5a_8.png
index 2d928940..4f9b0ae6 100644
--- a/res/drawable-xhdpi/tv_5a_8.png
+++ b/res/drawable-xhdpi/tv_5a_8.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_80.png b/res/drawable-xhdpi/tv_5a_80.png
index 6c79d7a7..101305ef 100644
--- a/res/drawable-xhdpi/tv_5a_80.png
+++ b/res/drawable-xhdpi/tv_5a_80.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_81.png b/res/drawable-xhdpi/tv_5a_81.png
index 9095cd20..70f39d00 100644
--- a/res/drawable-xhdpi/tv_5a_81.png
+++ b/res/drawable-xhdpi/tv_5a_81.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_82.png b/res/drawable-xhdpi/tv_5a_82.png
index 43641c3b..4a5c099d 100644
--- a/res/drawable-xhdpi/tv_5a_82.png
+++ b/res/drawable-xhdpi/tv_5a_82.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_83.png b/res/drawable-xhdpi/tv_5a_83.png
index 72204d82..eec16527 100644
--- a/res/drawable-xhdpi/tv_5a_83.png
+++ b/res/drawable-xhdpi/tv_5a_83.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_84.png b/res/drawable-xhdpi/tv_5a_84.png
index 450fb2ca..80d26b0b 100644
--- a/res/drawable-xhdpi/tv_5a_84.png
+++ b/res/drawable-xhdpi/tv_5a_84.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_85.png b/res/drawable-xhdpi/tv_5a_85.png
index 4145ea47..215ffb14 100644
--- a/res/drawable-xhdpi/tv_5a_85.png
+++ b/res/drawable-xhdpi/tv_5a_85.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_86.png b/res/drawable-xhdpi/tv_5a_86.png
index 5459784e..97c20a11 100644
--- a/res/drawable-xhdpi/tv_5a_86.png
+++ b/res/drawable-xhdpi/tv_5a_86.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_87.png b/res/drawable-xhdpi/tv_5a_87.png
index 9a36a9ae..dddae79c 100644
--- a/res/drawable-xhdpi/tv_5a_87.png
+++ b/res/drawable-xhdpi/tv_5a_87.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_88.png b/res/drawable-xhdpi/tv_5a_88.png
index dc8fca0e..a3a34877 100644
--- a/res/drawable-xhdpi/tv_5a_88.png
+++ b/res/drawable-xhdpi/tv_5a_88.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_89.png b/res/drawable-xhdpi/tv_5a_89.png
index 42f54a05..9786fbaa 100644
--- a/res/drawable-xhdpi/tv_5a_89.png
+++ b/res/drawable-xhdpi/tv_5a_89.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_9.png b/res/drawable-xhdpi/tv_5a_9.png
index e502f31f..b4fee41b 100644
--- a/res/drawable-xhdpi/tv_5a_9.png
+++ b/res/drawable-xhdpi/tv_5a_9.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_90.png b/res/drawable-xhdpi/tv_5a_90.png
index 693b1509..369afce2 100644
--- a/res/drawable-xhdpi/tv_5a_90.png
+++ b/res/drawable-xhdpi/tv_5a_90.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_91.png b/res/drawable-xhdpi/tv_5a_91.png
index 088cc56c..afb67ec2 100644
--- a/res/drawable-xhdpi/tv_5a_91.png
+++ b/res/drawable-xhdpi/tv_5a_91.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_92.png b/res/drawable-xhdpi/tv_5a_92.png
index 8875a7dd..848febef 100644
--- a/res/drawable-xhdpi/tv_5a_92.png
+++ b/res/drawable-xhdpi/tv_5a_92.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_93.png b/res/drawable-xhdpi/tv_5a_93.png
index 5107cac8..a9b0176c 100644
--- a/res/drawable-xhdpi/tv_5a_93.png
+++ b/res/drawable-xhdpi/tv_5a_93.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_94.png b/res/drawable-xhdpi/tv_5a_94.png
index 28184866..5935a8fa 100644
--- a/res/drawable-xhdpi/tv_5a_94.png
+++ b/res/drawable-xhdpi/tv_5a_94.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_95.png b/res/drawable-xhdpi/tv_5a_95.png
index 3dfa26d7..bbceef5e 100644
--- a/res/drawable-xhdpi/tv_5a_95.png
+++ b/res/drawable-xhdpi/tv_5a_95.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_96.png b/res/drawable-xhdpi/tv_5a_96.png
index d10f3b9c..6b877056 100644
--- a/res/drawable-xhdpi/tv_5a_96.png
+++ b/res/drawable-xhdpi/tv_5a_96.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_97.png b/res/drawable-xhdpi/tv_5a_97.png
index eb0e246b..bf6ca1c9 100644
--- a/res/drawable-xhdpi/tv_5a_97.png
+++ b/res/drawable-xhdpi/tv_5a_97.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_98.png b/res/drawable-xhdpi/tv_5a_98.png
index 9f8f54c8..e446f06c 100644
--- a/res/drawable-xhdpi/tv_5a_98.png
+++ b/res/drawable-xhdpi/tv_5a_98.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_5a_99.png b/res/drawable-xhdpi/tv_5a_99.png
index a7b3ec2f..12fb1822 100644
--- a/res/drawable-xhdpi/tv_5a_99.png
+++ b/res/drawable-xhdpi/tv_5a_99.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_bg.png b/res/drawable-xhdpi/tv_bg.png
index c3668ead..de366d3e 100644
--- a/res/drawable-xhdpi/tv_bg.png
+++ b/res/drawable-xhdpi/tv_bg.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_error.png b/res/drawable-xhdpi/tv_error.png
index f6107f03..718f203b 100644
--- a/res/drawable-xhdpi/tv_error.png
+++ b/res/drawable-xhdpi/tv_error.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_shadow.png b/res/drawable-xhdpi/tv_shadow.png
index a2a65e50..16cde301 100644
--- a/res/drawable-xhdpi/tv_shadow.png
+++ b/res/drawable-xhdpi/tv_shadow.png
Binary files differ
diff --git a/res/drawable-xhdpi/tv_usb_antenna.png b/res/drawable-xhdpi/tv_usb_antenna.png
index 578d05f9..ff6c5cc1 100644
--- a/res/drawable-xhdpi/tv_usb_antenna.png
+++ b/res/drawable-xhdpi/tv_usb_antenna.png
Binary files differ
diff --git a/res/drawable-xhdpi/usb_antenna.png b/res/drawable-xhdpi/usb_antenna.png
index ba7bde19..ca5b2d72 100644
--- a/res/drawable-xhdpi/usb_antenna.png
+++ b/res/drawable-xhdpi/usb_antenna.png
Binary files differ
diff --git a/res/drawable/dvr_selector_background.xml b/res/drawable/dvr_selector_background.xml
new file mode 100644
index 00000000..8329ab60
--- /dev/null
+++ b/res/drawable/dvr_selector_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="?android:attr/colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <shape>
+ <solid android:color="@android:color/white"/>
+ <corners android:radius="2dp" />
+ </shape>
+ </item>
+</ripple>
diff --git a/res/drawable/ic_record_start.xml b/res/drawable/ic_dvr_badge.xml
index 8d154c37..d810c2ec 100644
--- a/res/drawable/ic_record_start.xml
+++ b/res/drawable/ic_dvr_badge.xml
@@ -16,5 +16,5 @@
-->
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
- android:src="@drawable/ic_record_start_white"
- android:tint="#FFF44336" />
+ android:src="@drawable/ic_dvr"
+ android:gravity="fill"/>
diff --git a/res/drawable/priority_settings_action_item_selected.xml b/res/drawable/priority_settings_action_item_selected.xml
new file mode 100644
index 00000000..a1ab18ae
--- /dev/null
+++ b/res/drawable/priority_settings_action_item_selected.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:left="24dp" android:right="24dp">
+ <shape>
+ <solid android:color="#EEEEEE"/>
+ <corners android:radius="2dp" />
+ </shape>
+ </item>
+</layer-list>
+
diff --git a/res/drawable/progress_horizontal.xml b/res/drawable/progress_horizontal.xml
index 95b7a531..24376cd4 100644
--- a/res/drawable/progress_horizontal.xml
+++ b/res/drawable/progress_horizontal.xml
@@ -26,7 +26,7 @@
<item android:id="@android:id/secondaryProgress">
<clip>
<shape>
- <solid android:color="#EEEEEE"/>
+ <solid android:color="#FFF44336"/>
</shape>
</clip>
</item>
diff --git a/res/layout/activity_dvr_details.xml b/res/layout/activity_dvr_details.xml
new file mode 100644
index 00000000..4a9fb237
--- /dev/null
+++ b/res/layout/activity_dvr_details.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dvr_details_view_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" /> \ No newline at end of file
diff --git a/res/layout/activity_dvr_playback.xml b/res/layout/activity_dvr_playback.xml
new file mode 100644
index 00000000..204001c7
--- /dev/null
+++ b/res/layout/activity_dvr_playback.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:keepScreenOn="true"
+ android:background="@color/tvactivity_background" >
+
+ <!-- AppLayerTvView is wrapped by FrameLayout to handle aspect ratios by adjusting paddings. -->
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <com.android.tv.ui.AppLayerTvView android:id="@+id/dvr_tv_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center" />
+
+ </FrameLayout>
+
+ <fragment android:id="@+id/dvr_playback_controls_fragment"
+ android:name="com.android.tv.dvr.ui.DvrPlaybackOverlayFragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <View android:id="@+id/block_screen"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:background="@android:color/black"
+ android:visibility="gone" />
+
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/activity_dvr_schedules.xml b/res/layout/activity_dvr_schedules.xml
new file mode 100644
index 00000000..61e1f2a6
--- /dev/null
+++ b/res/layout/activity_dvr_schedules.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <TextView
+ android:id="@+id/empty_info_screen"
+ android:layout_width="600dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:gravity="center"
+ android:fontFamily="@string/font"
+ android:textSize="@dimen/tvview_block_text_size"
+ android:lineSpacingExtra="@dimen/tvview_block_line_spacing_extra"
+ android:textColor="@color/tvview_block_text_color" />
+
+ <FrameLayout android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/activity_dvr_series_settings.xml b/res/layout/activity_dvr_series_settings.xml
new file mode 100644
index 00000000..4ded310c
--- /dev/null
+++ b/res/layout/activity_dvr_series_settings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dvr_settings_view_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" /> \ No newline at end of file
diff --git a/res/layout/activity_tv.xml b/res/layout/activity_tv.xml
index b484ed60..f766ae00 100644
--- a/res/layout/activity_tv.xml
+++ b/res/layout/activity_tv.xml
@@ -40,4 +40,25 @@
android:layout_marginBottom="@dimen/pipview_margin_bottom"
android:layout_width="@dimen/pipview_small_size_width"
android:layout_height="@dimen/pipview_small_size_height" />
+
+ <com.android.tv.ui.TunableTvView android:id="@+id/pip_tunable_tv_view"
+ android:visibility="gone"
+ android:layout_marginLeft="@dimen/pipview_margin_horizontal"
+ android:layout_marginRight="@dimen/pipview_margin_horizontal"
+ android:layout_marginTop="@dimen/pipview_margin_top"
+ android:layout_marginBottom="@dimen/pipview_margin_bottom"
+ android:layout_width="@dimen/pipview_small_size_width"
+ android:layout_height="@dimen/pipview_small_size_height" />
+
+ <FrameLayout
+ android:id="@+id/scene_container"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent" />
+
+ <include layout="@layout/menu" />
+ <include layout="@layout/option_container" />
+ <include layout="@layout/program_guide" />
+ <FrameLayout android:id="@+id/fragment_container"
+ android:layout_height="match_parent"
+ android:layout_width="match_parent"/>
</FrameLayout>
diff --git a/res/layout/block_screen.xml b/res/layout/block_screen.xml
index 892b8e5e..6a04e966 100644
--- a/res/layout/block_screen.xml
+++ b/res/layout/block_screen.xml
@@ -21,7 +21,7 @@
android:layout_height="match_parent"
android:gravity="center"
android:visibility="gone"
- android:background="@android:color/black" >
+ android:background="@android:color/black">
<!-- This layout is used for the animation -->
<LinearLayout
android:id="@+id/block_screen_container"
@@ -61,7 +61,7 @@
android:gravity="center"
android:fontFamily="@string/font"
android:textSize="@dimen/tvview_block_text_size"
- android:lineSpacingExtra="4sp"
+ android:lineSpacingExtra="@dimen/tvview_block_line_spacing_extra"
android:textColor="@color/tvview_block_text_color" />
</LinearLayout>
</com.android.tv.ui.BlockScreenView>
diff --git a/res/layout/channel_banner.xml b/res/layout/channel_banner.xml
index 71264584..3f105fe3 100644
--- a/res/layout/channel_banner.xml
+++ b/res/layout/channel_banner.xml
@@ -107,13 +107,24 @@
android:fontFamily="@string/condensed_font"
android:textSize="@dimen/channel_banner_small_text_size" />
+ <TextView android:id="@+id/recording_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="12dp"
+ android:layout_alignBottom="@id/channel_name"
+ android:layout_toEndOf="@id/program_time_text"
+ android:drawableStart="@drawable/ic_recording_program"
+ android:textColor="@color/channel_banner_dim_text_color"
+ android:fontFamily="@string/condensed_font"
+ android:textSize="@dimen/channel_banner_small_text_size" />
+
<ProgressBar
android:id="@+id/remaining_time"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="60dp"
android:layout_height="4dp"
android:layout_alignBottom="@id/anchor"
- android:layout_toEndOf="@id/program_time_text"
+ android:layout_toEndOf="@id/recording_indicator"
android:layout_marginEnd="12dp"
android:layout_marginBottom="0.5dp"
android:mirrorForRtl="false"
diff --git a/res/layout/dvr_details_description.xml b/res/layout/dvr_details_description.xml
new file mode 100644
index 00000000..c5db470f
--- /dev/null
+++ b/res/layout/dvr_details_description.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <!-- Top margins are set programatically -->
+ <android.support.v17.leanback.widget.ResizingTextView
+ android:id="@+id/dvr_details_description_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ style="?attr/detailsDescriptionTitleStyle" />
+
+ <TextView android:id="@+id/dvr_details_description_subtitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ style="?attr/detailsDescriptionSubtitleStyle" />
+
+ <LinearLayout android:id="@+id/dvr_details_description_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:background="?android:attr/selectableItemBackground"
+ android:clickable="true">
+
+ <TextView android:id="@+id/dvr_details_description_body"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingTop="9dp"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ style="?attr/detailsDescriptionBodyStyle" />
+
+ <TextView android:id="@+id/dvr_details_description_read_more"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:text="@string/dvr_detail_read_more"
+ android:textColor="@color/lb_details_description_color"
+ android:textSize="16sp"
+ android:height="29dp"
+ android:layout_marginTop="3dp"
+ android:paddingLeft="12dp"
+ android:paddingRight="12dp"
+ android:paddingBottom="9dp"
+ android:textAllCaps="true" />
+
+ </LinearLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/dvr_recording_card_view.xml b/res/layout/dvr_recording_card_view.xml
index ccaf838f..d3808a31 100644
--- a/res/layout/dvr_recording_card_view.xml
+++ b/res/layout/dvr_recording_card_view.xml
@@ -14,42 +14,87 @@
~ limitations under the License
-->
-<merge
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tv="http://schemas.android.com/apk/res/com.android.tv"
- android:layout_width="@dimen/dvr_card_layout_width"
- android:layout_height="@dimen/dvr_card_layout_height">
-
- <ImageView
- android:id="@+id/image"
- android:layout_width="@dimen/dvr_card_image_layout_width"
- android:layout_height="@dimen/dvr_card_image_layout_height"
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tv="http://schemas.android.com/apk/res/com.android.tv"
+ android:layout_width="@dimen/dvr_card_layout_width"
+ android:layout_height="wrap_content">
+
+ <FrameLayout
+ android:layout_width="@dimen/dvr_card_image_layout_width"
+ android:layout_height="@dimen/dvr_card_image_layout_height"
+ android:layout_margin="2dp">
+
+ <ImageView android:id="@+id/image"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
android:layout_gravity="center_horizontal"
- android:layout_margin="2dp"
- android:gravity="center"
- tv:layout_viewType="main"/>
+ android:scaleType="centerCrop"
+ android:contentDescription="@null"
+ tv:layout_viewType="main" />
+
+ <ProgressBar android:id="@+id/recording_progress"
+ style="@android:style/Widget.ProgressBar.Horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dvr_card_progress_height"
+ android:mirrorForRtl="false"
+ android:progressTint="@color/play_controls_progress_bar_watched"
+ android:progressDrawable="@drawable/progress_horizontal"
+ android:indeterminate="false"
+ android:visibility="gone"
+ android:max="100"
+ android:layout_gravity="bottom" />
- <LinearLayout
- android:orientation="vertical"
- android:id="@+id/info_area"
+ <FrameLayout android:id="@+id/affiliated_icon_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- tv:layout_viewType="info">
+ android:background="@drawable/card_image_gradient"
+ android:visibility="invisible">
+
+ <ImageView android:id="@+id/affiliated_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom|right"
+ android:layout_margin="12dp" />
+
+ </FrameLayout>
+ </FrameLayout>
+
+ <LinearLayout android:id="@+id/info_area"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="11dp"
+ android:paddingEnd="11dp"
+ android:paddingTop="7dp"
+ android:paddingBottom="7dp"
+ android:background="@color/dvr_card_info"
+ tv:layout_viewType="info">
+
+ <TextView android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="1dp"
+ android:gravity="start"
+ style="@style/dvr_card_view_title_text"
+ tv:layout_viewType="main"/>
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content" >
- <TextView
- android:id="@+id/title"
- android:layout_width="match_parent"
+ <TextView android:id="@+id/content_major"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="2dp"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:gravity="start"
+ style="@style/dvr_card_view_content_text" />
- <TextView
- android:id="@+id/content"
- android:layout_width="match_parent"
+ <TextView android:id="@+id/content_minor"
+ android:layout_alignParentEnd="true"
+ android:layout_toEndOf="@+id/content_major"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_margin="2dp"
- android:gravity="center"
- android:textAppearance="?android:attr/textAppearanceMedium"/>
+ android:gravity="end"
+ style="@style/dvr_card_view_content_text" />
+ </RelativeLayout>
</LinearLayout>
</merge>
diff --git a/res/layout/dvr_schedules_header.xml b/res/layout/dvr_schedules_header.xml
new file mode 100644
index 00000000..0a643bef
--- /dev/null
+++ b/res/layout/dvr_schedules_header.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/dvr_schedules_item_width"
+ android:layout_height="wrap_content"
+ android:paddingRight="@dimen/dvr_schedules_layout_padding"
+ android:paddingLeft="@dimen/dvr_schedules_layout_padding"
+ android:layout_marginTop="@dimen/dvr_schedules_header_margin_top"
+ android:layout_marginBottom="@dimen/dvr_schedules_header_margin_bottom">
+
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentStart="true"
+ android:layout_toStartOf="@+id/button_container">
+ <TextView android:id="@+id/header_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textSize="20sp"
+ android:textColor="@color/dvr_schedules_item_main"/>
+ <TextView android:id="@+id/header_description"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dvr_schedules_header_subtitle_margin_top"
+ android:ellipsize="end"
+ android:singleLine="true"
+ android:textSize="14sp"
+ android:textColor="@color/dvr_schedules_header_description"/>
+ </LinearLayout>
+
+ <FrameLayout android:id="@id/button_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_alignParentEnd="true"
+ android:visibility="gone">
+ <com.android.tv.dvr.ui.list.DvrSchedulesFocusView
+ android:id="@+id/selector"
+ android:tag="@string/dvr_schedules_header_focus_view"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:alpha="0"/>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+ <include android:id="@+id/series_settings"
+ layout="@layout/dvr_schedules_header_button" />
+ <include android:id="@+id/series_toggle_start_stop"
+ layout="@layout/dvr_schedules_header_button" />
+ </LinearLayout>
+ </FrameLayout>
+ </RelativeLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/dvr_schedules_header_button.xml b/res/layout/dvr_schedules_header_button.xml
new file mode 100644
index 00000000..30163ab8
--- /dev/null
+++ b/res/layout/dvr_schedules_header_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/dvr_schedules_header_icon_container_width"
+ android:layout_height="match_parent"
+ android:paddingLeft="@dimen/dvr_schedules_header_icon_horizontal_margin"
+ android:paddingRight="@dimen/dvr_schedules_header_icon_horizontal_margin"
+ android:drawablePadding="@dimen/dvr_schedules_header_icon_horizontal_margin"
+ android:focusableInTouchMode="true"
+ android:focusable="true"
+ android:clickable="true"
+ android:textSize="14sp"
+ android:gravity="center_vertical" />
diff --git a/res/layout/dvr_schedules_item.xml b/res/layout/dvr_schedules_item.xml
new file mode 100644
index 00000000..1d97cb98
--- /dev/null
+++ b/res/layout/dvr_schedules_item.xml
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/dvr_schedules_item_width"
+ android:layout_height="wrap_content"
+ android:elevation="@dimen/card_elevation_normal"
+ android:orientation="vertical"
+ android:outlineProvider="paddedBounds"
+ android:paddingStart="@dimen/dvr_schedules_layout_padding"
+ android:paddingEnd="@dimen/dvr_schedules_layout_padding">
+
+ <ImageView
+ android:id="@+id/schedule_row_separator"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/dvr_schedules_row_divider_height"
+ android:background="@color/dvr_schedules_item_background"
+ android:src="@color/dvr_schedules_list_item_selector"
+ android:contentDescription="@null"/>
+
+ <FrameLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:background="@color/dvr_schedules_item_background">
+ <com.android.tv.dvr.ui.list.DvrSchedulesFocusView
+ android:id="@+id/selector"
+ android:tag="@string/dvr_schedules_item_focus_view"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:alpha="0"/>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <LinearLayout android:id="@+id/info_container"
+ android:layout_width="0dp"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dvr_schedules_item_section_margin"
+ android:layout_weight="1"
+ android:clickable="true"
+ android:focusableInTouchMode="true"
+ android:focusable="true">
+
+ <TextView android:id="@+id/time"
+ android:layout_width="@dimen/dvr_schedules_item_time_width"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/dvr_schedules_item_time_margin"
+ android:paddingStart="@dimen/dvr_schedules_item_time_start_padding"
+ android:layout_marginBottom="@dimen/dvr_schedules_item_time_margin"
+ android:lines="1"
+ android:textColor="@color/dvr_schedules_item_info"/>
+ <LinearLayout android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical">
+ <LinearLayout android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:layout_marginTop="@dimen/dvr_schedules_item_info_top_margin">
+ <TextView android:id="@+id/program_title"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:gravity="start"
+ android:lines="1"
+ android:ellipsize="end"
+ android:textColor="@color/dvr_schedules_item_main"/>
+ <TextView android:id="@+id/info_separator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:text="@string/dvr_schedules_information_separator"
+ android:textColor="@color/dvr_schedules_item_info"/>
+ <TextView android:id="@+id/channel_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:ellipsize="end"
+ android:lines="1"
+ android:textColor="@color/dvr_schedules_item_info"/>
+ </LinearLayout>
+ <TextView android:id="@+id/conflict_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="start"
+ android:textSize="10sp"
+ android:layout_marginBottom="@dimen/dvr_schedules_item_conflict_info_bottom_margin"
+ android:textColor="@color/dvr_schedules_item_info"
+ android:visibility="gone"/>
+ </LinearLayout>
+ </LinearLayout>
+
+ <RelativeLayout android:id="@+id/action_second_container"
+ android:layout_width="@dimen/dvr_schedules_item_icon_size"
+ android:layout_height="match_parent"
+ android:layout_marginEnd="@dimen/dvr_schedules_item_section_margin"
+ android:clickable="true"
+ android:focusableInTouchMode="true"
+ android:focusable="true"
+ android:visibility="gone">
+ <ImageView android:id="@+id/action_second"
+ android:layout_width="@dimen/dvr_schedules_item_icon_size"
+ android:layout_height="@dimen/dvr_schedules_item_icon_size"
+ android:layout_centerVertical="true"
+ android:layout_centerHorizontal="true"/>
+ </RelativeLayout>
+
+ <RelativeLayout android:id="@+id/action_first_container"
+ android:layout_width="@dimen/dvr_schedules_item_delete_width"
+ android:layout_height="match_parent"
+ android:gravity="center_vertical"
+ android:clickable="true"
+ android:focusableInTouchMode="true"
+ android:focusable="true"
+ android:visibility="gone">
+ <ImageView android:id="@+id/action_first"
+ android:layout_width="@dimen/dvr_schedules_item_icon_size"
+ android:layout_height="@dimen/dvr_schedules_item_icon_size"
+ android:layout_alignParentStart="true"
+ android:layout_centerVertical="true"/>
+ </RelativeLayout>
+ </LinearLayout>
+ </FrameLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/onboarding_item_divider.xml b/res/layout/guided_action_divider.xml
index 7f3a29ca..7f3a29ca 100644
--- a/res/layout/onboarding_item_divider.xml
+++ b/res/layout/guided_action_divider.xml
diff --git a/res/layout/halfsized_dialog.xml b/res/layout/halfsized_dialog.xml
index a5e017e4..f09b4836 100644
--- a/res/layout/halfsized_dialog.xml
+++ b/res/layout/halfsized_dialog.xml
@@ -17,10 +17,7 @@
<!-- container for hosting HalfSizedDialog -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/halfsized_dialog_host"
android:layout_width="match_parent"
- android:layout_height="match_parent">
- <FrameLayout android:id="@+id/halfsized_dialog_host"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginTop="300dp"/>
-</FrameLayout> \ No newline at end of file
+ android:layout_height="match_parent"
+ android:paddingTop="300dp" />
diff --git a/res/layout/halfsized_guidance.xml b/res/layout/halfsized_guidance.xml
deleted file mode 100644
index 4b444d3e..00000000
--- a/res/layout/halfsized_guidance.xml
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- 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.
--->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <RelativeLayout
- android:id="@+id/guidance_container"
- style="?attr/guidanceContainerStyle" >
-
- <ImageView
- android:id="@+id/guidance_icon"
- style="?attr/guidanceIconStyle"
- tools:ignore="ContentDescription"/>
-
- <TextView
- android:id="@+id/guidance_breadcrumb"
- style="?attr/guidanceBreadcrumbStyle"/>
-
- <TextView
- android:id="@+id/guidance_title"
- style="?attr/guidanceTitleStyle"/>
-
- <TextView
- android:id="@+id/guidance_description"
- style="?attr/guidanceDescriptionStyle"/>
-
- </RelativeLayout>
-
-</FrameLayout> \ No newline at end of file
diff --git a/res/layout/lb_details_overview.xml b/res/layout/lb_details_overview.xml
new file mode 100644
index 00000000..dbcf2055
--- /dev/null
+++ b/res/layout/lb_details_overview.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<!-- This layout file is copied from Leanback library and used to override the original layout.
+ Be cautious to change this layout to prevent weird UI behavior -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:lb="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/lb_details_overview_margin_start"
+ android:paddingEnd="@dimen/lb_details_overview_margin_end"
+ android:paddingBottom="@dimen/lb_details_overview_margin_bottom"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:descendantFocusability="afterDescendants">
+
+ <!-- Used for dimming -->
+ <FrameLayout android:id="@+id/details_frame"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/lb_details_overview_height_large"
+ android:foreground="#ffffff"
+ android:elevation="@dimen/lb_details_overview_z">
+
+ <!-- Background is applied to this inner layout -->
+ <LinearLayout android:id="@+id/details_overview"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="horizontal">
+
+ <ImageView android:id="@+id/details_overview_image"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:adjustViewBounds="true"
+ android:scaleType="fitStart" />
+
+ <LinearLayout android:id="@+id/details_overview_right_panel"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:paddingBottom="@dimen/lb_details_overview_description_margin_bottom"
+ android:orientation="vertical" >
+
+ <!-- layout_marginStart and layout_marginEnd are overridden -->
+ <android.support.v17.leanback.widget.NonOverlappingFrameLayout
+ android:id="@+id/details_overview_description"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1"
+ android:gravity="top"
+ android:layout_marginStart="@dimen/dvr_details_overview_description_margin_start"
+ android:layout_marginEnd="@dimen/dvr_details_overview_description_margin_end"
+ android:paddingTop="@dimen/lb_details_overview_description_margin_top"
+ android:clipToPadding="false"
+ android:clipChildren="false" />
+
+ <!-- horizontalSpacing is defined as @dimen/lb_details_overview_action_items_spacing
+ in newer versions of Leanback Library than LC uses. -->
+ <android.support.v17.leanback.widget.HorizontalGridView
+ android:id="@+id/details_overview_actions"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:paddingStart="@dimen/lb_details_overview_description_margin_start"
+ android:paddingEnd="@dimen/lb_details_overview_description_margin_end"
+ android:horizontalSpacing="16dp"
+ lb:rowHeight="@dimen/lb_details_overview_actions_height" />
+
+ </LinearLayout>
+ </LinearLayout>
+ </FrameLayout>
+</FrameLayout> \ No newline at end of file
diff --git a/res/layout/menu_card_app_link.xml b/res/layout/menu_card_app_link.xml
index 631b5fbb..918cb788 100644
--- a/res/layout/menu_card_app_link.xml
+++ b/res/layout/menu_card_app_link.xml
@@ -56,31 +56,7 @@
<FrameLayout android:id="@+id/app_link_text_holder"
android:layout_width="match_parent"
android:layout_height="wrap_content">
-
- <TextView android:id="@+id/app_link_text_focused"
- android:layout_width="match_parent"
- android:layout_height="@dimen/card_meta_layout_height"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:paddingTop="@dimen/card_meta_padding_top"
- android:ellipsize="end"
- android:fontFamily="@string/condensed_font"
- android:maxLines="2"
- android:textColor="@color/card_meta_text_color"
- android:textSize="12sp" />
-
- <TextView android:id="@+id/app_link_text_unfocused"
- android:layout_width="match_parent"
- android:layout_height="@dimen/card_meta_layout_height"
- android:paddingStart="12dp"
- android:paddingEnd="12dp"
- android:paddingTop="@dimen/card_meta_padding_top"
- android:ellipsize="end"
- android:fontFamily="@string/condensed_font"
- android:singleLine="true"
- android:textColor="@color/card_meta_text_color"
- android:textSize="12sp" />
-
+ <include layout="@layout/menu_card_text" />
</FrameLayout>
</com.android.tv.menu.AppLinkCardView>
diff --git a/res/layout/menu_card_channel.xml b/res/layout/menu_card_channel.xml
index 42aeb460..4e49636f 100644
--- a/res/layout/menu_card_channel.xml
+++ b/res/layout/menu_card_channel.xml
@@ -72,31 +72,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/channel_card_meta_background">
-
- <TextView android:id="@+id/channel_title_focused"
- android:layout_width="match_parent"
- android:layout_height="@dimen/card_meta_layout_height"
- android:paddingStart="@dimen/card_meta_padding_start"
- android:paddingEnd="@dimen/card_meta_padding_end"
- android:paddingTop="@dimen/card_meta_padding_top"
- android:ellipsize="end"
- android:fontFamily="@string/condensed_font"
- android:maxLines="2"
- android:textColor="@color/card_meta_text_color"
- android:textSize="12sp" />
-
- <TextView android:id="@+id/channel_title_unfocused"
- android:layout_width="match_parent"
- android:layout_height="@dimen/card_meta_layout_height"
- android:paddingStart="@dimen/card_meta_padding_start"
- android:paddingEnd="@dimen/card_meta_padding_end"
- android:paddingTop="@dimen/card_meta_padding_top"
- android:ellipsize="end"
- android:fontFamily="@string/condensed_font"
- android:singleLine="true"
- android:textColor="@color/card_meta_text_color"
- android:textSize="12sp" />
-
+ <include layout="@layout/menu_card_text" />
</FrameLayout>
</com.android.tv.menu.ChannelCardView>
diff --git a/res/layout/menu_card_dvr.xml b/res/layout/menu_card_dvr.xml
index 0ba7131d..cc589775 100644
--- a/res/layout/menu_card_dvr.xml
+++ b/res/layout/menu_card_dvr.xml
@@ -35,18 +35,10 @@
android:layout_gravity="center_horizontal" />
</FrameLayout>
- <TextView
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="@dimen/card_meta_layout_height"
- android:paddingStart="@dimen/card_meta_padding_start"
- android:paddingEnd="@dimen/card_meta_padding_end"
- android:paddingTop="@dimen/card_meta_padding_top"
- android:singleLine="true"
- android:ellipsize="end"
- android:fontFamily="@string/condensed_font"
- android:textColor="@color/card_meta_text_color"
- android:background="@color/guide_card_meta_background"
- android:text="@string/channels_item_dvr"
- android:textSize="12sp" />
-
+ android:layout_height="wrap_content"
+ android:background="@color/guide_card_meta_background">
+ <include layout="@layout/menu_card_text" />
+ </FrameLayout>
</com.android.tv.menu.SimpleCardView>
diff --git a/res/layout/menu_card_setup.xml b/res/layout/menu_card_setup.xml
index b495e7ea..38abd4e5 100644
--- a/res/layout/menu_card_setup.xml
+++ b/res/layout/menu_card_setup.xml
@@ -15,7 +15,7 @@
~ limitations under the License.
-->
-<com.android.tv.menu.SetupCardView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.tv.menu.SimpleCardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/card_layout_width"
android:layout_height="wrap_content"
android:orientation="vertical"
@@ -48,4 +48,4 @@
android:text="@string/channels_item_setup"
android:textSize="12sp" />
-</com.android.tv.menu.SetupCardView>
+</com.android.tv.menu.SimpleCardView>
diff --git a/res/layout/menu_card_record.xml b/res/layout/menu_card_text.xml
index 6a195f0c..777b100f 100644
--- a/res/layout/menu_card_record.xml
+++ b/res/layout/menu_card_text.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.
@@ -15,29 +15,24 @@
~ limitations under the License.
-->
-<com.android.tv.menu.RecordCardView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/card_layout_width"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:elevation="@dimen/card_elevation_normal"
- android:focusable="true"
- android:clickable="true">
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tv="http://schemas.android.com/apk/res/com.android.tv"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
- <FrameLayout
- android:layout_width="@dimen/card_image_layout_width"
- android:layout_height="@dimen/card_image_layout_height"
- android:background="@color/channel_card_guide">
- <ImageView
- android:id="@+id/record_icon"
- android:layout_width="82dp"
- android:layout_height="48dp"
- android:layout_marginTop="16dp"
- android:src="@drawable/ic_record_start"
- android:layout_gravity="center_horizontal" />
- </FrameLayout>
+ <TextView android:id="@+id/card_text_focused"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/card_meta_layout_height"
+ android:paddingStart="@dimen/card_meta_padding_start"
+ android:paddingEnd="@dimen/card_meta_padding_end"
+ android:paddingTop="@dimen/card_meta_padding_top"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:fontFamily="@string/condensed_font"
+ android:textColor="@color/card_meta_text_color"
+ android:textSize="12sp" />
- <TextView
- android:id="@+id/record_label"
+ <TextView android:id="@+id/card_text"
android:layout_width="match_parent"
android:layout_height="@dimen/card_meta_layout_height"
android:paddingStart="@dimen/card_meta_padding_start"
@@ -47,8 +42,5 @@
android:ellipsize="end"
android:fontFamily="@string/condensed_font"
android:textColor="@color/card_meta_text_color"
- android:background="@color/guide_card_meta_background"
- android:text="@string/channels_item_record_start"
android:textSize="12sp" />
-
-</com.android.tv.menu.RecordCardView>
+</merge>
diff --git a/res/layout/overlay_root_view.xml b/res/layout/overlay_root_view.xml
deleted file mode 100644
index 1fc8647f..00000000
--- a/res/layout/overlay_root_view.xml
+++ /dev/null
@@ -1,43 +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.
- -->
-
-<com.android.tv.ui.OverlayRootView xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/overlay_root_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
-
- <com.android.tv.ui.TunableTvView android:id="@+id/pip_tunable_tv_view"
- android:visibility="gone"
- android:layout_marginLeft="@dimen/pipview_margin_horizontal"
- android:layout_marginRight="@dimen/pipview_margin_horizontal"
- android:layout_marginTop="@dimen/pipview_margin_top"
- android:layout_marginBottom="@dimen/pipview_margin_bottom"
- android:layout_width="@dimen/pipview_small_size_width"
- android:layout_height="@dimen/pipview_small_size_height" />
-
- <FrameLayout
- android:id="@+id/scene_container"
- android:layout_height="match_parent"
- android:layout_width="match_parent" />
-
- <include layout="@layout/menu" />
- <include layout="@layout/option_container" />
- <include layout="@layout/program_guide" />
- <FrameLayout android:id="@+id/fragment_container"
- android:layout_height="match_parent"
- android:layout_width="match_parent"/>
-</com.android.tv.ui.OverlayRootView>
diff --git a/res/layout/play_controls_contents.xml b/res/layout/play_controls_contents.xml
index 2f17b9f6..ac61a2d4 100644
--- a/res/layout/play_controls_contents.xml
+++ b/res/layout/play_controls_contents.xml
@@ -102,39 +102,56 @@
android:textSize="@dimen/play_controls_rec_time_text_size"
android:fontFamily="@string/font" />
- <LinearLayout
+ <RelativeLayout
android:id="@+id/play_control_bar"
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/play_controls_button_height"
- android:layout_gravity="center">
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/play_controls_button_height">
<com.android.tv.menu.PlayControlsButton
- android:id="@+id/jump_previous"
+ android:id="@+id/play_pause"
android:layout_width="@dimen/play_controls_button_width"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_centerHorizontal="true" />
<com.android.tv.menu.PlayControlsButton
android:id="@+id/rewind"
android:layout_width="@dimen/play_controls_button_width"
android:layout_height="match_parent"
- android:layout_marginStart="@dimen/play_controls_button_start_margin" />
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_toLeftOf="@id/play_pause" />
<com.android.tv.menu.PlayControlsButton
- android:id="@+id/play_pause"
+ android:id="@+id/jump_previous"
android:layout_width="@dimen/play_controls_button_width"
android:layout_height="match_parent"
- android:layout_marginStart="@dimen/play_controls_button_start_margin" />
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_toLeftOf="@id/rewind" />
<com.android.tv.menu.PlayControlsButton
android:id="@+id/fast_forward"
android:layout_width="@dimen/play_controls_button_width"
android:layout_height="match_parent"
- android:layout_marginStart="@dimen/play_controls_button_start_margin" />
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_toRightOf="@id/play_pause" />
<com.android.tv.menu.PlayControlsButton
android:id="@+id/jump_next"
android:layout_width="@dimen/play_controls_button_width"
android:layout_height="match_parent"
- android:layout_marginStart="@dimen/play_controls_button_start_margin" />
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_toRightOf="@id/fast_forward" />
+ <com.android.tv.menu.PlayControlsButton
+ android:id="@+id/record"
+ android:layout_width="@dimen/play_controls_button_width"
+ android:layout_height="match_parent"
+ android:layout_marginLeft="@dimen/play_controls_button_normal_margin"
+ android:layout_marginRight="@dimen/play_controls_button_normal_margin"
+ android:layout_toRightOf="@id/jump_next"
+ android:visibility="gone" />
- </LinearLayout>
+ </RelativeLayout>
<TextView
android:id="@+id/unavailable_text"
diff --git a/res/layout/priority_settings_action_item.xml b/res/layout/priority_settings_action_item.xml
new file mode 100644
index 00000000..0f517319
--- /dev/null
+++ b/res/layout/priority_settings_action_item.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+
+<android.support.v17.leanback.widget.GuidedActionItemContainer
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ style="?attr/guidedActionItemContainerStyle"
+ android:foreground="@null"
+ android:outlineProvider="background">
+ <android.support.v17.leanback.widget.CheckableImageView
+ android:id="@+id/guidedactions_item_checkmark"
+ style="?attr/guidedActionItemCheckmarkStyle"
+ tools:ignore="ContentDescription" />
+ <ImageView
+ android:id="@+id/guidedactions_item_icon"
+ style="?attr/guidedActionItemIconStyle"
+ tools:ignore="ContentDescription" />
+
+ <android.support.v17.leanback.widget.NonOverlappingLinearLayout
+ android:id="@+id/guidedactions_item_content"
+ style="?attr/guidedActionItemContentStyle" >
+ <android.support.v17.leanback.widget.GuidedActionEditText
+ android:id="@+id/guidedactions_item_title"
+ style="?attr/guidedActionItemTitleStyle" />
+ <android.support.v17.leanback.widget.GuidedActionEditText
+ android:id="@+id/guidedactions_item_description"
+ style="?attr/guidedActionItemDescriptionStyle" />
+ </android.support.v17.leanback.widget.NonOverlappingLinearLayout>
+
+ <ImageView
+ android:id="@+id/guidedactions_item_chevron"
+ style="?attr/guidedActionItemChevronStyle"
+ tools:ignore="ContentDescription" />
+ <ImageView
+ android:id="@+id/guidedactions_item_tail_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="15dp"
+ android:adjustViewBounds="true"
+ android:src="@drawable/ic_draggable_white"
+ tools:ignore="ContentDescription" />
+</android.support.v17.leanback.widget.GuidedActionItemContainer> \ No newline at end of file
diff --git a/res/layout/program_guide_critic_score_layout.xml b/res/layout/program_guide_critic_score_layout.xml
new file mode 100644
index 00000000..bd643d7b
--- /dev/null
+++ b/res/layout/program_guide_critic_score_layout.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/critic_score_layout"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/program_guide_table_detail_critic_score_margin_start">
+
+ <TextView
+ android:id="@+id/critic_score_source"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@string/condensed_font"
+ android:textSize="@dimen/program_guide_table_critic_score_source_text_size" />
+
+ <ImageView
+ android:id="@+id/critic_score_logo"
+ android:layout_height="@dimen/program_guide_table_detail_critic_score_logo_dimen"
+ android:layout_width="@dimen/program_guide_table_detail_critic_score_logo_dimen"
+ android:layout_gravity="center"
+ android:scaleType="centerInside"
+ android:layout_marginStart="@dimen/program_guide_table_detail_critic_score_logo_margin_start"/>
+
+ <TextView
+ android:id="@+id/critic_score_score"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="@string/condensed_font"
+ android:textSize="@dimen/program_guide_table_critic_score_score_text_size"
+ android:layout_marginStart="@dimen/program_guide_table_detail_critic_score_score_margin_start" />
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/program_guide_table_row.xml b/res/layout/program_guide_table_row.xml
index c6c46e64..63dcf351 100644
--- a/res/layout/program_guide_table_row.xml
+++ b/res/layout/program_guide_table_row.xml
@@ -18,7 +18,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
- android:layout_height="wrap_content" >
+ android:layout_height="wrap_content"
+ android:focusable="false" >
+ <!-- focusable is set false to prevent accessibility focus being put on this layout -->
<include layout="@layout/program_guide_table_header_column_item" />
diff --git a/res/layout/program_guide_table_row_detail.xml b/res/layout/program_guide_table_row_detail.xml
index fff3afae..9fd18e99 100644
--- a/res/layout/program_guide_table_row_detail.xml
+++ b/res/layout/program_guide_table_row_detail.xml
@@ -80,6 +80,7 @@
android:textColor="@color/program_guide_table_detail_time_text_color" />
<include layout="@layout/program_track_meta"
+ android:id="@+id/program_track_meta"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/time"
@@ -87,6 +88,49 @@
android:layout_marginStart="@dimen/program_guide_table_detail_meta_margin_start"
android:layout_marginBottom="@dimen/program_guide_table_detail_meta_margin_bottom" />
+ <LinearLayout android:id="@+id/dvr_indicator"
+ android:orientation="horizontal"
+ android:layout_alignBottom="@id/time"
+ android:layout_toEndOf="@id/program_track_meta"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:visibility="gone" >
+
+ <ImageView android:id="@+id/dvr_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/program_guide_table_detail_dvr_drawable_padding"
+ android:layout_marginTop="@dimen/program_guide_table_detail_dvr_icon_margin_top"
+ android:layout_gravity="center" />
+
+ <TextView android:id="@+id/dvr_text_icon"
+ style="@style/track_meta_text"
+ android:text="@string/dvr_epg_program_icon_text"
+ android:layout_marginEnd="@dimen/program_guide_table_detail_dvr_drawable_padding"
+ android:layout_marginTop="@dimen/program_guide_table_detail_dvr_icon_margin_top"
+ android:layout_gravity="center"
+ android:visibility="gone" />
+
+ <TextView android:id="@+id/dvr_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:textSize="@dimen/program_guide_table_detail_dvr_text_size"
+ android:textColor="@color/program_guide_table_detail_dvr_text_color" />
+ </LinearLayout>
+
+ <!-- layout for the rotten tomatoes score -->
+ <LinearLayout
+ android:id="@+id/critic_scores"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignBottom="@id/time"
+ android:layout_toEndOf="@id/dvr_indicator"
+ android:layout_marginStart="@dimen/program_guide_table_detail_critic_scores_margin_start" >
+ </LinearLayout>
+
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
diff --git a/res/layout/program_track_meta.xml b/res/layout/program_track_meta.xml
index a5517f0a..e62427fa 100644
--- a/res/layout/program_track_meta.xml
+++ b/res/layout/program_track_meta.xml
@@ -20,19 +20,31 @@
android:layout_height="wrap_content">
<TextView android:id="@+id/closed_caption"
- style="@style/channel_banner_track_meta_text"
+ style="@style/track_meta_text.channel_banner"
android:visibility="gone" />
<TextView android:id="@+id/aspect_ratio"
- style="@style/channel_banner_track_meta_text"
+ style="@style/track_meta_text.channel_banner"
android:visibility="gone" />
<TextView android:id="@+id/resolution"
- style="@style/channel_banner_track_meta_text"
+ style="@style/track_meta_text.channel_banner"
android:visibility="gone" />
<TextView android:id="@+id/audio_channel"
- style="@style/channel_banner_track_meta_text"
+ style="@style/track_meta_text.channel_banner"
+ android:visibility="gone" />
+
+ <TextView android:id="@+id/content_ratings_0"
+ style="@style/track_meta_text.channel_banner"
+ android:visibility="gone" />
+
+ <TextView android:id="@+id/content_ratings_1"
+ style="@style/track_meta_text.channel_banner"
+ android:visibility="gone" />
+
+ <TextView android:id="@+id/content_ratings_2"
+ style="@style/track_meta_text.channel_banner"
android:visibility="gone" />
</LinearLayout>
diff --git a/res/layout/tunable_tv_view.xml b/res/layout/tunable_tv_view.xml
index 6c45caa8..e02fb892 100644
--- a/res/layout/tunable_tv_view.xml
+++ b/res/layout/tunable_tv_view.xml
@@ -16,6 +16,13 @@
-->
<merge xmlns:android="http://schemas.android.com/apk/res/android" >
+ <View
+ android:id="@+id/block_screen_for_tune"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/black" />
+
<include layout="@layout/block_screen"
android:id="@+id/hide_screen" />
@@ -27,13 +34,6 @@
android:background="@android:color/transparent"
android:layout_gravity="center" />
- <View
- android:id="@+id/block_screen_for_tune"
- android:visibility="gone"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@android:color/black" />
-
<include layout="@layout/block_screen"
android:id="@+id/block_screen" />
diff --git a/res/values-af/arrays.xml b/res/values-af/arrays.xml
index f0513f6a..1f94e3ce 100644
--- a/res/values-af/arrays.xml
+++ b/res/values-af/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Vol"</item>
<item msgid="8568284598210500589">"Zoem"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alle kanale"</item>
- <item msgid="6897460857821394118">"Gesin/kinders"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Inkopies"</item>
- <item msgid="3296058637230163031">"Flieks"</item>
- <item msgid="1054540282883891201">"Komedie"</item>
- <item msgid="7900158429062595471">"Reis"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Opvoeding"</item>
- <item msgid="7396447839483867269">"Diere/natuur"</item>
- <item msgid="4738043455148062673">"Nuus"</item>
- <item msgid="7405041316051047427">"Speletjies"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alle kanale"</item>
- <item msgid="7909003973960375395">"Gesin/kinders"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Inkopies"</item>
- <item msgid="6083795019290250078">"Flieks"</item>
- <item msgid="8302638329222449550">"Komedie"</item>
- <item msgid="3803709976021475052">"Reis"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Opvoeding"</item>
- <item msgid="7511135485827589547">"Diere/natuur"</item>
- <item msgid="6961248112238009967">"Nuus"</item>
- <item msgid="6484685553679698447">"Speletjies"</item>
- <item msgid="2737158328243183190">"Kunste"</item>
- <item msgid="6577176952650166615">"Vermaak"</item>
- <item msgid="7886693831871777617">"Leefstyl"</item>
- <item msgid="8145832312485577062">"Musiek"</item>
- <item msgid="1345789204804308580">"Beste"</item>
- <item msgid="2736680312770771994">"Tegnologie/wetenskap"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alle kanale"</item>
+ <item msgid="928298872841713530">"Gesin/kinders"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Inkopies"</item>
+ <item msgid="167201149441442173">"Flieks"</item>
+ <item msgid="525966731464264290">"Komedie"</item>
+ <item msgid="6096710741527327836">"Reis"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Opvoeding"</item>
+ <item msgid="7221999662426308394">"Diere/natuur"</item>
+ <item msgid="375300513250925001">"Nuus"</item>
+ <item msgid="7746320336582330410">"Speletjies"</item>
+ <item msgid="1255741860568329178">"Kunste"</item>
+ <item msgid="7603949681065702867">"Vermaak"</item>
+ <item msgid="4453821994746804366">"Leefstyl"</item>
+ <item msgid="3488534597567932843">"Musiek"</item>
+ <item msgid="7452153120614274095">"Beste"</item>
+ <item msgid="8215762047341133299">"Tegnologie/wetenskap"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Regstreekse Kanale"</item>
diff --git a/res/values-af/rating_system_strings.xml b/res/values-af/rating_system_strings.xml
index eb2883cf..84d4a151 100644
--- a/res/values-af/rating_system_strings.xml
+++ b/res/values-af/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index f290edac..7778e751 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Vorige"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programgids"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nuwe kanale beskikbaar"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Geen skakel beskikbaar"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> oop"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Onderskrifte"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Vertoonmodus"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subgraderings"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Voer jou PIN in om hierdie kanaal te kyk"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Voer jou PIN in om hierdie program te kyk"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Hierdie program is <xliff:g id="RATING">%1$s</xliff:g> gegradeer. Voer jou PIN in om hierdie program te kyk"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Voer jou PIN in"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Skep \'n PIN om ouerkontroles op te stel"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Voer nuwe PIN in"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Oopbronlisensies"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Oopbronlisensies"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Weergawe"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Help om Regstreekse Kanale te verbeter"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Deel anonieme gebruik- en diagnostiese data met Google sodat ons Regstreekse Kanale beter kan maak en kwessies soos omval en vries kan voorkom."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Druk Regs en voer jou PIN in om hierdie kanaal te kyk"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Druk Regs en voer jou PIN in om hierdie program te kyk"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Hierdie program is <xliff:g id="RATING">%1$s</xliff:g> gegradeer.\nDruk Regs en voer jou PIN in om hierdie program te kyk."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Net oudio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Swak sein"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Geen internetverbinding nie"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Hierdie kanaal kan nie voor <xliff:g id="END_TIME_1">%1$s</xliff:g> gespeel word nie omdat ander kanale tans opgeneem word. \n\nDruk Regs om die opnameskedule te verstel.</item>
+ <item quantity="one">Hierdie kanaal kan nie voor <xliff:g id="END_TIME_0">%1$s</xliff:g> gespeel word nie omdat \'n ander kanaal tans opgeneem word. \n\nDruk Regs om die opnameskedule te verstel.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Titelloos"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanaal is geblokkeer"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nuut"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Geen kanale is beskikbaar nie"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nuut"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nie opgestel nie"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Kry nog bronne"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Blaai deur programme wat regstreekse kanale bied"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Kry nog bronne"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Blaai deur programme wat regstreekse kanale bied"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nuwe kanaalbronne is beskikbaar"</string>
<string name="new_sources_description" msgid="749649005588426813">"Nuwe kanaalbronne kan kanale bied.\nStel hulle nou op of doen dit later in die kanaalbronne-instelling."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Stel nou op"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alle bronkanale is versteek.\nKies minstens een kanaal om te kyk."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Die video is onverwags onbeskikbaar"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"TERUG-sleutel is vir gekoppelde toestelle. Druk TUIS-knoppie om uit te gaan."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Regstreekse kanale word nie op hierdie toestel met Android Lollipop gesteun nie."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Regstreekse kanale het toestemming nodig om die TV-lysinskrywings te lees."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Stel jou bronne op"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Regstreekse kanale kombineer die ervaring van tradisionele TV-kanale met stroomkanale wat deur programme verskaf word. \n\nBegin deur die kanaalbronne op te stel wat reeds geïnstalleer is. Of blaai deur die Google Play Winkel vir meer programme wat regstreekse kanale bied."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Opnames en skedules"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minute"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minute"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 uur"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ure"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Onlangs"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Geskeduleer"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Reeks"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Ander"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Die kanaal kan nie opgeneem word nie."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Die program kan nie opgeneem word nie."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> is geskeduleer om opgeneem te word"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Neem <xliff:g id="PROGRAMNAME">%1$s</xliff:g> op van nou af tot <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Volledige skedule"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Volgende %1$d dae</item>
+ <item quantity="one">Volgende %1$d dag</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minute</item>
+ <item quantity="one">%1$d minuut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nuwe opnames</item>
+ <item quantity="one">%1$d nuwe opname</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d opnames</item>
+ <item quantity="one">%1$d opname</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d opnames geskeduleer</item>
+ <item quantity="one">%1$d opname geskeduleer</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Kyk"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Speel van begin af"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Speel verder"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Vee uit"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Vee opnames uit"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Hervat"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Seisoen <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Bekyk skedule"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Lees meer"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Vee opnames uit"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Kies die episodes wat jy graag wil uitvee. Sodra hulle uitgevee is, kan hulle nie teruggekry word nie."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Daar is geen opnames om uit te vee nie."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Kies gekykte episodes"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Kies alle episodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Ontkies alle episodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> van <xliff:g id="DURATION">%2$d</xliff:g> minute is gekyk"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> van <xliff:g id="DURATION">%2$d</xliff:g> sekondes is gekyk"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nooit gekyk nie"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d van %2$d episodes is uitgevee</item>
+ <item quantity="one">%1$d van %2$d episode is uitgevee</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioriteit"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Hoogste"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Laagste"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanale"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Enige"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Kies prioriteit"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"As daar te veel programme is wat op dieselfde tyd opgeneem moet word, sal net die programme met die hoër prioriteit opgeneem word."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Stoor"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Eenmalige opnames het die hoogste prioriteit"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Kanselleer"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Kanselleer"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Vergeet"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stop"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Bekyk opnameskedule"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Net hierdie een program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"nou – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Die hele reeks …"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Skeduleer in elk geval"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Neem eerder hierdie een op"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Kanselleer hierdie opname"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Kyk nou"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kan opgeneem word"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Opname geskeduleer"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Opneemkonflik"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Neem tans op"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Kon nie opneem nie"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lees tans programme om opneemskedules te skep"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Leesprogramme"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR het meer berging nodig"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Jy sal programme met DVR kan opneem. DVR werk egter nie op die oomblik nie omdat daar nie genoeg berging op jou toestel beskikbaar is nie. Koppel asseblief \'n eksterne hardeskryf wat <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB of groter is en volg die stappe om dit as toestelberging te formateer."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Berging ontbreek"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Van die berging wat DVR gebruik, ontbreek. Koppel asseblief die eksterne skyf wat jy vroeër gebruik het om DVR te heraktiveer. Andersins kan jy kies om die berging te vergeet as dit nie meer beskikbaar is nie."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Vergeet berging?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Al jou opgeneemde inhoud en skedules sal verloor word."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Stop opname?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Die opgeneemde inhoud sal gestoor word."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Opname is geskeduleer, maar daar is botsings"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Opname het begin, maar daar is konflikte"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> sal opgeneem word."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> word tans opgeneem."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Sommige dele van <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> sal nie opgeneem word nie."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Sommige dele van <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> en <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> sal nie opgeneem word nie."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Sommige dele van <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> en nog een skedule sal nie opgeneem word nie."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Sommige dele van <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> en nog %3$d skedules sal nie opgeneem word nie.</item>
+ <item quantity="one">Sommige dele van <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> en nog %3$d skedule sal nie opgeneem word nie.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Wat wil jy graag opneem?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hoe lank wil jy opneem?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Reeds geskeduleer"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Dieselfde program is reeds geskeduleer om om <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> opgeneem te word."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Reeds opgeneem"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Hierdie program is reeds opgeneem. Dit is in die DVR-biblioteek beskikbaar."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Kon nie opgeneemde program vind nie."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Verwante opnames"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Geen programbeskrywing nie)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d opnames</item>
+ <item quantity="one">%1$d opname</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> is uit opneemskedule verwyder"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Sal weens seinontvangerkonflikte gedeeltelik opgeneem word."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Sal weens seinontvangerkonflikte nie opgeneem word nie."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Geen opnames is al geskeduleer nie.\nJy kan opnames uit die programgids skeduleer."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d opneemkonflikte</item>
+ <item quantity="one">%1$d opneemkonflik</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Reeks se instellings"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Begin om reeks op te neem"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stop om reeks op te neem"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Stop om reeks op te neem?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Opgeneemde episodes sal in die DVR-biblioteek beskikbaar bly."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stop"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Geen episodes is beskikbaar nie.\nHulle sal opgeneem word sodra hulle beskikbaar is."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minute)</item>
+ <item quantity="one">(%1$d minuut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Vandag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Môre"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Gister"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Vandag <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Môre <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Telling"</string>
</resources>
diff --git a/res/values-am/arrays.xml b/res/values-am/arrays.xml
index 137c932a..bed9cdf7 100644
--- a/res/values-am/arrays.xml
+++ b/res/values-am/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"ሙሉ"</item>
<item msgid="8568284598210500589">"አጉላ"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ሁሉም ሰርጦች"</item>
- <item msgid="6897460857821394118">"ቤተሰብ/ህጻናት"</item>
- <item msgid="551257741825778215">"ስፖርት"</item>
- <item msgid="452133796804325879">"ግዢ"</item>
- <item msgid="3296058637230163031">"ፊልሞች"</item>
- <item msgid="1054540282883891201">"ኮሜዲ"</item>
- <item msgid="7900158429062595471">"ጉዞ"</item>
- <item msgid="3768998587825611787">"ድራማ"</item>
- <item msgid="8340620094959282881">"ትምህርት"</item>
- <item msgid="7396447839483867269">"እንስሳት/የዱር ህይወት"</item>
- <item msgid="4738043455148062673">"ዜና"</item>
- <item msgid="7405041316051047427">"ጨዋታ"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ሁሉም ሰርጦች"</item>
- <item msgid="7909003973960375395">"ቤተሰብ/ህጻናት"</item>
- <item msgid="3185279732911635789">"ስፖርት"</item>
- <item msgid="4704858492065325964">"ግዢ"</item>
- <item msgid="6083795019290250078">"ፊልሞች"</item>
- <item msgid="8302638329222449550">"ኮሜዲ"</item>
- <item msgid="3803709976021475052">"ጉዞ"</item>
- <item msgid="8116747365234169059">"ድራማ"</item>
- <item msgid="7356447541595315913">"ትምህርት"</item>
- <item msgid="7511135485827589547">"እንስሳት/የዱር ህይወት"</item>
- <item msgid="6961248112238009967">"ዜና"</item>
- <item msgid="6484685553679698447">"ጨዋታ"</item>
- <item msgid="2737158328243183190">"ኪነ ጥበባት"</item>
- <item msgid="6577176952650166615">"መዝናኛ"</item>
- <item msgid="7886693831871777617">"የአኗኗር ዘይቤ"</item>
- <item msgid="8145832312485577062">"ሙዚቃ"</item>
- <item msgid="1345789204804308580">"ፕሪሚየር"</item>
- <item msgid="2736680312770771994">"ቴክ/ሳይንስ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"ሁሉም ሰርጦች"</item>
+ <item msgid="928298872841713530">"ቤተሰብ/ህጻናት"</item>
+ <item msgid="2751606947569857164">"ስፖርት"</item>
+ <item msgid="7345749789651321496">"ግዢ"</item>
+ <item msgid="167201149441442173">"ፊልሞች"</item>
+ <item msgid="525966731464264290">"አስቂኝ"</item>
+ <item msgid="6096710741527327836">"ጉዞ"</item>
+ <item msgid="2851882187117833883">"ድራማ"</item>
+ <item msgid="78492781188719038">"ትምህርት"</item>
+ <item msgid="7221999662426308394">"እንስሳት/የዱር ህይወት"</item>
+ <item msgid="375300513250925001">"ዜና"</item>
+ <item msgid="7746320336582330410">"ጨዋታ"</item>
+ <item msgid="1255741860568329178">"ጥበባት"</item>
+ <item msgid="7603949681065702867">"መዝናኛ"</item>
+ <item msgid="4453821994746804366">"የአኗኗር ዘይቤ"</item>
+ <item msgid="3488534597567932843">"ሙዚቃ"</item>
+ <item msgid="7452153120614274095">"ፕሪሚየር"</item>
+ <item msgid="8215762047341133299">"ቴክኖሎጂ/ሳይንስ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"የቀጥታ ስርጭት ሰርጦች"</item>
diff --git a/res/values-am/rating_system_strings.xml b/res/values-am/rating_system_strings.xml
index 156efc47..b4bd5cc5 100644
--- a/res/values-am/rating_system_strings.xml
+++ b/res/values-am/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index f397b81e..bd63879b 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"ቀዳሚ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"የፕሮግራም መመሪያ"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"አዲስ ሰርጦች ይገኛሉ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ምንም አገናኝ የለም"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ክፈት"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"የተዘጉ የስዕል መግለጫዎች"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"የማሳያ ሁኔታ"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ንዑስ ደረጃዎች"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ይህን ሰርጥ ለመመልከት የእርስዎን ፒን ያስገቡ"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ይህን ፕሮግራም ለመመልከት የእርስዎን ፒን ያስገቡ"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ይህ ፕሮግራም የ<xliff:g id="RATING">%1$s</xliff:g> ደረጃ ተሰጥቶታል። ይህን ፕሮግራም ለመመልከት የእርስዎን ፒን ያስገቡ።"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"የእርስዎን ፒን ያስገቡ"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"የወላጅ መቆጣጠሪያዎችን ለማዋቀር ፒን ይፍጠሩ።"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"አዲስ ፒን ያስገቡ"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"የክፍት ምንጭ ፍቃዶች"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"የክፍት ምንጭ ፍቃዶች"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ስሪት"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Live TVን ለማሻሻል አግዝ"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"የቀጥታ ስርጭት ሰርጦችን የተሻሉ ማድረግ እንድንችል እና እንደ መሰናከል እና ቀጥ ማለት የመሳሰሉ ችግሮችን መከላከል እንድንችል ከGoogle ጋ ማንነትን የማያሳውቅ የአጠቃቀም እና የምርመራ ውሂብን ይጋሩ።"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ይህን ሰርጥ ለመመልከት ቀኝን ይጫኑ እና የእርስዎን ፒን ያስገቡ"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ይህን ፕሮግራም ለመመልከት ቀኝን ይጫኑ እና የእርስዎን ፒን ያስገቡ"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ይህ ፕሮግራም <xliff:g id="RATING">%1$s</xliff:g> ደረጃ ነው የተሰጠው።\nይህን ፕሮግራም ለመመልከት ቀኝን ይጫኑ እና የእርስዎን ፒን ያስገቡ።"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ኦዲዮ ብቻ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"ደካማ ምልክት"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ምንም የበይነመረብ ግንኙነት የለም"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">ሌሎች ጣቢያዎች እየተቀዱ ስለሆኑ ይህ ሰርጥ እስከ <xliff:g id="END_TIME_1">%1$s</xliff:g> ድረስ መጫወት አይችልም፡ \n\nየመቅረጫ ጊዜ መርሐግብርን ለማስተካከል ቀኝ ይጫኑ።</item>
+ <item quantity="other">ሌሎች ጣቢያዎች እየተቀዱ ስለሆኑ ይህ ሰርጥ እስከ <xliff:g id="END_TIME_1">%1$s</xliff:g> ድረስ መጫወት አይችልም፡ \n\nየመቅረጫ ጊዜ መርሐግብርን ለማስተካከል ቀኝ ይጫኑ።</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ርእስ የለውም"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"ሰርጥ ታግዷል"</string>
<string name="setup_category_new" msgid="2899355289563443627">"አዲስ"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ምንም ሰርጦች አይገኙም"</string>
<string name="setup_input_new" msgid="3337725672277046798">"አዲስ"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"አልተዋቀረም"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"ተጨማሪ ምንጮችን ያግኙ"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"የቀጥታ ስርጭት ሰርጦችን የሚያቀርቡ መተግበሪያዎችን ያስሱ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"ተጨማሪ ምንጮችን ያግኙ"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"የቀጥታ ስርጭት ሰርጦችን የሚያቀርቡ መተግበሪያዎችን ያስሱ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"አዲስ የሰርጥ ምንጮች ይገኛሉ"</string>
<string name="new_sources_description" msgid="749649005588426813">"አዲስ የሰርጥ ምንጮች የሚያቀርቧቸው ሰርጦች አሏቸው።\nአሁን ያዋቅሯቸው፣ ወይም ደግሞ ይህን በኋላ ላይ በሰርጥ ምንጮች ቅንብር ውስጥ ያድርጉት።"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"አሁን ያዋቅሩ"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ሁሉም የምንጭ ሰርጦች ተደብቀዋል።\nቢያንስ አንድ የሚመለከቱት ሰርጥ ይምረጡ።"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ቪዲዮው በማይጠበቅ ሁኔታ የማይገኝ ሆኗል"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK ቁልፍ ለተገናኙ መሳሪያዎች። ለመውጣት HOME አዝራርን ይጫኑ።"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"ቀጥተኛ ሰርጦች እዚህ መሣሪያ ላይ በAndroid Lollipop አይደገፉም።"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"ቀጥተኛ ሰርጦች የቴሌቪዥን ዝርዝሮችን ለማንበብ ፍቃድ ያስፈልጋቸዋል።"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"የእርስዎን ምንጮች ያቀናብሩ"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"የቀጥታ ስርጭት ሰርጦች የተለምዷዊ ቴሌቪዥን ጣቢያዎች እና በመተግበሪያዎች የሚቀርቡ የዥረት ሰርጦች ተሞክሮን ያጣምራሉ። \n\nአስቀድመው የተጫኑ የሰርጥ ምንጮችን በማቀናበር ይጀምሩ። ወይም ደግሞ የቀጥታ ሰርጦችን የሚያቀርቡ ተጨማሪ መተግበሪያዎችን ለማግኘት Google Play መደብርን ያስሱ።"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ቀረጻዎች እና መርሐግብሮች"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 ደቂቃዎች"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 ደቂቃዎች"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ሰዓት"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ሰዓቶች"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"የቅርብ ጊዜ"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"መርሐግብር የተያዘለት"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"ተከታታይ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"ሌሎች"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ሰርጡ ሊቀረጽ አልቻለም።"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"ፕሮግራሙ ሊቀረጽ አልቻለም።"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ለምዝገባ መርሐግብር ተይዞለታል"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ከአሁን ወደ <xliff:g id="ENDTIME">%2$s</xliff:g> በመቅረጽ ላይ"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"ሙሉ የጊዜ መርሐግብር"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">ቀጣይ %1$d ቀኖች</item>
+ <item quantity="other">ቀን %1$d ቀኖች</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d ደቂቃዎች</item>
+ <item quantity="other">%1$d ደቂቃዎች</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d አዳዲስ ቀረጻዎች</item>
+ <item quantity="other">%1$d አዳዲስ ቀረጻዎች</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d ቀረጻዎች</item>
+ <item quantity="other">%1$d ቀረጻዎች</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d ቀረጻዎች በመርሐግብር ተይዘዋል</item>
+ <item quantity="other">%1$d ቀረጻዎች በመርሐግብር ተይዘዋል</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ይመልከቱ"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"ከመጀመሪያው አጫውት"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ከቆመበት ቀጥል"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"ሰርዝ"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ቀረጻዎችን ሰርዝ"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"ከቆመበት ቀጥል"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"ምዕራፍ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"መርሐግብር ይመልከቱ"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"ተጨማሪ ያንብቡ"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ቀረጻዎችን ይሰርዙ"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ሊሰርዟቸው የሚፈልጓቸውን ክፍሎች ይምረጡ። አንዴ ከተሰረዙ በኋላ ተመልሰው ሊገኙ አይችሉም።"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ምንም የሚሰረዙ ቀረጻዎች የሉም።"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"የታዩ ክፍሎችን ምረጥ"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"ሁሉንም ክፍሎች ምረጥ"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ሁሉንም ክፍሎች አትምረጥ"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> ከ<xliff:g id="DURATION">%2$d</xliff:g> ደቂቃዎች ታይቷል"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> ከ<xliff:g id="DURATION">%2$d</xliff:g> ሰከንዶች ታይቷል"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"በጭራሽ ያልታዩ"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d ከ%2$d ክፍሎች ተሰርዘዋል</item>
+ <item quantity="other">%1$d ከ%2$d ክፍሎች ተሰርዘዋል</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ቅድሚያ የሚሰጣቸው"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"በጣም ከፍተኛው"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ዝቅተኛ"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"አይ። <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ሰርጦች"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ማንኛውም"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ቅድሚያ ተሰጭነትን ይመርጡ"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"በተመሳሳዩ ጊዜ ላይ የሚቀረጹ በጣም ብዙ ፕሮግራሞች ሲኖሩ ከፍ ያለ ቅድሚያ ያላቸው ብቻ ናቸው የሚቀረጹት።"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"አስቀምጥ"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"የአንድ-ጊዜ ቀረጻዎች ከፍተኛ ቅድሚያ ተሰጭነት አላቸው"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"ይቅር"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"ተወው"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"እርሳ"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"አቁም"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"የምዝገባ መርሐግብርን ይመልከቱ"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ይህ ነጠላ ፕሮግራም"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"አሁን - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"መላው ተከታታይ..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"ለማንኛውም መርሐግብር አስይዝ"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"በምትኩ ይሄኛውን ቅረጽ"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ይህን ቀረጻ ተወው"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"አሁን ይመልከቱ"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ሊቀረጽ የሚችል"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ቀረጻ መርሐግብር ተይዞለታል"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"የቀረጻ ግጭት"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"መቅዳት"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"መቅረጽ አልተሳካም"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"የቀረጻ መርሐግብሮችን ለመፍጠር ፕሮግራሞችን በማንበብ ላይ"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"ፕሮግራሞችን በማንበብ ላይ"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"ዲቪአር ተጨማሪ ማከማቻ ያስፈልገዋል"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"ፕሮግራሞችን በዲቪአር መቅረጽ ይችላሉ። ይሁንና አሁን ዲቪአር እንዲሰራ በመሣሪያዎ ላይ በቂ የማከማቻ ቦታ የለም። እባክዎ <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> ጊባ ወይም ከዚያ በላይ የሆነ ውጫዊ አንጻፊ ይሰኩና እንደ የመሣሪያ ማከማቻ ቅርጸት ለመስራት ያሉትን ደረጃዎች ይከተሉ።"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"የሚጎድል ማከማቻ"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"በDVR ጥቅም ላይ የዋለ አንዳንድ ማከማቻ ይጎድላል። DVRን ዳግም ለማንቃት ከዚህ በፊት የሚጠቀሙበትን ውጫዊ አንጻፊ እባክዎ ያገናኙ። በአማራጭነት፣ ከእንግዲህ የማይገኝ ከሆነ ማከማቻውን ለመርሳት መምረጥ ይችላሉ።"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ማከማቻ ይረሳ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"ሁሉም የእርስዎ የተቀዳ ይዘት እና መርሐግብሮች ይጠፋሉ።"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"መቅረጽ ይቁም?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"የተቀረጸው ይዘት ይቀመጣል።"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ምዝገባ መርሐግብር ተይዞለታል፣ ነገር ግን ግጭቶች አሉ"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ቀረጻ ተጀምሯል፣ ነገር ግን ግጭቶች አሉት"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ይቀረጻል።"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> እየተቀረጸ ነው።"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"አንዳንድ የ<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ክፍሎች አይቀረጹም።"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"አንዳንድ የ<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> እና የ<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ክፍሎች አይቀረጹም።"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"አንዳንድ የ<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>፣ <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> እና አንድ ተጨማሪ መርሐግብር ክፍሎች አይቀረጹም።"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">አንዳንድ የ<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>፣ <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> እና %3$d ተጨማሪ መርሐግብሮች ክፍሎች አይቀረጹም።</item>
+ <item quantity="other">አንዳንድ የ<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>፣ <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> እና %3$d ተጨማሪ መርሐግብሮች ክፍሎች አይቀረጹም።</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"ምን መመዝገብ ይፈልጋሉ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"እስከ መቼ ድረስ ነው መቅረጽ የሚፈልጉት?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"አስቀድሞ በመርሐግብር ተይዞለታል"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"ተመሳሳዩ ፕሮግራም አስቀድሞ በ<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> ላይ እንዲቀረጽ መርሐግብር ተይዞለታል።"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"አስቀድሞ ተቀርጿል"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ይህ ፕሮግራም አስቀድሞ ተቀርጿል። በዲቪአር ቤተ-መጽሐፍት ውስጥ ይገኛል።"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"የተቀረጸ ፕሮግራም አልተገኘም።"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ተዛማጅ ቀረጻዎች"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ምንም የፕሮግራም መግለጫ የለም)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d ቀረጻዎች</item>
+ <item quantity="other">%1$d ቀረጻዎች</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ከቀረጻ መርሐግብር ተወግዷል"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"በመቃኛ ግጭቶች ምክንያት በከፊል የሚቀዳ ይሆናል።"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"በመቃኛ ግጭቶች ምክንያት ሊቀዳ አይችልም።"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ገና ምንም መርሐግብር የተያዘላቸው ቀረጻዎች የሉም።\nከፕሮግራም መመሪያው ሆነው ቀረጻን መርሐግብር ማስያዝ ይችላሉ።"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d የቀረጻ ግጭቶች</item>
+ <item quantity="other">%1$d የቀረጻ ግጭቶች</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"የተከታታዮች ቅንብሮች"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"የተከታታይ ቀረጻን ጀምር"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"የተከታታይ ቀረጻን አቁም"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"የተከታታይ ቀረጻ ይቆም?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"የተቀረጹ ክፍሎች በዲቪአር ቤተ-መጽሐፍቱ ላይ የሚገኙ እንደሆኑ ይቆያሉ።"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"አቁም"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ምንም ክፍሎች አይገኙም።\nልክ የሚገኙ ሲሆኑ ይቀረጻሉ።"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d ደቂቃዎች)</item>
+ <item quantity="other">(%1$d ደቂቃዎች)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ዛሬ"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"ነገ"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ትላንት"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ዛሬ"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ነገ"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ነጥብ"</string>
</resources>
diff --git a/res/values-ar/arrays.xml b/res/values-ar/arrays.xml
index 160838e1..30874771 100644
--- a/res/values-ar/arrays.xml
+++ b/res/values-ar/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"كامل"</item>
<item msgid="8568284598210500589">"تكبير/تصغير"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"كل القنوات"</item>
- <item msgid="6897460857821394118">"العائلات/الأطفال"</item>
- <item msgid="551257741825778215">"الرياضة"</item>
- <item msgid="452133796804325879">"التسوق"</item>
- <item msgid="3296058637230163031">"الأفلام"</item>
- <item msgid="1054540282883891201">"الكوميديا"</item>
- <item msgid="7900158429062595471">"السفر"</item>
- <item msgid="3768998587825611787">"الدراما"</item>
- <item msgid="8340620094959282881">"التعليم"</item>
- <item msgid="7396447839483867269">"حيوانات/حياة برية"</item>
- <item msgid="4738043455148062673">"الأخبار"</item>
- <item msgid="7405041316051047427">"ألعاب الفيديو"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"كل القنوات"</item>
- <item msgid="7909003973960375395">"العائلات/الأطفال"</item>
- <item msgid="3185279732911635789">"الرياضة"</item>
- <item msgid="4704858492065325964">"التسوق"</item>
- <item msgid="6083795019290250078">"الأفلام"</item>
- <item msgid="8302638329222449550">"الكوميديا"</item>
- <item msgid="3803709976021475052">"السفر"</item>
- <item msgid="8116747365234169059">"الدراما"</item>
- <item msgid="7356447541595315913">"التعليم"</item>
- <item msgid="7511135485827589547">"حيوانات/حياة برية"</item>
- <item msgid="6961248112238009967">"الأخبار"</item>
- <item msgid="6484685553679698447">"ألعاب الفيديو"</item>
- <item msgid="2737158328243183190">"الفنون"</item>
- <item msgid="6577176952650166615">"الترفيه"</item>
- <item msgid="7886693831871777617">"نمط الحياة"</item>
- <item msgid="8145832312485577062">"الموسيقى"</item>
- <item msgid="1345789204804308580">"العرض الأول"</item>
- <item msgid="2736680312770771994">"التكنولوجيا / العلوم"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"كل القنوات"</item>
+ <item msgid="928298872841713530">"الأسرة/الأطفال"</item>
+ <item msgid="2751606947569857164">"رياضة"</item>
+ <item msgid="7345749789651321496">"تسوّق"</item>
+ <item msgid="167201149441442173">"أفلام"</item>
+ <item msgid="525966731464264290">"كوميديا"</item>
+ <item msgid="6096710741527327836">"سفر"</item>
+ <item msgid="2851882187117833883">"دراما"</item>
+ <item msgid="78492781188719038">"تعليم"</item>
+ <item msgid="7221999662426308394">"حيوانات/حياة برية"</item>
+ <item msgid="375300513250925001">"أخبار"</item>
+ <item msgid="7746320336582330410">"ألعاب"</item>
+ <item msgid="1255741860568329178">"الفنون"</item>
+ <item msgid="7603949681065702867">"ترفيه"</item>
+ <item msgid="4453821994746804366">"نمط حياة"</item>
+ <item msgid="3488534597567932843">"موسيقي"</item>
+ <item msgid="7452153120614274095">"العرض الأول"</item>
+ <item msgid="8215762047341133299">"تكنولوجيا/علوم"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"قنوات البث التلفزيوني المباشر"</item>
diff --git a/res/values-ar/rating_system_strings.xml b/res/values-ar/rating_system_strings.xml
index 997a0f41..25d2ae7d 100644
--- a/res/values-ar/rating_system_strings.xml
+++ b/res/values-ar/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 6061f180..f91139b9 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"السابق"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"دليل البرامج"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"تتوفر قنوات جديدة"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"لا يتوفر أي رابط"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"فتح <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"التسميات التوضيحية المغلقة"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"وضع العرض"</string>
@@ -128,6 +127,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"تقييمات فرعية"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"أدخل رقم التعريف الشخصي لمشاهدة هذه القناة"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"أدخل رقم التعريف الشخصي لمشاهدة هذا البرنامج"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"هذا البرنامج يحمل التقييم <xliff:g id="RATING">%1$s</xliff:g>. يمكنك إدخال رقم التعريف الشخصي لمشاهدة هذا البرنامج"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"أدخل رقم التعريف الشخصي"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"لتعيين عناصر التحكم الأبوي، عليك إنشاء رقم تعريف شخصي"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"إدخال رقم تعريف شخصي جديد"</string>
@@ -152,8 +152,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"تراخيص البرامج المفتوحة المصدر"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"تراخيص البرامج المفتوحة المصدر"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"الإصدار"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"المساعدة في تحسين القنوات المباشرة"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"‏يمكنك مشاركة بيانات مجهولة المصدر حول الاستخدام والتشخيص باستخدام Google، حتى نتمكن من تحسين تطبيق البث التلفزيوني المباشر ومنع حدوث مشكلات مثل الأعطال والتجميد."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"لمشاهدة هذه القناة، اضغط على اليمين وأدخل رقم التعريف الشخصي"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"لمشاهدة هذا البرنامج، اضغط على اليمين وأدخل رقم التعريف الشخصي"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"تم تصنيف هذا البرنامج على أنه <xliff:g id="RATING">%1$s</xliff:g>.\nلمشاهدة هذا البرنامج، اضغط على اليمين وأدخل رقم التعريف الشخصي."</string>
@@ -165,6 +163,14 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"الصوت فقط"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"الإشارة ضعيفة"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"عدم توفر اتصال بالإنترنت"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="zero">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_1">%1$s</xliff:g> لأنه يجري تسجيل قنوات أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ <item quantity="two">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_1">%1$s</xliff:g> لأنه يجري تسجيل قنوات أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ <item quantity="few">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_1">%1$s</xliff:g> لأنه يجري تسجيل قنوات أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ <item quantity="many">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_1">%1$s</xliff:g> لأنه يجري تسجيل قنوات أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ <item quantity="other">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_1">%1$s</xliff:g> لأنه يجري تسجيل قنوات أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ <item quantity="one">يتعذر تشغيل هذه القناة حتى <xliff:g id="END_TIME_0">%1$s</xliff:g> لأنه يجري تسجيل قناة أخرى الآن. \n\nيمكنك الضغط على \"اليمين\" لضبط الجدول الزمني للتسجيل.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"بلا عنوان"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"تم حظر القناة"</string>
<string name="setup_category_new" msgid="2899355289563443627">"جديدة"</string>
@@ -180,8 +186,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"لا تتوفر أية قناة"</string>
<string name="setup_input_new" msgid="3337725672277046798">"جديد"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"لم يتم الإعداد"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"الحصول على مزيد من المصادر"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"تصفح التطبيقات التي تقدم قنوات مباشرة"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"الحصول على مزيد من المصادر"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"تصفح التطبيقات التي تقدم تطبيق البث التلفزيوني المباشر"</string>
<string name="new_sources_title" msgid="3878933676500061895">"مصادر قنوات جديدة متاحة"</string>
<string name="new_sources_description" msgid="749649005588426813">"هناك مصادر قنوات جديدة تعرض قنوات. \n يمكنك إعدادها الآن أو لاحقًا حسب ما يتم تعيينه في إعداد مصادر القنوات."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"الإعداد الآن"</string>
@@ -199,8 +205,202 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"كل قنوات المصدر مخفية.\nحدد على الأقل قناة واحدة لمشاهدتها."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"الفيديو غير متوفر بشكل مفاجئ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"زر الرجوع مخصص للجهاز المتصل. يمكنك الضغط على زر الصفحة الرئيسية للخروج."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"‏القنوات المباشرة غير متوافقة على هذا الجهاز مع Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"‏تحتاج القنوات المباشرة إلى إذن لقراءة قوائم TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"إعداد مصادرك"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"‏تجمع قنوات البث التلفزيوني المباشر بين تجربة قنوات التلفزيون التقليدية وقنوات البث التي توفِّرها التطبيقات. \n\nيمكنك البدء من خلال إعداد مصادر القنوات المثبَّتة حاليًا، أو تصفُّح متجر Google Play للحصول على المزيد من التطبيقات التي توفِّر قنوات بث تلفزيوني مباشر."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"التسجيلات والجداول الزمنية"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 دقائق"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 دقيقة"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"ساعة واحدة"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ساعات"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"حديثة"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"مجدولة"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"مسلسلة"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"غير ذلك"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"يتعذر تسجيل القناة."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"يتعذر تسجيل البرنامج."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"تمت إضافة جدول زمني لإجراء تسجيل لبرنامج <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"جارٍ تسجيل <xliff:g id="PROGRAMNAME">%1$s</xliff:g> من الآن حتى <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"الجدول الزمني كاملاً"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <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">يوم واحد قادم</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <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="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <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="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <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">تسجيل واحد</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <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="dvr_detail_watch" msgid="7085694764364338215">"مشاهدة"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"تشغيل من البداية"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"استئناف التشغيل"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"حذف"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"حذف التسجيلات"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"استئناف"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"الموسم <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"عرض الجدول الزمني"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"مزيد من المعلومات"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"حذف التسجيلات"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"حدِّد الحلقات التي تريد حذفها، علمًا بأنه لا يمكن استردادها بعد الحذف."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"لا تتوفر تسجيلات لحذفها."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"تحديد الحلقات التي تمت مشاهدتها"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"تحديد جميع الحلقات"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"إلغاء تحديد جميع الحلقات"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"تمت مشاهدة <xliff:g id="WATCHED">%1$d</xliff:g> من إجمالي <xliff:g id="DURATION">%2$d</xliff:g> دقيقة"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"تمت مشاهدة <xliff:g id="WATCHED">%1$d</xliff:g> من إجمالي <xliff:g id="DURATION">%2$d</xliff:g> ثانية"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"لم تسبق مشاهدتها"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="zero">‏تم حذف %1$d من إجمالي %2$d حلقة</item>
+ <item quantity="two">‏تم حذف %1$d من إجمالي حلقتين (%2$d)</item>
+ <item quantity="few">‏تم حذف %1$d من إجمالي %2$d حلقات</item>
+ <item quantity="many">‏تم حذف %1$d من إجمالي %2$d حلقة</item>
+ <item quantity="other">‏تم حذف %1$d من إجمالي %2$d حلقة</item>
+ <item quantity="one">‏تم حذف %1$d من إجمالي %2$d حلقة</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"الأولوية"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"الأعلى"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"الأقل"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"رقم <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"القنوات"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"أي مسلسل"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"اختيار الأولوية"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"عندما تكون هناك برامج كثيرة جدًا مطلوب تسجيلها في آنٍ واحد، فلن يتم تسجيل أي برامج منها إلا تلك ذات القدر الأعلى من الأولوية فقط."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"حفظ"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"تسجيلات المرة الواحدة لها الأولوية القصوى"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"إلغاء"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"إلغاء"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"حذف"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"إيقاف"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"عرض جدول عمليات التسجيل الزمني"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"هذا البرنامج وحده"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"الآن - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"المسلسل كاملاً ..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"إعداد جدول زمني على أي حال"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"تسجيل هذا بدلاً من ذلك"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"إلغاء هذا التسجيل"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"المشاهدة الآن"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"قابل للتسجيل"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"تمتّ جدولة التسجيل"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"تعارض في التسجيل"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"جارٍ التسجيل"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"أخفق التسجيل"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"جارٍ قراءة البرامج لإنشاء جداول زمنية للتسجيل"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"جارٍ قراءة البرامج"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"يحتاج مسجِّل الفيديو الرقمي إلى المزيد من السعة التخزينية"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"ستتمكن من تسجيل البرامج باستخدام مسجّل الفيديو الرقمي؛ ولكن ليست هناك سعة تخزينية كافية على جهازك الآن ليعمل مسجِّل الفيديو الرقمي. يُرجى توصيل محرك أقراص خارجي بسعة تخزين <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>غيغابايت أو أكبر واتباع الخطوات لتهيئته كوحدة تخزين للجهاز."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"سعة التخزين المفقودة"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"‏بعض سعة التخزين المستخدمة في جهاز DVR مفقود. يُرجى توصيل محرك الأقراص الخارجي الذي سبق لك استخدامه لإعادة تمكين جهاز DVR. بدلاً من ذلك، يمكنك اختيار حذف سعة التخزين إذا لم تعد متاحة."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"هل تريد حذف سعة التخزين؟"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"سيتم فقد جميع المحتويات والجداول الزمنية المسجَّلة."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"هل تريد إيقاف التسجيل؟"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"سيتم حفظ المحتوى الذي تم تسجيله."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"تمت إضافة جدول زمني لإجراء التسجيل ولكنه يتعارض مع جداول زمنية أخرى"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"تم بدء التسجيل ولكنه يتعارض مع جداول زمنية أخرى"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"لن يتم تسجيل <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"يتم تسجيل <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> وجدول زمني واحد آخر."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="zero">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و%3$d جدول زمني آخر.</item>
+ <item quantity="two">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> وجدولين زمنيين آخرين (%3$d).</item>
+ <item quantity="few">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و%3$d جداول زمنية أخرى.</item>
+ <item quantity="many">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و%3$d جدولاً زمنيًا آخر.</item>
+ <item quantity="other">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و%3$d جدول زمني آخر.</item>
+ <item quantity="one">‏لن يتم تسجيل بعض الأجزاء من <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g> و<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> وجدول زمني آخر (%3$d).</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"ماذا تريد تسجيله؟"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"كم مدة التسجيل التي تريدها؟"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"تم إعداد جدول زمني من قبل"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"تم إعداد جدول زمني من قبل لتسجيل البرنامج نفسه في <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"تم التسجيل من قبل"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"‏تم تسجيل هذا البرنامج من قبل. وسيكون متاحًا في مكتبة DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"لم يتم العثور على البرنامج المُسّجل"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"تسجيلات ذات صلة"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(لا يتوفر وصف للبرنامج)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <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">تسجيل واحد</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"تمت إزالة <xliff:g id="PROGRAMNAME">%1$s</xliff:g> من الجدول الزمني للتسجيل"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"سيتم تسجيل جزء من البرنامج بسبب وجود تعارضات في المواقف."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"لن يتم تسجيل البرنامج بسبب وجود تعارضات في المواقف."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ليست هناك أي تسجيلات في هذا الجدول الزمني إلى الآن.\nيمكنك إعداد جدول زمني للتسجيل من دليل البرنامج."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <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="dvr_series_schedules_settings" msgid="4868501926847903985">"إعدادات سلسلة التسجيلات"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"بدء تسجيل السلسلة"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"إيقاف تسجيل السلسلة"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"هل تريد إيقاف تسجيل السلسلة؟"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"‏ستظل الحلقات المسجّلة متاحة في مكتبة DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"إيقاف"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"لا تتوفر أي حلقات.\nسيتم تسجيلها بعد توفرها."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="zero">‏(%1$d دقيقة)</item>
+ <item quantity="two">(دقيقتان)</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="dvr_date_today" msgid="7691050705354303471">"اليوم"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"غدًا"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"أمس"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> اليوم"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> غدًا"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"النتيجة"</string>
</resources>
diff --git a/res/values-az-rAZ/arrays.xml b/res/values-az-rAZ/arrays.xml
index 8c6e5aae..7f891617 100644
--- a/res/values-az-rAZ/arrays.xml
+++ b/res/values-az-rAZ/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Tam"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Bütün kanallar"</item>
- <item msgid="6897460857821394118">"Ailə/Uşaqlar"</item>
- <item msgid="551257741825778215">"İdman"</item>
- <item msgid="452133796804325879">"Şoppinq"</item>
- <item msgid="3296058637230163031">"Filmlər"</item>
- <item msgid="1054540282883891201">"Komediya"</item>
- <item msgid="7900158429062595471">"Səyahət"</item>
- <item msgid="3768998587825611787">"Dram"</item>
- <item msgid="8340620094959282881">"Təhsil"</item>
- <item msgid="7396447839483867269">"Heyvan/Vəhşi təbiət"</item>
- <item msgid="4738043455148062673">"Xəbərlər"</item>
- <item msgid="7405041316051047427">"Oyun"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Bütün kanallar"</item>
- <item msgid="7909003973960375395">"Ailə/Uşaqlar"</item>
- <item msgid="3185279732911635789">"İdman"</item>
- <item msgid="4704858492065325964">"Şoppinq"</item>
- <item msgid="6083795019290250078">"Filmlər"</item>
- <item msgid="8302638329222449550">"Komediya"</item>
- <item msgid="3803709976021475052">"Səyahət"</item>
- <item msgid="8116747365234169059">"Dram"</item>
- <item msgid="7356447541595315913">"Təhsil"</item>
- <item msgid="7511135485827589547">"Heyvan/Vəhşi təbiət"</item>
- <item msgid="6961248112238009967">"Xəbərlər"</item>
- <item msgid="6484685553679698447">"Oyun"</item>
- <item msgid="2737158328243183190">"İncəsənət"</item>
- <item msgid="6577176952650166615">"Əyləncə"</item>
- <item msgid="7886693831871777617">"Həyat tərzi"</item>
- <item msgid="8145832312485577062">"Musiqi"</item>
- <item msgid="1345789204804308580">"Premyera"</item>
- <item msgid="2736680312770771994">"Texnologiya/Elm"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Bütün kanallar"</item>
+ <item msgid="928298872841713530">"Ailə/Uşaqlar"</item>
+ <item msgid="2751606947569857164">"İdman"</item>
+ <item msgid="7345749789651321496">"Şoppinq"</item>
+ <item msgid="167201149441442173">"Filmlər"</item>
+ <item msgid="525966731464264290">"Komediya"</item>
+ <item msgid="6096710741527327836">"Səyahət"</item>
+ <item msgid="2851882187117833883">"Dram"</item>
+ <item msgid="78492781188719038">"Təhsil"</item>
+ <item msgid="7221999662426308394">"Heyvan/Vəhşi təbiət"</item>
+ <item msgid="375300513250925001">"Xəbərlər"</item>
+ <item msgid="7746320336582330410">"Oyun"</item>
+ <item msgid="1255741860568329178">"İncəsənət"</item>
+ <item msgid="7603949681065702867">"Əyləncə"</item>
+ <item msgid="4453821994746804366">"Həyat tərzi"</item>
+ <item msgid="3488534597567932843">"Musiqi"</item>
+ <item msgid="7452153120614274095">"Premyera"</item>
+ <item msgid="8215762047341133299">"Texnologiya/Elm"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canlı Kanallar"</item>
diff --git a/res/values-az-rAZ/rating_system_strings.xml b/res/values-az-rAZ/rating_system_strings.xml
index 278af47e..bd28a4e8 100644
--- a/res/values-az-rAZ/rating_system_strings.xml
+++ b/res/values-az-rAZ/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-az-rAZ/strings.xml b/res/values-az-rAZ/strings.xml
index 643299c3..6ccb6d24 100644
--- a/res/values-az-rAZ/strings.xml
+++ b/res/values-az-rAZ/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Əvvəlki"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Proqram Təlimatı"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Yeni əlçatan kanallar"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Əlçatan link yoxdur"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqini açın"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Qapalı başlıqlar"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Ekran rejimi"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Alt-reytinqlər"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Bu kanalı izləmək üçün PİN kodunuzu daxil edin"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Bu proqramı izləmək üçün PİN kodunuzu daxil edin"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Bu proqram <xliff:g id="RATING">%1$s</xliff:g> ilə qiymətləndirilib. Bu proqramı izləmək üçün PİN kodunuzu daxil edin"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PİN kodunuzu daxil edin"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Valideyn nəzarəi yaratmaq üçün PİN yaradın"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Yeni PIN kodu daxil edin"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Açıq mənbə lisenziyaları"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Açıq mənbə lisenziyaları"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versiya"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Canlı Kanalları inkişaf etdirməyə kömək edin"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Anonim istifadə və diaqnostika datasını Google ilə paylaşın, beləcə Canlı Kanalları daha yaxşı edə və qırılma və donma problemlərinin qarşısını ala bilərik."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Bu kanalı izləmək üçün Sağa basın və PİN kodunuzu daxil edin"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Bu proqramı izləmək üçün Sağa basın və PİN kodunuzu daxil edin"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Bu proqram <xliff:g id="RATING">%1$s</xliff:g> ilə qiymətləndirilib.\nBu proqramı izləmək üçün Sağa basın və PİN kodunuzu daxil edin."</string>
@@ -159,6 +157,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Yalnız Audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Zəif siqnal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"İnternet bağlantısı yoxdur"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Bu kanal <xliff:g id="END_TIME_1">%1$s</xliff:g> radələrinə kimi fəaliyyət göstərə bilməz, cünki, digər kanallar qeydə alınır \n\nQeydə alma cədvəlini nizamlamaq üçün Sağı basın.</item>
+ <item quantity="one">Digər kanal qeydə alındığı üçün bu kanal <xliff:g id="END_TIME_0">%1$s</xliff:g> radələrinə kimi fəaliyyət göstərə bilməz. \n\nQeydə alma cədvəlini nizamlamaq üçün Sağı basın.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Başlıq yoxdur"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal blok edilib"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Yeni"</string>
@@ -170,8 +172,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Əlçatan kanal yoxdur"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Yeni"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Quraşdırılmayıb"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Əlavə mənbə əldə edin"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Canlı kanallar təklif edən tətbiqlər axtarın"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Əlavə mənbə əldə edin"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Canlı kanallar təklif edən tətbiqlər axtarın"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Yeni kanal mənbələri əlçatandır"</string>
<string name="new_sources_description" msgid="749649005588426813">"Yeni kanal mənbələrinin kanal təklifləri var.\nOnları indi ayarlayın, və ya daha sonra kanal mənbələri ayarından edin."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"İndi ayarlayın"</string>
@@ -189,8 +191,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Bütün mənbə kanalları gizlədilib.\nİzləmək üçün ən azı bir kanal seçin."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Bu video gözlənilmədən əlçatmazdır"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Geri düyməsi qoşulu cihazlar üçündür. Çıxmaq üçün ƏSAS SƏHİFƏ düyməsini basın."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Canlı Kanallar Android Lollipop ilə bu cihazda dəstəklənmir"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Canlı Kanallar TV siyahıları oxumaq üçün icazə istəyir."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Mənbələrinizi quraşdırın"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Canlı kanallar tətbiq tərəfindən yayımlanan kanallar ilə ənənəvi TV kanallarının təcrübəsini özündə birləşdirir. \n\n Artıq yüklənmiş kanal mənbələrini quraşdıraraq başlayın. Və ya canlı kanallar təklif edən bir neçə tətbiq üçün Google Play Store\'da axtarış edin."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Qeydə almalar və cədvəllər"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 dəqiqə"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 dəqiqə"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 saat"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 saat"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Son"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Planlaşdırılıb"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriyalar"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Digərləri"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanal qeydə alına bilməz."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Proqram qeydə alına bilməz."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> tətbiqinin qeydə alınması üçün vaxt təyin edilib"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> bu dəqiqədən etibarən <xliff:g id="ENDTIME">%2$s</xliff:g> radələrinə kimi deydə alınır"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Tam cədvəl"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Növbəti %1$d gün</item>
+ <item quantity="one">Növbəti %1$d gün</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d dəqiqə</item>
+ <item quantity="one">%1$d dəqiqə</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d yeni qeydə alma</item>
+ <item quantity="one">%1$d yeni qeydə alma</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d qeydə alma</item>
+ <item quantity="one">%1$d qeydə alma</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d qeydə alma təyin edildi</item>
+ <item quantity="one">%1$d qeydə alma təyin edildi</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"İzləyin"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Əvvəldən oxudun"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Oxutmağa davam edin"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Silin"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Qeydə almaları silin"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Davam edin"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> mövsüm"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Cədvələ baxın"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Ətraflı məlumat"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Qeydə almaları silin"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Silmək istədiyiniz epizodları seçin. Silinənlər bərpa oluna bilməz."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Silinmək üçün heç bir qeydə alma yoxdur."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Baxılmış epizodları seçin"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Bütün epizodları seçin"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Bütün epizodların seçimlərini qaldırın"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> müddətdən <xliff:g id="WATCHED">%1$d</xliff:g> dəqiqəsinə baxıldı"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> müddətdən <xliff:g id="WATCHED">%1$d</xliff:g> saniyəsinə baxıldı"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Heç vaxt baxılmayıb"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d epizoddan %1$d epizod silindi</item>
+ <item quantity="one">%2$d epizoddan %1$d epizod silindi</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Ən yüksək"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Ən alçaq"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Yox. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanallar"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Hər hansı"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Prioriteti seçin"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Eyni anda qeydə alınacaq bir neçə proqram olduqda, yalnız vacib olanlar qeydə alınacaq."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Yadda saxlayın"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Bir dəfəlik qeydiyyatlar yüksək prioritetlidir"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Ləğv edin"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Ləğv edin"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Unudun"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Dayandırın"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Qeydiyyat cədvəlinə baxın"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Tək bu proqram"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"indi - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Bütün seriyalar…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"İstənilən halda vaxt təyin edin"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Əvəzinə bunu qeydə alın"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Bu qeydə almanı ləğv edin"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"İndi baxın"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Qeydə alınabilən"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Qeydiyyat planlaşdırılıb"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Qeydiyyat münaqişəsi"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Qeydə alınır"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Qeydə alma uğursuz oldu"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Qeyd etmə cədvəli yaratmaq üçün proqramlar oxunur"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Oxuma proqramları"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR üçün əlavə yaddaş tələb olunur"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR ilə proqram qeydə ala biləcəksiniz. Hazırda DVR-ın işləməsi üçün cihazda kifayət qədər yaddaş yoxdur. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB və ya daha böyük həcmli xarici yaddaşı qoşun və cihaz yaddaşı olaraq format etmək üçün mərhələlərə riayət edin."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Yaddaş catışmır"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR tərəfindən istifadə olunan yaddaşın bir hissəsi əlçatan deyil. DVR\'ı yenidən aktiv etməmişdən əvvəl istifadə etdiyiniz xarici diskə qoşulun. Bundan başqa, artıq əlçatan deyilsə, yaddaşı unutmağı seçə bilərsiniz."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Yaddaş ehtiyyatını unutmusunuz?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Qeydə alınmış bütün məzmun və cədvəlləriniz itəcək."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Qeydetmə dayandırılsın?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Qeydə alınan məzmun yadda saxlanacaq."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Qeydiyyat vaxtı təyin edilib lakin ziddiyətlər var"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Qeydə alma başladı, lakin ziddiyətlər var."</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> qeydə alınacaq."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> qeydə alındı."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> tətbiqinin bəzi hissələri qeydə alınmayacaq."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> və <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> tətbiqlərinin bəzi hissələri qeydə alınmayacaq."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> tətbiqlərinin bəzi hissələri və daha bir cədvəl qeydə alınmayacaq."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> tətbiqlərinin bəzi hissələri və daha %3$d cədvəl qeydə alınmayacaq.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> tətbiqlərinin bəzi hissələri və daha %3$d cədvəl qeydə alınmayacaq.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Qeydə almaq istəyirsiniz?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Nə qədər müddətə qeydə almaq istəyirsiniz?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Artıq vaxt təyin edilib"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Eyni proqramın qeydə alınması üçün artıq <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> radələrində vaxt təyin edilib."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Artıq qeydə alınıb"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Bu proqram artıq qeydə alınıb. O, DVR kitabxanasında əlçatandır."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Qeyd edilmiş proqram tapılmadı."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Əlaqədar qeydetmələr"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Proqramın təsviri yoxdur)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d qeyd etmə</item>
+ <item quantity="one">%1$d qeyd etmə</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> qeyd cədvəlindən çıxarıldı"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Kökləyici ziddiyətləri səbəbi ilə qismən qeydə alınacaq."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Kökləyici ziddiyətləri səbəbi ilə qeydə alınmacaq."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Hələ ki cədvəldə heç bir qeydə alma yoxdur.\nProqram bələdçisindən qeydə alma üçün vaxt təyin edə bilərsiniz."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d qeydə alma münaqişəsi</item>
+ <item quantity="one">%1$d qeydə alma münaqişəsi</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Davamlılıq ayarları"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Ardıcıl qeydə almanı başladın"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Ardıcıl qeydə alma dayandırılsın"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Ardıcıl qeydə alma dayandırılsın?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Qeydə alınmış epizodlar DVR kitabxanasında əlçatan olacaq."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Dayandırın"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Heç bir epizod əlçatan deyil.\nOnlar, əlçatan olduqda qeydə alınacaq."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d dəqiqə)</item>
+ <item quantity="one">(%1$d dəqiqə) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Bugün"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Sabah"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Dünən"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> bugün"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> sabah"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Hesab"</string>
</resources>
diff --git a/res/values-bg/arrays.xml b/res/values-bg/arrays.xml
index 7ab868dc..66313ab6 100644
--- a/res/values-bg/arrays.xml
+++ b/res/values-bg/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Пълно (16:9)"</item>
<item msgid="8568284598210500589">"Променен мащаб"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Всички канали"</item>
- <item msgid="6897460857821394118">"Семейство/деца"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Пазаруване"</item>
- <item msgid="3296058637230163031">"Филми"</item>
- <item msgid="1054540282883891201">"Комедия"</item>
- <item msgid="7900158429062595471">"Пътувания"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Образование"</item>
- <item msgid="7396447839483867269">"Животни/дива природа"</item>
- <item msgid="4738043455148062673">"Новини"</item>
- <item msgid="7405041316051047427">"Игри"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Всички канали"</item>
- <item msgid="7909003973960375395">"Семейство/деца"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Пазаруване"</item>
- <item msgid="6083795019290250078">"Филми"</item>
- <item msgid="8302638329222449550">"Комедия"</item>
- <item msgid="3803709976021475052">"Пътувания"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Образование"</item>
- <item msgid="7511135485827589547">"Животни/дива природа"</item>
- <item msgid="6961248112238009967">"Новини"</item>
- <item msgid="6484685553679698447">"Игри"</item>
- <item msgid="2737158328243183190">"Изкуство"</item>
- <item msgid="6577176952650166615">"Развлечения"</item>
- <item msgid="7886693831871777617">"Начин на живот"</item>
- <item msgid="8145832312485577062">"Музика"</item>
- <item msgid="1345789204804308580">"Премиери"</item>
- <item msgid="2736680312770771994">"Технологии/наука"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Всички канали"</item>
+ <item msgid="928298872841713530">"Семейство/деца"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Пазаруване"</item>
+ <item msgid="167201149441442173">"Филми"</item>
+ <item msgid="525966731464264290">"Комедия"</item>
+ <item msgid="6096710741527327836">"Пътувания"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Образование"</item>
+ <item msgid="7221999662426308394">"Животни/дива природа"</item>
+ <item msgid="375300513250925001">"Новини"</item>
+ <item msgid="7746320336582330410">"Игри"</item>
+ <item msgid="1255741860568329178">"Изкуства"</item>
+ <item msgid="7603949681065702867">"Развлечения"</item>
+ <item msgid="4453821994746804366">"Начин на живот"</item>
+ <item msgid="3488534597567932843">"Музика"</item>
+ <item msgid="7452153120614274095">"Премиери"</item>
+ <item msgid="8215762047341133299">"Наука и технологии"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Канали на живо"</item>
diff --git a/res/values-bg/rating_system_strings.xml b/res/values-bg/rating_system_strings.xml
index d58017fb..aa88bd55 100644
--- a/res/values-bg/rating_system_strings.xml
+++ b/res/values-bg/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 201418a4..ab202fe2 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Назад"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Програми: Справочник"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Налице са нови канали"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Няма налична връзка"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Отваряне на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Надписи"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Показв.: Режим"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Подкласификации"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Въведете ПИН кода си, за да гледате този канал"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Въведете ПИН кода си, за да гледате тази програма"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Тази програма е класифицирана като „<xliff:g id="RATING">%1$s</xliff:g>“. Въведете ПИН кода си, за да я гледате"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Въведете ПИН кода си"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"За да зададете родителски контроли, създайте ПИН код"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Въведете новия ПИН код"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Лицензи за отворен код"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Лицензи за отворен код"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Версия"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Съдействие за подобряването на Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Споделяйте с Google анонимни данни за употребата и диагностиката, за да подобрим Телевизия онлайн и да предотвратим проблеми като сривове и замръзвания."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"За да гледате този канал, натиснете стрелката за надясно и въведете ПИН кода си"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"За да гледате тази програма, натиснете стрелката за надясно и въведете ПИН кода си"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Класификацията на тази програма е „<xliff:g id="RATING">%1$s</xliff:g>“.\nЗа да я гледате, натиснете стрелката за надясно и въведете ПИН кода си."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Само аудио"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Слаб сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Няма връзка с интернет"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Този канал не може да се пусне преди <xliff:g id="END_TIME_1">%1$s</xliff:g>, защото се записват други канали. \n\nНатиснете бутона за надясно, за да коригирате графика за записване.</item>
+ <item quantity="one">Този канал не може да се пусне преди <xliff:g id="END_TIME_0">%1$s</xliff:g>, защото се записва друг канал. \n\nНатиснете бутона за надясно, за да коригирате графика за записване.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Без заглавие"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Каналът е блокиран"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Нови"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Няма налични канали"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Нови"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Не е настроено"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Добавяне на още източници"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Разгледайте приложенията, предлагащи канали на живо"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Добавяне на още източници"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Разгледайте приложенията, предлагащи канали на живо"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Налице са нови източници на канали"</string>
<string name="new_sources_description" msgid="749649005588426813">"Нови източници предлагат канали.\nНастройте ги сега или го направете по-късно от настройката за източници на канали."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Настройване сега"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Всички входящи канали са скрити.\nИзберете поне един, който да гледате."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Видеоклипът неочаквано не е налице"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Клавишът за връщане назад е за свързаното устройство. За изход натиснете бутона „Начало“."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Приложението Live TV не се поддържа на това устройство с Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Приложението Live TV се нуждае от разрешение, за да чете телевизионните програми."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Настройте източниците си"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Каналите на живо съчетават традиционните телевизионни канали с поточно предаваните, които се предоставят чрез приложения. \n\nЗапочнете, като настроите вече инсталираните източници на канали. Или разгледайте Google Play Магазин за още приложения, предлагащи канали на живо."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Записи и графици"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 минути"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 минути"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 час"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 часа"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Скорошни"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Насрочени"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Поредица"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Други"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Каналът не може да бъде записан."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Програмата не може да бъде записана."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Насрочено е записване за „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Записване на „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ от този момент до <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Пълен график"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Следващите %1$d дни</item>
+ <item quantity="one">Следващият %1$d ден</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d минути</item>
+ <item quantity="one">%1$d минута</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d нови записа</item>
+ <item quantity="one">%1$d нов запис</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d записа</item>
+ <item quantity="one">%1$d запис</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d насрочени записа</item>
+ <item quantity="one">%1$d насрочен запис</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Гледане"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Пускане от началото"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Продължаване"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Изтриване"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Изтриване на записи"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Възобновяване"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Вижте графика"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Прочетете повече"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Изтриване на записи"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Изберете епизодите, които искате да изтриете. Няма да можете да ги възстановите след това."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Няма записи за изтриване."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Избиране на гледаните епизоди"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Избиране на всички епизоди"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Вс. епизоди: Отмяна на избора"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Изгледахте <xliff:g id="WATCHED">%1$d</xliff:g> от <xliff:g id="DURATION">%2$d</xliff:g> минути"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Изгледахте <xliff:g id="WATCHED">%1$d</xliff:g> от <xliff:g id="DURATION">%2$d</xliff:g> секунди"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Негледани"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d от %2$d епизода са изтрити</item>
+ <item quantity="one">%1$d от %2$d епизод е изтрит</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Приоритет"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Най-висок"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Най-нисък"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Не. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Канали"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Всички"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Изберете приоритет"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Когато има прекалено много програми за записване по едно и също време, ще бъдат записани само тези с най-висок приоритет."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Запазване"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Най-висок приоритет имат еднократните записи"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Отказ"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Отказ"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Забравяне"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Спиране"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Вижте графика за записване"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Само тази програма"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"от сега до <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Цялата поредица…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Насрочване въпреки това"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Записване на тази програма"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Анулиране на този запис"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Гледайте сега"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"С възможност за запис"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Записът е насрочен"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Конфликт със записа"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Записва се"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Записването не бе успешно"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Програмите се четат с цел създаване на графици за записване"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Програмите се четат"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Дигиталният видеорекордер се нуждае от още място за съхранение"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Ще сте в състояние да записвате програми посредством дигиталния видеорекордер. В момента обаче той не може да работи, тъй като няма достатъчно място в хранилището на устройството ви. Моля, свържете външен диск с размер от поне <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> ГБ и изпълнете стъпките, за да го форматирате като хранилище на устройството."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Хранилището липсва"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Част от използваното от цифровия видеорекордер хранилище липсва. Моля, свържете по-рано ползвания от вас външен диск, за да активирате отново видеорекордера. Друга възможност е да изберете хранилището да се забрави, ако вече не е налично."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Да се забрави ли хранилището?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Цялото ви записано съдържание и графици ще бъдат изгубени."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Да се спре ли записването?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Записаното съдържание ще бъде запазено."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Записът е насрочен, но има конфликти"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Записването започна, но има конфликти"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"„<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ ще се запише."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Предаването по <xliff:g id="CHANNELNAME">%1$s</xliff:g> се записва."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Някои части от „<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>“ няма да бъдат записани."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Някои части от „<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>“ и „<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>“ няма да бъдат записани."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Някои части от „<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>“ и още едно насрочено предаване няма да бъдат записани."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Някои части от „<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>“ и още %3$d насрочени предавания няма да бъдат записани.</item>
+ <item quantity="one">Някои части от „<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>“ и още %3$d насрочено предаване няма да бъдат записани.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Какво искате да запишете?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Колко време искате да записвате?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Вече насрочихте"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Същата програма вече е насрочена за записване в <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Вече записахте"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Тази програма вече е записана. Тя е налична в библиотеката на устройството за дигитален видеозапис."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Записаната програма не е намерена."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Сродни записи"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Няма описание на програмата)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d записа</item>
+ <item quantity="one">%1$d запис</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Премахнахте „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ от графика за записване"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Ще се запише частично поради конфликти с тунера."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Няма да се запише поради конфликти с тунера."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Графикът за записване все още е празен.\nМожете да насрочите записване от програмния справочник."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d конфликта със записа</item>
+ <item quantity="one">%1$d конфликт със записа</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Настройки за поредицата"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Старт на записа на поредицата"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Спиране на записа на поредицата"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Да се спре ли записването на поредицата?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Записаните епизоди ще останат налице в библиотеката на устройството за дигитален видеозапис."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Спиране"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Няма налични епизоди.\nТе ще бъдат записани, когато са налице."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d минути)</item>
+ <item quantity="one">(%1$d минута) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Днес"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Утре"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Вчера"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Днес: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Утре: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Рейтинг"</string>
</resources>
diff --git a/res/values-bn-rBD/arrays.xml b/res/values-bn-rBD/arrays.xml
index 31fbf35b..76a0792a 100644
--- a/res/values-bn-rBD/arrays.xml
+++ b/res/values-bn-rBD/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"সম্পূর্ণ"</item>
<item msgid="8568284598210500589">"জুম"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"সমস্ত চ্যানেল"</item>
- <item msgid="6897460857821394118">"পরিবার/শিশু"</item>
- <item msgid="551257741825778215">"খেলাধুলা"</item>
- <item msgid="452133796804325879">"কেনাকাটা"</item>
- <item msgid="3296058637230163031">"চলচ্চিত্র"</item>
- <item msgid="1054540282883891201">"হাস্যরস"</item>
- <item msgid="7900158429062595471">"ভ্রমণ"</item>
- <item msgid="3768998587825611787">"নাটক"</item>
- <item msgid="8340620094959282881">"শিক্ষা"</item>
- <item msgid="7396447839483867269">"প্রাণী/বন্যজীবন"</item>
- <item msgid="4738043455148062673">"সংবাদ"</item>
- <item msgid="7405041316051047427">"গেমিং"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"সমস্ত চ্যানেল"</item>
- <item msgid="7909003973960375395">"পরিবার/শিশু"</item>
- <item msgid="3185279732911635789">"খেলাধুলা"</item>
- <item msgid="4704858492065325964">"কেনাকাটা"</item>
- <item msgid="6083795019290250078">"চলচ্চিত্র"</item>
- <item msgid="8302638329222449550">"হাস্যরস"</item>
- <item msgid="3803709976021475052">"ভ্রমণ"</item>
- <item msgid="8116747365234169059">"নাটক"</item>
- <item msgid="7356447541595315913">"শিক্ষা"</item>
- <item msgid="7511135485827589547">"প্রাণী/বন্যজীবন"</item>
- <item msgid="6961248112238009967">"সংবাদ"</item>
- <item msgid="6484685553679698447">"গেমিং"</item>
- <item msgid="2737158328243183190">"কলা"</item>
- <item msgid="6577176952650166615">"বিনোদন"</item>
- <item msgid="7886693831871777617">"জীবনশৈলী"</item>
- <item msgid="8145832312485577062">"সঙ্গীত"</item>
- <item msgid="1345789204804308580">"প্রিমিয়ার"</item>
- <item msgid="2736680312770771994">"প্রযুক্তি/বিজ্ঞান"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"সমস্ত চ্যানেল"</item>
+ <item msgid="928298872841713530">"পরিবার/শিশু"</item>
+ <item msgid="2751606947569857164">"খেলাধুলা"</item>
+ <item msgid="7345749789651321496">"কেনাকাটা"</item>
+ <item msgid="167201149441442173">"চলচ্চিত্র"</item>
+ <item msgid="525966731464264290">"কমেডি"</item>
+ <item msgid="6096710741527327836">"ভ্রমণ"</item>
+ <item msgid="2851882187117833883">"নাটক"</item>
+ <item msgid="78492781188719038">"শিক্ষা"</item>
+ <item msgid="7221999662426308394">"প্রাণী/বন্যজীবন"</item>
+ <item msgid="375300513250925001">"সংবাদ"</item>
+ <item msgid="7746320336582330410">"গেমিং"</item>
+ <item msgid="1255741860568329178">"কলা"</item>
+ <item msgid="7603949681065702867">"বিনোদন"</item>
+ <item msgid="4453821994746804366">"জীবনশৈলী"</item>
+ <item msgid="3488534597567932843">"সঙ্গীত"</item>
+ <item msgid="7452153120614274095">"প্রিমিয়ার"</item>
+ <item msgid="8215762047341133299">"প্রযুক্তি/বিজ্ঞান"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"লাইভ চ্যানেলগুলি"</item>
diff --git a/res/values-bn-rBD/rating_system_strings.xml b/res/values-bn-rBD/rating_system_strings.xml
index a8916a03..81c9593b 100644
--- a/res/values-bn-rBD/rating_system_strings.xml
+++ b/res/values-bn-rBD/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-bn-rBD/strings.xml b/res/values-bn-rBD/strings.xml
index 7205c73a..52938ab2 100644
--- a/res/values-bn-rBD/strings.xml
+++ b/res/values-bn-rBD/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"পূর্ববর্তী"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"প্রোগ্রাম গাইড"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"নতুন চ্যানেলগুলি উপলব্ধ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"কোনো লিঙ্ক উপলব্ধ নেই"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> খুলুন"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"সাবটাইটেলগুলি"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"প্রদর্শন মোড"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"উপ-রেটিংগুলি"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"এই চ্যানেলটি দেখতে আপনার পিন লিখুন"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"এই প্রোগ্রামটি দেখতে আপনার পিন লিখুন"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"এই প্রোগ্রামটি <xliff:g id="RATING">%1$s</xliff:g> রেটপ্রাপ্ত। এই প্রোগ্রামটি দেখার জন্য আপনার PIN লিখুন।"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"আপনার পিন লিখুন"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"অভিভাবকীয় নিয়ন্ত্রণগুলি সেট করতে, একটি পিন তৈরি করুন"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"নতুন পিন লিখুন"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"মুক্ত উৎস লাইসেন্সগুলি"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"মুক্ত উৎস লাইসেন্সগুলি"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"সংস্করণ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"লাইভ চ্যানেলগুলি উন্নত করতে সহায়তা করুন"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google এর সাথে নামবিহীন ব্যবহার এবং ডায়াগনস্টিক ডেটা শেয়ার করুন যাতে করে আমরা লাইভ চ্যানেলগুলিকে আরো উন্নত করতে এবং ক্র্যাশ ও ফ্রিজ হয়ে যাওয়ার মতো সমস্যাগুলিকে আটকাতে পারি৷"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"এই চ্যানেলটিকে দেখতে, ডানদিকে চাপুন এবং আপনার পিন লিখুন"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"এই প্রোগ্রামটি দেখতে, ডানদিকে চাপুন এবং আপনার পিন লিখুন"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"এই প্রোগ্রামটি <xliff:g id="RATING">%1$s</xliff:g> রেট প্রাপ্ত৷\nএই প্রোগ্রামটি দেখতে, ডানদিকে চাপুন এবং আপনার পিন লিখুন"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"কেবলমাত্র অডিও"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"সিগন্যাল দুর্বল"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"কোনো ইন্টারনেট সংযোগ নেই"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one"><xliff:g id="END_TIME_1">%1$s</xliff:g>পর্যন্ত এই চ্যালেনটি চালানো যাবে না কারণ অন্যান্য চ্যানেলগুলি রেকর্ড করা হচ্ছে৷ \n\nরেকর্ড করার সময়সূচী সামঞ্জস্য করতে ডান দিকে ক্লিক করুন৷</item>
+ <item quantity="other"><xliff:g id="END_TIME_1">%1$s</xliff:g>পর্যন্ত এই চ্যালেনটি চালানো যাবে না কারণ অন্যান্য চ্যানেলগুলি রেকর্ড করা হচ্ছে৷ \n\nরেকর্ড করার সময়সূচী সামঞ্জস্য করতে ডান দিকে ক্লিক করুন৷</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"কোনো শিরোনাম নেই"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"চ্যানেল অবরুদ্ধ করা হয়েছে"</string>
<string name="setup_category_new" msgid="2899355289563443627">"নতুন"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"কোনো চ্যানেল উপলব্ধ নেই"</string>
<string name="setup_input_new" msgid="3337725672277046798">"নতুন"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"সেট আপ করা নেই"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"আরো উৎস পান"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"লাইভ চ্যানেলগুলি অফার করে এমন অ্যাপগুলি ব্রাউজ করুন"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"আরো উৎস পান"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"লাইভ চ্যানেল অফার করে এমন অ্যাপ্স ব্রাউজ করুন"</string>
<string name="new_sources_title" msgid="3878933676500061895">"নতুন চ্যানেলের সূত্রগুলি উপলব্ধ রয়েছে"</string>
<string name="new_sources_description" msgid="749649005588426813">"নতুন চ্যানেলের সূত্রগুলিতে প্রদান করার জন্য চ্যানেল রয়েছে।\nসেগুলিকে এখনই সেট আপ করুন, বা চ্যানের সূত্রের সেটিংয়ের মধ্যে পরে এটি করুন।"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"এখনই সেট আপ করুন"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"সমস্ত উৎস চ্যানেল লুকানো আছে৷\nদেখার জন্য কমপক্ষে একটি চ্যানেল নির্বাচন করুন৷"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ভিডিওটি অপ্রত্যাশিতভাবে অনুপলব্ধ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"\'ব্যাক\' কীটি সংযুক্ত ডিভাইসের ক্ষেত্রে ব্যবহারের জন্য৷ প্রস্থান করতে হোম বোতামটি টিপুন৷"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"এই ডিভাইসটিতে Android Lollipop এর সাথে লাইভ চ্যানেলগুলি সমর্থিত নয়।"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"টিভির তালিকাগুলি পড়ার জন্য লাইভ চ্যানেলগুলিকে অনুমতি নিতে হবে।"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"আপনার উৎসগুলি সেট আপ করুন"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"লাইভ চ্যানেলগুলি অ্যাপ্লিকেশানগুলির দ্বারা সরবরাহ করা স্ট্রিমিং চ্যানেলের সঙ্গে ঐতিহ্যগত টিভি চ্যানেলের সম্মিলিত অভিজ্ঞতা প্রদান করে৷ \n\nইতিমধ্যেই ইনস্টল থাকা চ্যানেল উৎসগুলি সেট আপ করার মাধ্যেমে শুরু করুন৷ অথবা লাইভ চ্যানেলগুলি অফার করে এমন অ্যাপ্লিকেশানগুলি পেতে Google Play স্টোর ব্রাউজ করুন৷"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"রেকডিং &amp; সময়সূচী"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"১০ মিনিট"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"৩০ মিনিট"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"১ ঘণ্টা"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"৩ ঘণ্টা"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"সাম্প্রতিক"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"নির্ধারিত"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"সিরিজ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"অন্যরা"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"চ্যানেলটি রেকর্ড করা যাবে না৷"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"প্রোগ্রামটি রেকর্ড করা যাবে না৷"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> রেকর্ড করার সময় নির্ধারিত হয়েছে"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>কে এখান থেকে <xliff:g id="ENDTIME">%2$s</xliff:g> পর্যন্ত রেকর্ড করা হচ্ছে"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"সম্পূর্ণ সময়সূচী"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">পরবর্তী %1$d দিন</item>
+ <item quantity="other">পরবর্তী %1$d দিন</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d মিনিট</item>
+ <item quantity="other">%1$d মিনিট</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$dটি নতুন রেকডিং</item>
+ <item quantity="other">%1$dটি নতুন রেকডিং</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$dটি রেকর্ডিং</item>
+ <item quantity="other">%1$dটি রেকর্ডিং</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$dটি রেকর্ডিংয়ের সময় নির্ধারিত হয়েছে</item>
+ <item quantity="other">%1$dটি রেকর্ডিংয়ের সময় নির্ধারিত হয়েছে</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"দেখুন"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"শুরু থেকে প্লে করুন"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"পুনরায় প্লে করুন"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"মুছুন"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"রেকডিংগুলি মুছুন"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"পুনরায় শুরু করুন"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"সিজন <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"সময়সূচী দেখুন"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"আরো পড়ুন"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"রেকডিংগুলি মুছুন"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"আপনি যে পর্বগুলিকে মুছতে চান সেগুলিকে নির্বাচন করুন। একবার মোছা হলে সেগুলিকে পুনরুদ্ধার করা যাবে না।"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"মোছার জন্য সেখানে কোনো রেকডিং নেই।"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"দেখা পর্বগুলিকে নির্বাচন করুন"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"সমস্ত পর্ব নির্বাচন করুন"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"সমস্ত পর্ব নির্বাচন মুক্ত করুন"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> এর মধ্যে <xliff:g id="WATCHED">%1$d</xliff:g> মিনিট দেখা হয়েছে"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> এর মধ্যে <xliff:g id="WATCHED">%1$d</xliff:g> সেকেন্ড দেখা হয়েছে"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"কখনই দেখা হয়নি"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%2$dটির মধ্যে %1$dটি পর্ব মোছা হয়েছে</item>
+ <item quantity="other">%2$dটির মধ্যে %1$dটি পর্ব মোছা হয়েছে</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"অগ্রাধিকার"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"সর্বোচ্চ"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"সর্বনিম্ন"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"না৷ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"চ্যানেল"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"যে কোনো"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"অগ্রাধিকার চয়ন করুন"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"যখন একই সময়ে অনেকগুলি প্রোগ্রাম রেকর্ড করা হয় তখন শুধুমাত্র উচ্চ অগ্রাধিকারযুক্ত প্রোগ্রামগুলিকে রেকর্ড করা হবে৷"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"সংরক্ষণ করুন"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"একবার করা রেকর্ডিংগুলিতে সর্বোচ্চ অগ্রাধিকার রয়েছে"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"বাতিল করুন"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"বাতিল করুন"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"মুছে দিন"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"থামান"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"রেকডিং এর সময়সূচী দেখুন"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"শুধুমাত্র এই প্রোগ্রামটি"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"এখন - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"সম্পূর্ণ সিরিজ…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"যাই হোক, সময়সূচি নির্ধারণ করুন"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"বরং এটি রেকর্ড করুন"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"এই রেকর্ডিং বাতিল করুন"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"এখনই দেখুন"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"রেকর্ড করা যাবে"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"রেকর্ডিংএর সময় নির্ধারিত হয়েছে"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"রেকর্ডিং দ্বন্দ্ব"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"রেকর্ড করা হচ্ছে"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"রেকডিং করা গেল না"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"রেকর্ডিংয়ের সময়সূচীগুলি তৈরি করতে প্রোগ্রামগুলি পড়া হচ্ছে"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"প্রোগ্রামগুলি পড়া হচ্ছে"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR এর আরো সঞ্চয়স্থান দরকার"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"আপনি DVR এর মাধ্যমে প্রোগ্রাম রেকর্ড করতে পারবেন৷ তবে DVR কাজ করার জন্য আপনার ডিভাইসে এখন যথেষ্ঠ সঞ্চয়স্থান নেই৷ অনুগ্রহ করে <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB বা তার থেকে বড় আকারের কোনো বাহ্যিক ডিভাইসের সাথে সংযোগ করুন এবং ডিভাইসের সঞ্চয়স্থান হিসাবে ফর্ম্যাট করতে পদক্ষেপগুলি অনুসরণ করুন৷"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"সঞ্চয়স্থান অনুপস্থিত"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR দ্বারা ব্যবহৃত কিছু সঞ্চয়স্থান অনুপস্থিত৷ DVR পুনরায় সক্ষম করার আগে অনুগ্রহ করে আপনার আগে ব্যবহার করা বাহ্যিক ড্রাইভ সংযোগ করুন৷ অথবা, যদি সঞ্চয়স্থানটি আর উপলব্ধ না থাকে তবে আপনি সেটিকে মুছে দিতে পারবেন৷"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"সঞ্চয়স্থান মুছতে চান?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"আপনার রেকর্ড করা সমস্ত সামগ্রী এবং সময়সূচী মুছে যাবে৷"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"রেকর্ড করা থামাবেন?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"রেকর্ড করা সামগ্রী সংরক্ষণ করা হবে৷"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"রেকর্ডিংয়ের যে সময় নির্ধারিত করা হয়েছে তাতে অন্যদের সমসয়ের সাথে বিরোধ ঘটাতে পারে।"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"রেকর্ডিং শুরু হয়েছে কিন্তু দ্বন্দ্বগুলি রয়েছে"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> রেকর্ড করা হবে৷"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> রেকর্ড করা হচ্ছে৷"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> এর কিছু অংশ রেকর্ড করা হবে না৷"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> এবং <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> এর কিছু অংশ রেকর্ড করা হবে না৷"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>এর কিছু অংশ এবং আরো একটি সময়সূচী রেকর্ড করা হবে না৷"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one"> <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> এর কিছু অংশ এবং আরো %3$dটি সময়সূচী রেকর্ড করা হবে না৷</item>
+ <item quantity="other"> <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> এর কিছু অংশ এবং আরো %3$dটি সময়সূচী রেকর্ড করা হবে না৷</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"আপনি কি রেকর্ড করতে চান?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"আপনি কতক্ষন রেকর্ড করতে চান?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ইতিমধ্যে সময়সূচী নির্ধারণ করা হয়েছে"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"একই প্রোগ্রাম ইতিমধ্যেই <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> এ রেকর্ড করার জন্য নির্ধারণ করা হয়েছে।"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ইতিমধ্যে রেকর্ড করা হয়েছে"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"এই প্রোগ্রামটি ইতিমধ্যে রেকর্ড করা হয়েছে। এটি DVR লাইব্রেরিতে উপলব্ধ।"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"রেকর্ড করা প্রোগ্রাম খুঁজে পাওয়া যায়নি৷"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"সম্পর্কিত রেকর্ডিং"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(প্রোগ্রামের কোনো বিবরণ নেই)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$dটি রেকর্ডিং</item>
+ <item quantity="other">%1$dটি রেকর্ডিং</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"রেকর্ড করার সময়সূচী থেকে <xliff:g id="PROGRAMNAME">%1$s</xliff:g> সরানো হয়েছে"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"টিউনার না থাকার কারণে আংশিকভাবে রেকর্ড করা হবে৷"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"টিউনার না থাকার কারণে রেকর্ড করা হবে না৷"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"এখনো পর্যন্ত কোনো রেকর্ডিংয়ের জন্য সময়সূচী নির্ধারণ করা হয়নি।\nআপনি প্রোগ্রাম গাইড থেকে রেকর্ডিংয়ের সময়সূচী নির্ধারণ করতে পারেন।"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$dটি রেকডিং দ্বন্দ্ব</item>
+ <item quantity="other">%1$dটি রেকডিং দ্বন্দ্ব</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"সিরিজ সেটিংস"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"সিরিজ রেকডিং শুরু করুন"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"সিরিজ রেকডিং বন্ধ করুন"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"সিরিজি রেকর্ড করা বন্ধ করতে চান?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"রেকর্ড করা পর্বগুলি DVR লাইব্রেরিতে উপলব্ধ থাকবে৷"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"বন্ধ করুন"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"কোনো পর্ব উপলব্ধ নেই।\nএকবার উপলব্ধ হলে সেগুলিকে রেকর্ড করা হবে।"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d মিনিট)</item>
+ <item quantity="other">(%1$d মিনিট)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"আজ"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"আগামীকাল"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"গতকাল"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"আজ <xliff:g id="TIME_RANGE">%1$s</xliff:g> টায়"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"আগামীকাল <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"স্কোর"</string>
</resources>
diff --git a/res/values-ca/arrays.xml b/res/values-ca/arrays.xml
index 69033753..d00927f6 100644
--- a/res/values-ca/arrays.xml
+++ b/res/values-ca/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Complet"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Tots els canals"</item>
- <item msgid="6897460857821394118">"Familiar/infantil"</item>
- <item msgid="551257741825778215">"Esports"</item>
- <item msgid="452133796804325879">"Compres"</item>
- <item msgid="3296058637230163031">"Pel·lícules"</item>
- <item msgid="1054540282883891201">"Comèdia"</item>
- <item msgid="7900158429062595471">"Viatges"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Educació"</item>
- <item msgid="7396447839483867269">"Animals/fauna"</item>
- <item msgid="4738043455148062673">"Notícies"</item>
- <item msgid="7405041316051047427">"Jocs"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Tots els canals"</item>
- <item msgid="7909003973960375395">"Familiar/infantil"</item>
- <item msgid="3185279732911635789">"Esports"</item>
- <item msgid="4704858492065325964">"Compres"</item>
- <item msgid="6083795019290250078">"Pel·lícules"</item>
- <item msgid="8302638329222449550">"Comèdia"</item>
- <item msgid="3803709976021475052">"Viatges"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Educació"</item>
- <item msgid="7511135485827589547">"Animals/fauna"</item>
- <item msgid="6961248112238009967">"Notícies"</item>
- <item msgid="6484685553679698447">"Jocs"</item>
- <item msgid="2737158328243183190">"Art"</item>
- <item msgid="6577176952650166615">"Entreteniment"</item>
- <item msgid="7886693831871777617">"Estil de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"Principal"</item>
- <item msgid="2736680312770771994">"Ciència i tecnologia"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Tots els canals"</item>
+ <item msgid="928298872841713530">"Familiar/infantil"</item>
+ <item msgid="2751606947569857164">"Esports"</item>
+ <item msgid="7345749789651321496">"Compres"</item>
+ <item msgid="167201149441442173">"Pel·lícules"</item>
+ <item msgid="525966731464264290">"Comèdia"</item>
+ <item msgid="6096710741527327836">"Viatges"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educació"</item>
+ <item msgid="7221999662426308394">"Animals/fauna"</item>
+ <item msgid="375300513250925001">"Notícies"</item>
+ <item msgid="7746320336582330410">"Jocs"</item>
+ <item msgid="1255741860568329178">"Art"</item>
+ <item msgid="7603949681065702867">"Entreteniment"</item>
+ <item msgid="4453821994746804366">"Estil de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"Principal"</item>
+ <item msgid="8215762047341133299">"Ciència i tecnologia"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"TV en directe"</item>
diff --git a/res/values-ca/rating_system_strings.xml b/res/values-ca/rating_system_strings.xml
index 1ee038aa..0aabc23b 100644
--- a/res/values-ca/rating_system_strings.xml
+++ b/res/values-ca/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 7509b64c..3ab61ffb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guia de programes"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nous canals disponibles"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Sense enllaç disponible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Obre <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtítols"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mode visualitz."</string>
@@ -79,9 +78,9 @@
<string name="edit_channels_item_deselect_group" msgid="5092649099546997807">"Anul·la la selecció"</string>
<string name="edit_channels_item_group_by" msgid="7794571851966798199">"Agrupa per"</string>
<string name="edit_channels_group_by_sources" msgid="5481053601210461217">"Font del canal"</string>
- <string name="edit_channels_group_by_hd_sd" msgid="5582719665718278819">"Alta definició/definició estàndard"</string>
+ <string name="edit_channels_group_by_hd_sd" msgid="5582719665718278819">"HD/SD"</string>
<string name="edit_channels_group_divider_for_hd" msgid="5311355566660389423">"Alta definició"</string>
- <string name="edit_channels_group_divider_for_sd" msgid="5846195382266436167">"Definició estàndard"</string>
+ <string name="edit_channels_group_divider_for_sd" msgid="5846195382266436167">"SD"</string>
<string name="side_panel_title_group_by" msgid="1783176601425788939">"Agrupa per"</string>
<string name="program_guide_content_locked" msgid="198056836554559553">"Aquest programa està bloquejat"</string>
<string name="program_guide_content_locked_format" msgid="514915272862967389">"Aquest programa està classificat com a <xliff:g id="RATING">%1$s</xliff:g>"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subclassificacions"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Introducció del PIN per mirar aquest canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Introducció del PIN per mirar aquest programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Aquest programa està classificat com a <xliff:g id="RATING">%1$s</xliff:g>. Introdueix el PIN per mirar-lo"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Introducció del PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Per definir els controls dels pares, crea un PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Introdueix el PIN nou"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Llicències de programari lliure"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Llicències de programari lliure"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versió"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Vull contribuir a millorar Canals en directe"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Comparteix dades d\'ús i de diagnòstic anònimes amb Google per millorar TV en directe i evitar problemes, com ara bloqueigs i errors."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Per veure aquest canal, prem el botó dret i introdueix el PIN."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Per veure aquest programa, prem el botó dret i introdueix el PIN."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Aquest programa està classificat com a <xliff:g id="RATING">%1$s</xliff:g>.\nPer veure\'l, prem el botó dret i introdueix el PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Només àudio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"El senyal és feble"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"No hi ha connexió a Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Aquest canal no es podrà reproduir fins a les <xliff:g id="END_TIME_1">%1$s</xliff:g> perquè s\'estan enregistrant altres canals. \n\nPrem la tecla dreta per ajustar l\'horari d\'enregistrament.</item>
+ <item quantity="one">Aquest canal no es podrà reproduir fins a les <xliff:g id="END_TIME_0">%1$s</xliff:g> perquè se n\'està enregistrant un altre. \n\nPrem la tecla dreta per ajustar l\'horari d\'enregistrament.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sense títol"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal bloquejat"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Noves"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No hi ha cap canal disponible"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nou"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"No s\'ha configurat"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Obtén més fonts"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Navega per les aplicacions que ofereixen TV en directe"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Obtén més fonts"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Navega per les aplicacions que ofereixen TV en directe"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Hi ha noves fonts de canals disponibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Les noves fonts de canals tenen canals per oferir.\nConfigura-les ara o fes-ho més tard des de la seva secció de configuració."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configura ara"</string>
@@ -187,8 +189,160 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Tots els canals d\'origen estan amagats.\nSelecciona com a mínim un canal per veure\'l."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"El vídeo ha deixat d\'estar disponible de manera inesperada"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"La tecla ENRERE és per als dispositius connectats. Prem el botó INICI per sortir."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Canals en directe no s\'admet en aquest dispositiu amb Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Canals en directe necessita permís per consultar les programacions de TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configura les teves fonts"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"L\'aplicació TV en directe combina l\'experiència dels canals de televisió tradicionals amb els canals de reproducció en temps real proporcionats per les aplicacions. \n\nPer començar, configura les fonts de canals que ja hi ha instal·lades. També pots navegar per Google Play Store per descobrir més aplicacions que ofereixin TV en directe."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Enregistraments i horaris"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuts"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuts"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hores"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recents"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programats"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Sèries"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Altres"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"El canal no es pot enregistrar."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"El programa no es pot enregistrar."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"S\'ha programat l\'enregistrament de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"S\'enregistrarà <xliff:g id="PROGRAMNAME">%1$s</xliff:g> d\'ara fins a les <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Calendari complet"</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for dvr_full_schedule_card_view_content (790788122541080768) -->
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minuts</item>
+ <item quantity="one">%1$d minut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d enregistraments nous</item>
+ <item quantity="one">%1$d enregistrament nou</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d enregistraments</item>
+ <item quantity="one">%1$d enregistrament</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d enregist. programats</item>
+ <item quantity="one">%1$d enregistr. programat</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Reprodueix"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reprodueix des del principi"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reprèn la reproducció"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Suprimeix"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Suprimeix els enregistraments"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reprèn"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Mostra programa"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Més informació"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Suprimeix enregistr."</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecciona els episodis que vols suprimir. No els podràs recuperar una vegada s\'hagin suprimit."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"No hi ha cap enregistrament per suprimir."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Selecciona els episodis mirats"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Selecciona tots els episodis"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Desselecciona tots els episodis"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> minuts de visualització (<xliff:g id="DURATION">%2$d</xliff:g> en total)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> segons de visualització (<xliff:g id="DURATION">%2$d</xliff:g> en total)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Enregistraments no mirats"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">S\'han suprimit %1$d episodis (%2$d en total)</item>
+ <item quantity="one">S\'ha suprimit %1$d episodi (%2$d en total)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritat"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Més alta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Més baixa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"No. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canals"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Qualsevol"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Selecciona la prioritat"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Quan hi hagi massa programes per enregistrar a la mateixa hora, només s\'enregistraran els que tinguin una prioritat més elevada."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Desa"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Els enregistraments únics tenen la prioritat més alta"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancel·la"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancel·la"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"No recordis"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Atura"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Mostra programa d\'enregistrament"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Només aquest programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ara - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Sèrie completa…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programa igualment"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Enregistra aquest programa"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancel·la aquest enregistrament"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Mira ara"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Enregistrable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Enregistrament programat"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflicte d\'enregistrament"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"S\'està enregistrant"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Error d\'enregistrament"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"S\'estan llegint els programes per crear programacions d\'enregistrament"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"S\'estan llegint els programes"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"El DVR necessita més emmagatzematge"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Podràs· enregistrar· programes· amb· el· DVR.· No· obstant· això,· en· aquests· moments· no· tens· prou· emmagatzematge· al· dispositiu· perquè· el· DVR· pugui· funcionar.· Connecta· una· unitat· externa· que· tingui· com· a· mínim· <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB· d\'espai· disponible· i· segueix· els· passos· per· formatar-la· com· a· unitat· d\'emmagatzematge· del· dispositiu."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Falta el dispositiu d\'emmagatzematge"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Falta contingut emmagatzemat pel DVR. Connecta la unitat externa que utilitzaves abans per tornar a activar el DVR. Si el dispositiu d\'emmagatzematge ja no està disponible, pots optar perquè s\'oblidi."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Vols que s\'oblidi el dispositiu d\'emmagatzematge?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tot el contingut i totes les agendes que tinguis desades es perdran."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Vols aturar l\'enregistrament?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"El contingut enregistrat es desarà."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Hi ha un enregistrament programat, però té conflictes"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"L\'enregistrament ha començat, però té conflictes"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> s\'enregistrarà."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> s\'està enregistrant."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Algunes parts de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> no s\'enregistraran."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Algunes parts de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> no s\'enregistraran."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Algunes parts de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> i d\'una programació més no s\'enregistraran."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Algunes parts de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> i %3$d programacions més no s\'enregistraran.</item>
+ <item quantity="one">Algunes parts de <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> i %3$d programació més no s\'enregistraran.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Què vols enregistrar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Quanta estona vols que duri l\'enregistrament?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Ja s\'ha programat"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Ja s\'ha programat l\'enregistrament d\'aquest programa per a les <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Ja s\'ha enregistrat"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Aquest programa ja s\'ha enregistrat. El trobaràs a la biblioteca de DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"El programa enregistrat no s\'ha trobat."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Enregistraments relacionats"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Cap descripció del programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d enregistraments</item>
+ <item quantity="one">%1$d enregistrament</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"S\'ha suprimit <xliff:g id="PROGRAMNAME">%1$s</xliff:g> de l\'horari d\'enregistrament"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"S\'enregistrarà parcialment per conflictes amb sintonitzador."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"No s\'enregistrarà perquè hi ha conflictes amb sintonitzador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Encara no hi ha enregistraments programats.\nPots programar-ne des de la programació."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d conflictes d\'enregistrament</item>
+ <item quantity="one">%1$d conflicte d\'enregistrament</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Configuració de la sèrie"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Inicia enregistrament sèrie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Atura enregistrament sèrie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Vols aturar l\'enregistrament de la sèrie?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Els episodis enregistrats continuaran estant disponibles a la biblioteca de DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Atura"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No hi ha episodis disponibles.\nS\'enregistraran quan estiguin disponibles."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minuts)</item>
+ <item quantity="one">(%1$d minut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Avui"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Demà"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ahir"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Avui, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Demà, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puntuació"</string>
</resources>
diff --git a/res/values-cs/arrays.xml b/res/values-cs/arrays.xml
index b56275a8..c116f645 100644
--- a/res/values-cs/arrays.xml
+++ b/res/values-cs/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Úplné"</item>
<item msgid="8568284598210500589">"Přiblížení"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Všechny kanály"</item>
- <item msgid="6897460857821394118">"Rodina/děti"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Nakupování"</item>
- <item msgid="3296058637230163031">"Filmy"</item>
- <item msgid="1054540282883891201">"Komedie"</item>
- <item msgid="7900158429062595471">"Cestování"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Vzdělávání"</item>
- <item msgid="7396447839483867269">"Zvířata/příroda"</item>
- <item msgid="4738043455148062673">"Zpravodajství"</item>
- <item msgid="7405041316051047427">"Hry"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Všechny kanály"</item>
- <item msgid="7909003973960375395">"Rodina/děti"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Nakupování"</item>
- <item msgid="6083795019290250078">"Filmy"</item>
- <item msgid="8302638329222449550">"Komedie"</item>
- <item msgid="3803709976021475052">"Cestování"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Vzdělávání"</item>
- <item msgid="7511135485827589547">"Zvířata/příroda"</item>
- <item msgid="6961248112238009967">"Zpravodajství"</item>
- <item msgid="6484685553679698447">"Hry"</item>
- <item msgid="2737158328243183190">"Umění"</item>
- <item msgid="6577176952650166615">"Zábava"</item>
- <item msgid="7886693831871777617">"Životní styl"</item>
- <item msgid="8145832312485577062">"Hudba"</item>
- <item msgid="1345789204804308580">"Šampionáty"</item>
- <item msgid="2736680312770771994">"Věda a technika"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Všechny kanály"</item>
+ <item msgid="928298872841713530">"Rodina/děti"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Nakupování"</item>
+ <item msgid="167201149441442173">"Filmy"</item>
+ <item msgid="525966731464264290">"Komedie"</item>
+ <item msgid="6096710741527327836">"Cestování"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Vzdělávání"</item>
+ <item msgid="7221999662426308394">"Zvířata/příroda"</item>
+ <item msgid="375300513250925001">"Zpravodajství"</item>
+ <item msgid="7746320336582330410">"Hraní her"</item>
+ <item msgid="1255741860568329178">"Umění"</item>
+ <item msgid="7603949681065702867">"Zábava"</item>
+ <item msgid="4453821994746804366">"Životní styl"</item>
+ <item msgid="3488534597567932843">"Hudba"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Věda a technika"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Televize online"</item>
diff --git a/res/values-cs/rating_system_strings.xml b/res/values-cs/rating_system_strings.xml
index fe416df5..ffdedaab 100644
--- a/res/values-cs/rating_system_strings.xml
+++ b/res/values-cs/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 53fefb0b..6dac1751 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Předchozí"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programový průvodce"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Jsou dostupné nové kanály"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Odkaz není k dispozici"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Spustit aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Skryté titulky"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Režim zobrazení"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Dílčí hodnocení"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Chcete-li sledovat tento kanál, zadejte kód PIN."</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Chcete-li sledovat tento program, zadejte kód PIN."</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Tento program má hodnocení <xliff:g id="RATING">%1$s</xliff:g>. Chcete-li jej sledovat, zadejte kód PIN."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Zadání kódu PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Chcete-li nastavit rodičovskou kontrolu, vytvořte kód PIN."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Zadejte nový PIN"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licence open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licence open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Verze"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Pomáhat s vylepšováním aktivních kanálů"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Sdílet s Googlem anonymní statistiky využití a diagnostické údaje, abychom Televizi online mohli zlepšit a zabránit problémům, jako jsou selhání a zamrzání."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Chcete-li tento kanál sledovat, stiskněte šipku vpravo a zadejte kód PIN."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Chcete-li tento program sledovat, stiskněte šipku vpravo a zadejte kód PIN."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Tento program má hodnocení <xliff:g id="RATING">%1$s</xliff:g>.\nChcete-li tento program sledovat, stiskněte šipku vpravo a zadejte kód PIN."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Pouze zvuk"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Slabý signál"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nejste připojeni k internetu"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="few">Tento kanál do <xliff:g id="END_TIME_1">%1$s</xliff:g> nelze přehrát, protože se nahrávají jiné kanály. \n\nChcete-li upravit plán nahrávání, stiskněte šipku vpravo.</item>
+ <item quantity="many">Tento kanál do <xliff:g id="END_TIME_1">%1$s</xliff:g> nelze přehrát, protože se nahrávají jiné kanály. \n\nChcete-li upravit plán nahrávání, stiskněte šipku vpravo.</item>
+ <item quantity="other">Tento kanál do <xliff:g id="END_TIME_1">%1$s</xliff:g> nelze přehrát, protože se nahrávají jiné kanály. \n\nChcete-li upravit plán nahrávání, stiskněte šipku vpravo.</item>
+ <item quantity="one">Tento kanál do <xliff:g id="END_TIME_0">%1$s</xliff:g> nelze přehrát, protože se nahrává jiný kanál. \n\nChcete-li upravit plán nahrávání, stiskněte šipku vpravo.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Bez názvu"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanál byl zablokován"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nové"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nejsou k dispozici žádné kanály"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nový"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Není nastaveno"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Stáhnout další zdroje"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Procházejte aplikace, které nabízejí televizi online"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Stáhnout další zdroje"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Procházejte aplikace, které nabízejí televizi online"</string>
<string name="new_sources_title" msgid="3878933676500061895">"K dispozici jsou nové zdroje kanálů"</string>
<string name="new_sources_description" msgid="749649005588426813">"K dispozici jsou nové zdroje kanálů s dalšími kanály.\nMůžete je nastavit hned nebo později v nastavení zdrojů kanálů."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Nastavit"</string>
@@ -187,14 +191,188 @@
<string name="msg_no_specific_input" msgid="2688885987104249852">"Televizní vstup nebyl nalezen."</string>
<string name="msg_no_pip_support" msgid="161508628996629445">"Funkce PIP není podporována."</string>
<string name="msg_no_available_input_by_pip" msgid="7038191654524679666">"Není k dispozici vstup, který lze zobrazovat pomocí PIP."</string>
- <string name="msg_not_passthrough_input" msgid="4502101097091087411">"Typ tuneru není vhodný. Pro TV vstup typu tuneru spusťte aplikaci Aktivní kanály."</string>
+ <string name="msg_not_passthrough_input" msgid="4502101097091087411">"Typ tuneru není vhodný. Pro TV vstup typu tuneru spusťte aplikaci Televize online."</string>
<string name="msg_tune_failed" msgid="3277419551849972252">"Ladění se nezdařilo."</string>
<string name="msg_missing_app" msgid="8291542072400042076">"Aplikace potřebná k provedení této akce nebyla nalezena."</string>
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Všechny zdrojové kanály jsou skryty.\nVyberte alespoň jeden kanál, který chcete sledovat."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video nečekaně přestalo být dostupné."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Tlačítko Zpět je určeno pro připojené zařízení. Ukončení provedete pomocí tlačítka Domů."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"V tomto zařízení se systémem Android Lollipop nejsou aktivní kanály podporovány."</string>
- <string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Aktivní kanály potřebují oprávnění ke čtení televizních programů."</string>
+ <string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Televize online potřebuje oprávnění ke čtení televizních programů."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Nastavte zdroje"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Televize online spojuje klasické televizní kanály se streamovanými kanály z aplikací. \n\nChcete-li začít, nastavte zdroje kanálů, které již jsou nainstalovány. Případně můžete v Obchodu Google Play vyhledat další aplikace, které nabízí televizi online."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Nahrávání a plány"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minut"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minut"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hodina"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hodiny"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nedávné"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Naplánováno"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriál"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Ostatní"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Tento kanál nelze nahrávat."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Tento program nelze nahrávat."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Nahrávání programu <xliff:g id="PROGRAMNAME">%1$s</xliff:g> bylo naplánováno"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Nahrávání programu <xliff:g id="PROGRAMNAME">%1$s</xliff:g> od této chvíle do <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Celý plán"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="few">Další %1$d dny</item>
+ <item quantity="many">Dalších %1$d dne</item>
+ <item quantity="other">Dalších %1$d dnů</item>
+ <item quantity="one">Další %1$d den</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="few">%1$d minuty</item>
+ <item quantity="many">%1$d minuty</item>
+ <item quantity="other">%1$d minut</item>
+ <item quantity="one">%d minuta</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="few">%1$d nové nahrávky</item>
+ <item quantity="many">%1$d nové nahrávky</item>
+ <item quantity="other">%1$d nových nahrávek</item>
+ <item quantity="one">%1$d nová nahrávka</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="few">%1$d nahrávky</item>
+ <item quantity="many">%1$d nahrávky</item>
+ <item quantity="other">%1$d nahrávek</item>
+ <item quantity="one">%1$d nahrávka</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="few">%1$d naplánované nahrávky</item>
+ <item quantity="many">%1$d naplánované nahrávky</item>
+ <item quantity="other">%1$d naplánovaných nahrávek</item>
+ <item quantity="one">%1$d naplánovaná nahrávka</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Přehrát"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Přehrát od začátku"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Pokračovat v přehrávání"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Smazat"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Smazat nahraný obsah"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Pokračovat"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Série <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Otevřít program"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Další informace"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Smazání obsahu"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Vyberte epizody, které chcete smazat. Po smazání je nebude možné obnovit."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nemáte žádný obsah ke smazání."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Vybrat přehrané epizody"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Vybrat všechny epizody"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Smazat všechny epizody"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Přehráli jste <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g> min"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Přehráli jste <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g> s"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nepřehrané"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="few">Smazány %1$d z %2$d epizod</item>
+ <item quantity="many">Smazáno %1$d z %2$d epizod</item>
+ <item quantity="other">Smazáno %1$d z %2$d epizod</item>
+ <item quantity="one">Smazána %1$d z %2$d epizod</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritní"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Nejvyšší"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Nejnižší"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Č. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanály"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Libovolný"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Vybrat prioritu"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Když naplánujete nahrávání příliš mnoha programů, budou nahrány pouze programy s vyšší prioritou."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Uložit"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Jednorázová nahrávání mají nejvyšší prioritu"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Zrušit"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Zrušit"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Zapomenout"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Zastavit"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Zobrazit plán nahrávání"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Pouze tento program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"nyní – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Celou sérii…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Přesto naplánovat"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Místo toho nahrát tento program"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Zrušit toto nahrávání"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Sledovat"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Lze nahrát"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Nahrávání je naplánováno"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflikt nahrávání"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Nahrávání"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Nahrávání se nezdařilo"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Načítání programů za účelem vytvoření plánů nahrávání"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Načítání programů"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR potřebuje víc místa"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Programy bude možné nahrát pomocí DVR. Ve vašem zařízení však momentálně není dost místa, a DVR proto nebude fungovat. Zapojte externí úložiště o velikosti minimálně <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB a podle pokynů jej naformátujte jako úložiště zařízení."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Úložiště není dostupné"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Část úložiště, které využívá DVR, není dostupná. Před opětovnou aktivací DVR připojte externí disk. Pokud úložiště již není k dispozici, můžete jej zapomenout."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Zapomenout úložiště?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Veškerý nahraný obsah a plány nahrávání budou smazány."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Zastavit nahrávání?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Nahraný obsah bude uložen."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Nahrávání je naplánováno, ale obsahuje konflikty"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Nahrávání bylo zahájeno, ale obsahuje konflikty"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Nahraje se program <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Nahrává se z kanálu <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Části programu <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> nahrány nebudou."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Části programů <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> a <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> nahrány nebudou."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Části programů <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> a 1 dalšího naplánovaného programu nahrány nebudou."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="few">Části programů <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d dalších naplánovaných programů nahrány nebudou.</item>
+ <item quantity="many">Části programů <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d dalšího naplánovaného programu nahrány nebudou.</item>
+ <item quantity="other">Části programů <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d dalších naplánovaných programů nahrány nebudou.</item>
+ <item quantity="one">Části programů <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> a %3$d dalšího naplánovaného programu nahrány nebudou.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Co chcete nahrát?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Jak dlouho chcete nahrávat?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Již naplánováno"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Nahrávání stejného programu již bylo naplánováno na <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Již nahráno"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Tento program již byl nahrán. Naleznete jej v knihovně DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Nahraný program nebyl nalezen."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Související nahrávky"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Žádný popis programu)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="few">%1$d nahrávky</item>
+ <item quantity="many">%1$d nahrávky</item>
+ <item quantity="other">%1$d nahrávek</item>
+ <item quantity="one">%1$d nahrávka</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> byl odstraněn z plánu nahrávání"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Z důvodu konfliktu tunerů bude nahrána jen část obsahu."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Z důvodu konfliktu tunerů obsah nebude nahrán."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Zatím není naplánováno žádné nahrávání.\nNahrávání lze naplánovat pomocí programového průvodce."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="few">%1$d konflikty nahrávání</item>
+ <item quantity="many">%1$d konfliktu nahrávání</item>
+ <item quantity="other">%1$d konfliktů nahrávání</item>
+ <item quantity="one">%1$d konflikt nahrávání</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Nastavení série"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Spustit nahrávání série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Zastavit nahrávání série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Zastavit nahrávání série?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Nahrané epizody zůstanou dostupné v knihovně DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Zastavit"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nejsou k dispozici žádné epizody.\nEpizody budou nahrány, až budou k dispozici."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="few">(%1$d minuty)</item>
+ <item quantity="many">(%1$d minuty)</item>
+ <item quantity="other">(%1$d minut)</item>
+ <item quantity="one">(%1$d minuta) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Dnes"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Zítra"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Včera"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Dnes v <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Zítra v <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Skóre"</string>
</resources>
diff --git a/res/values-da/arrays.xml b/res/values-da/arrays.xml
index 95f67ea3..9e0d84c6 100644
--- a/res/values-da/arrays.xml
+++ b/res/values-da/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Fuld"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alle kanaler"</item>
- <item msgid="6897460857821394118">"Familie/børn"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Film"</item>
- <item msgid="1054540282883891201">"Komedie"</item>
- <item msgid="7900158429062595471">"Rejser"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Uddannelse"</item>
- <item msgid="7396447839483867269">"Dyr/naturens verden"</item>
- <item msgid="4738043455148062673">"Nyheder"</item>
- <item msgid="7405041316051047427">"Spil"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alle kanaler"</item>
- <item msgid="7909003973960375395">"Familie/børn"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Film"</item>
- <item msgid="8302638329222449550">"Komedie"</item>
- <item msgid="3803709976021475052">"Rejser"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Uddannelse"</item>
- <item msgid="7511135485827589547">"Dyr/naturens verden"</item>
- <item msgid="6961248112238009967">"Nyheder"</item>
- <item msgid="6484685553679698447">"Spil"</item>
- <item msgid="2737158328243183190">"Kunst"</item>
- <item msgid="6577176952650166615">"Underholdning"</item>
- <item msgid="7886693831871777617">"Livsstil"</item>
- <item msgid="8145832312485577062">"Musik"</item>
- <item msgid="1345789204804308580">"Premiere"</item>
- <item msgid="2736680312770771994">"Teknik/videnskab"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alle kanaler"</item>
+ <item msgid="928298872841713530">"Familie/børn"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Film"</item>
+ <item msgid="525966731464264290">"Komedie"</item>
+ <item msgid="6096710741527327836">"Rejser"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Uddannelse"</item>
+ <item msgid="7221999662426308394">"Dyr/naturens verden"</item>
+ <item msgid="375300513250925001">"Nyheder"</item>
+ <item msgid="7746320336582330410">"Spil"</item>
+ <item msgid="1255741860568329178">"Kunst"</item>
+ <item msgid="7603949681065702867">"Underholdning"</item>
+ <item msgid="4453821994746804366">"Livsstil"</item>
+ <item msgid="3488534597567932843">"Musik"</item>
+ <item msgid="7452153120614274095">"Premiere"</item>
+ <item msgid="8215762047341133299">"Teknik/videnskab"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Tv-kanaler"</item>
diff --git a/res/values-da/rating_system_strings.xml b/res/values-da/rating_system_strings.xml
index 316020b0..01cc4e44 100644
--- a/res/values-da/rating_system_strings.xml
+++ b/res/values-da/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 244270e9..b053e77d 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Forrige"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programguide"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Der er nye tilgængelige kanaler"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Intet tilgængeligt link"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Åbn <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Undertekster"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Format"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Underklassificering"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Angiv din pinkode for at se denne kanal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Angiv din pinkode for at se dette program"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Dette program er klassificeret som <xliff:g id="RATING">%1$s</xliff:g>. Du skal indtaste din pinkode for at se programmet"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Angiv din pinkode"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Angiv en pinkode for at aktivere børnesikring"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Angiv ny pinkode"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Open source-licenser"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Open source-licenser"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Hjælp med at forbedre Tv-kanaler"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Del anonyme forbrugs- og diagnostikdata med Google, så vi kan forbedre Tv-kanaler og forhindre problemer, som f.eks. nedbrud og fastfrysning."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Se denne kanal ved at trykke på højreknappen og angive din pinkode"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Se dette program ved at trykke på højreknappen og angive din pinkode"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Dette program er klassificereret som <xliff:g id="RATING">%1$s</xliff:g>.\nSe dette program ved at trykke på højreknappen og angive din pinkode"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Kun lyd"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Svagt signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Der er ingen internetforbindelse"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Denne kanal kan ikke afspilles før kl. <xliff:g id="END_TIME_1">%1$s</xliff:g>, da andre kanaler i øjeblikket optages. \n\nTryk på højreknappen for at justere tidsplanen for optagelse.</item>
+ <item quantity="other">Denne kanal kan ikke afspilles før kl. <xliff:g id="END_TIME_1">%1$s</xliff:g>, da andre kanaler i øjeblikket optages. \n\nTryk på højreknappen for at justere tidsplanen for optagelse.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Ingen titel"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanalen er blokeret"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nye"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Der er ingen tilgængelige kanaler"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nye"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Ikke konfigureret"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Få flere kilder"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Gennemse apps, der viser tv-kanaler"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Få flere kilder"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Gennemse apps, der viser tv-kanaler"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Der er nye tilgængelige kanalkilder"</string>
<string name="new_sources_description" msgid="749649005588426813">"Du kan få kanaler fra nye kanalkilder.\nKonfigurer dem nu, eller gør det senere i indstillingen for kanalkilder."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Konfigurer nu"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alle kildekanaler er skjult.\nVælg mindst én kanal, som du vil se."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videoen er mod forventning ikke tilgængelig"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Knappen Tilbage er til den tilsluttede enhed. Tryk på knappen Hjem for at afslutte."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Tv-kanaler understøttes ikke på denne enhed med Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Tv-kanaler skal have tilladelse for at kunne læse tv-guiden."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Konfigurer dine kilder"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Tv-kanaler kombinerer oplevelsen af traditionelle fjernsynskanaler med streamingkanaler fra apps. \n\nKom godt i gang ved at konfigurere de kanalkilder, der allerede er installeret. Du kan også gå til Google Play Butik og finde flere apps med tv-kanaler."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Optagelser og tidsplaner"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutter"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutter"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 time"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 timer"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Seneste"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Planlagt"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Andre"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanalen kan ikke optages."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programmet kan ikke optages."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Optagelse af <xliff:g id="PROGRAMNAME">%1$s</xliff:g> er planlagt"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Optager <xliff:g id="PROGRAMNAME">%1$s</xliff:g> fra nu af til <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Hele tidsplanen"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Næste %1$d dag</item>
+ <item quantity="other">Næste %1$d dage</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minut</item>
+ <item quantity="other">%1$d minutter</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d ny optagelse</item>
+ <item quantity="other">%1$d nye optagelser</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d optagelse</item>
+ <item quantity="other">%1$d optagelser</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d planlagt optagelse</item>
+ <item quantity="other">%1$d planlagte optagelser</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Se"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Afspil fra begyndelsen"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Genoptag afspilning"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Slet"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Slet optagelser"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Genoptag"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Sæson <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Se tidsplan"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Læs mere"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Slet optagelser"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Vælg de afsnit, du vil slette. De kan ikke gendannes, når du har slettet dem."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Der er ingen optagelser at slette."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Markér sete afsnit"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Markér alle afsnit"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Fjern markering af alle afsnit"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Du har set <xliff:g id="WATCHED">%1$d</xliff:g> ud af <xliff:g id="DURATION">%2$d</xliff:g> minutter"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Du har set <xliff:g id="WATCHED">%1$d</xliff:g> ud af <xliff:g id="DURATION">%2$d</xliff:g> sekunder"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Aldrig set"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d ud af %2$d afsnit blev slettet</item>
+ <item quantity="other">%1$d ud af %2$d afsnit blev slettet</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Højest"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lavest"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanaler"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Alle"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Vælg prioritet"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Når der er for mange programmer at optage på samme tid, er det kun programmer med højere prioritet, der optages."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Gem"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Engangsoptagelser har højest prioritet"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Annuller"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Annuller"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Glem"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stop"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Tidsplan for optagelse"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Dette ene program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"nu-<xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Hele serien…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Opret alligevel"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Optag dette program i stedet for"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Annuller denne optagelse"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Se nu"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kan optages"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Optagelse er planlagt"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Modstridende optagelser"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Optager"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Optagelsen mislykkedes"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Læser programmer for at oprette tidsplaner for optagelse"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Læser programmer"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR kræver mere lagerplads"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Du kan optage programmer med DVR. Der er dog ikke længere nok lagerplads på din enhed til at DVR kan fungere. Tilslut et eksternt drev på mindst <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB, og følg vejledningen i, hvordan du formaterer det som internt lager."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Lager mangler"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Noget af det lager, der bruges af DVR, mangler. Tilslut det eksterne drev, du brugte før, for at genaktivere DVR. Alternativt kan du vælge at glemme lageret, hvis det ikke længere er tilgængeligt."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Vil du glemme lageret?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Du mister alt dit optagede indhold og dine tidsplaner."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Skal optagelsen stoppes?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Det optagede indhold gemmes."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Optagelsen er planlagt, men der er konflikter"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Optagelsen er startet, men der er konflikter"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> optages."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> optages."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Dele af <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> optages ikke."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Dele af <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> og <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> optages ikke."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Dele af <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> og én anden planlagt optagelse optages ikke."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Dele af <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> og %3$d anden planlagt optagelse optages ikke.</item>
+ <item quantity="other">Dele af <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> og %3$d andre planlagte optagelser optages ikke.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Hvad vil du optage?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hvor længe vil du gerne optage?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Allerede planlagt"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"En optagelse af dette program er allerede planlagt kl. <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Det er allerede optaget"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Dette program er allerede optaget. Du kan finde det i DVR-samlingen."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Det optagede program blev ikke fundet."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Relaterede optagelser"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ingen programbeskrivelse)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d optagelse</item>
+ <item quantity="other">%1$d optagelser</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> blev fjernet fra tidsplanen for optagelse"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Optages delvist, da der ikke er en tilgængelig tuner."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Optages ikke, da der ikke er en tilgængelig tuner."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Der er endnu ingen planlagte optagelser.\nDu kan planlægge optagelser i programguiden."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d konflikt i forbindelse med optagelse</item>
+ <item quantity="other">%1$d konflikter i forbindelse med optagelse</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Indstillinger for Serier"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Start optagelse af serie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stop optagelse af serie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Vil du stoppe optagelsen af serien?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Optagede afsnit kan findes i DVR-samlingen."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stop"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Der er ingen tilgængelige tv-serier.\nDe optages, så snart de er tilgængelige.."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minut)</item>
+ <item quantity="other">(%1$d minutter)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"I dag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"I morgen"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"I går"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i dag"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i morgen"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Resultat"</string>
</resources>
diff --git a/res/values-de/arrays.xml b/res/values-de/arrays.xml
index 6cf5c03f..d7fad130 100644
--- a/res/values-de/arrays.xml
+++ b/res/values-de/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Voll"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alle Kanäle"</item>
- <item msgid="6897460857821394118">"Familie/Kinder"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Einkaufen"</item>
- <item msgid="3296058637230163031">"Filme"</item>
- <item msgid="1054540282883891201">"Komödien"</item>
- <item msgid="7900158429062595471">"Reisen"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Bildung"</item>
- <item msgid="7396447839483867269">"Tiere/Wildtiere"</item>
- <item msgid="4738043455148062673">"Nachrichten"</item>
- <item msgid="7405041316051047427">"Spiele"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alle Kanäle"</item>
- <item msgid="7909003973960375395">"Familie/Kinder"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Einkaufen"</item>
- <item msgid="6083795019290250078">"Filme"</item>
- <item msgid="8302638329222449550">"Komödien"</item>
- <item msgid="3803709976021475052">"Reisen"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Bildung"</item>
- <item msgid="7511135485827589547">"Tiere/Wildtiere"</item>
- <item msgid="6961248112238009967">"Nachrichten"</item>
- <item msgid="6484685553679698447">"Spiele"</item>
- <item msgid="2737158328243183190">"Kunst"</item>
- <item msgid="6577176952650166615">"Unterhaltung"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Musik"</item>
- <item msgid="1345789204804308580">"Premiere"</item>
- <item msgid="2736680312770771994">"Technik/Wissenschaft"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alle Kanäle"</item>
+ <item msgid="928298872841713530">"Familie/Kinder"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Filme"</item>
+ <item msgid="525966731464264290">"Komödien"</item>
+ <item msgid="6096710741527327836">"Reisen"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Bildung"</item>
+ <item msgid="7221999662426308394">"Tiere/Wildtiere"</item>
+ <item msgid="375300513250925001">"Nachrichten"</item>
+ <item msgid="7746320336582330410">"Spiele"</item>
+ <item msgid="1255741860568329178">"Kunst"</item>
+ <item msgid="7603949681065702867">"Unterhaltung"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Musik"</item>
+ <item msgid="7452153120614274095">"Premiere"</item>
+ <item msgid="8215762047341133299">"Technik/Wissenschaft"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live-TV"</item>
diff --git a/res/values-de/rating_system_strings.xml b/res/values-de/rating_system_strings.xml
index 66e49606..303c7f60 100644
--- a/res/values-de/rating_system_strings.xml
+++ b/res/values-de/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 525039bb..b4cc6c0f 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Zurück"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programmübersicht"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Neue Kanäle verfügbar"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Kein Link verfügbar"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Untertitel"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Anzeigemodus"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subkategorien"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Zum Ansehen dieses Kanals PIN eingeben"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Zum Ansehen dieses Programms PIN eingeben"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Diese Sendung wurde als \"<xliff:g id="RATING">%1$s</xliff:g>\" eingestuft. Gib deinen PIN ein, um sie anzusehen"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN eingeben"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Erstellen Sie eine PIN, um den Jugendschutz einzurichten."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Neue PIN eingeben"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Open-Source-Lizenzen"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Open-Source-Lizenzen"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Bei der Verbesserung von Live TV helfen"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Teilen Sie anonyme Nutzungs- und Diagnosedaten mit Google, damit wir Live-TV verbessern können und die App nicht mehr hängen bleibt oder abstürzt."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Um sich diesen Kanal anzusehen, drücken Sie rechts und geben Sie die PIN ein."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Um sich dieses Programm anzusehen, drücken Sie rechts und geben Sie die PIN ein."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Diese Sendung wurde als \"<xliff:g id="RATING">%1$s</xliff:g>\" eingestuft.\nUm sich diese Sendung anzusehen, drücken Sie rechts und geben Sie Ihre PIN ein."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Nur Audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Schwaches Signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Keine Internetverbindung"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Dieser Kanal kann bis <xliff:g id="END_TIME_1">%1$s</xliff:g> nicht wiedergegeben werden, weil andere Kanäle aufgenommen werden. \n\nDrücken Sie rechts, um den Aufnahmeplan anzupassen.</item>
+ <item quantity="one">Dieser Kanal kann bis <xliff:g id="END_TIME_0">%1$s</xliff:g> nicht wiedergegeben werden, weil ein anderer Kanal aufgenommen wird. \n\nDrücken Sie rechts, um den Aufnahmeplan anzupassen.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Kein Titel"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal blockiert"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Neu"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Keine Kanäle verfügbar"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Neu"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nicht eingerichtet"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Weitere Quellen suchen"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Nach Apps suchen, die Live-TV anbieten"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Weitere Quellen suchen"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Nach Apps suchen, die Live-TV anbieten"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Neue Kanalquellen verfügbar"</string>
<string name="new_sources_description" msgid="749649005588426813">"Neue Kanalquellen bieten weitere Kanäle an.\nDiese können Sie entweder jetzt oder später über die Einstellung \"Kanalquellen\" einrichten."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Jetzt einrichten"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alle Quellkanäle sind ausgeblendet.\nWählen Sie mindestens einen Kanal aus, den Sie anschauen möchten."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Das Video ist unerwarteterweise nicht verfügbar."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Die Taste \"Zurück\" gilt für das verbundene Gerät. Zum Beenden drücken Sie auf \"Startseite\"."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV wird auf diesem Gerät mit Android Lollipop nicht unterstützt."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV benötigt einen Lesezugriff für die Kanalliste."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Quellen einrichten"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Bei Live-TV wird die Nutzererfahrung mit klassischen Fernsehsendern mit der von Streaming-Kanälen von Apps kombiniert.\n\nRichten Sie zuerst die bereits installierten Kanalquellen ein. Sie können auch im Google Play Store nach weiteren Apps suchen, die Live-TV anbieten."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Aufnahmen und Zeitpläne"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 Minuten"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 Minuten"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 Stunde"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 Stunden"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Letzte"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Geplant"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serien"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Andere"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Dieser Kanal kann nicht aufgenommen werden."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Diese Sendung kann nicht aufgenommen werden."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Aufnahme von <xliff:g id="PROGRAMNAME">%1$s</xliff:g> geplant"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"\"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" wird ab jetzt bis <xliff:g id="ENDTIME">%2$s</xliff:g> aufgenommen"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programmübersicht"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Nächste %1$d Tage</item>
+ <item quantity="one">Nächster %1$d Tag</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d Minuten</item>
+ <item quantity="one">%1$d Minute</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d neue Aufnahmen</item>
+ <item quantity="one">%1$d neue Aufnahme</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d Aufnahmen</item>
+ <item quantity="one">%1$d Aufnahme</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d geplante Aufnahmen</item>
+ <item quantity="one">%1$d geplante Aufnahme</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Ansehen"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Von Anfang an abspielen"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Wiedergabe fortsetzen"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Löschen"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Aufnahmen löschen"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Fortsetzen"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Staffel <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Aufnahmeplan"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Weitere Infos"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Aufnahmen löschen"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Wählen Sie die Folgen aus, die gelöscht werden sollen. Eine Wiederherstellung ist nicht möglich."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Es sind keine Aufnahmen zum Löschen vorhanden."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Angesehene Folgen auswählen"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Alle Folgen auswählen"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Auswahl für alle Folgen aufheben"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> von <xliff:g id="DURATION">%2$d</xliff:g> Minuten angesehen"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> von <xliff:g id="DURATION">%2$d</xliff:g> Sekunden angesehen"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Noch nie angesehen"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d von %2$d Folgen wurden gelöscht</item>
+ <item quantity="one">%1$d von %2$d Folge wurde gelöscht</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorität"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Höchste"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Niedrigste"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nein. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanäle"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Alle"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Priorität auswählen"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Wenn zu viele Programme gleichzeitig aufgenommen werden, werden nur die Programme mit höherer Priorität aufgenommen."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Speichern"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Einmalige Aufnahmen haben höchste Priorität"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Abbrechen"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Abbrechen"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Entfernen"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Beenden"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Aufnahmeplan ansehen"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Nur diese Folge"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"Von jetzt bis <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Die ganze Serie…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Aufnahmeplan trotzdem erstellen"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Stattdessen diese Sendung aufnehmen"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Diesen Aufnahmeplan abbrechen"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Jetzt ansehen"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kann aufgenommen werden"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Aufnahme geplant"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflikt bei der Aufnahme"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Aufnahme"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Aufnahme fehlgeschlagen"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Sendungen werden gelesen, um Aufnahmepläne zu erstellen"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Sendungen werden gelesen"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR benötigt mehr Speicher"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Sie können mit DVR Sendungen aufnehmen, jedoch ist auf Ihrem Gerät momentan nicht ausreichend Speicherplatz vorhanden. Schließen Sie ein externes Laufwerk mit mindestens <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB freiem Speicher an und folgen Sie der Anleitung zur Formatierung als Gerätespeicher."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Speicher nicht verfügbar"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Ein Teil des DVR-Speichers ist nicht verfügbar. Um DVR neu zu aktivieren, stellen Sie eine Verbindung zu dem externen Gerät her, das Sie zuvor verwendet haben. Sie können den Speicher auch entfernen, wenn er nicht mehr verfügbar ist."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Speicher entfernen?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Alle aufgenommenen Inhalte und Aufnahmepläne gehen verloren."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Aufnahme beenden?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Die aufgenommenen Inhalte werden gespeichert."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Aufnahme geplant, aber es liegen Konflikte vor"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Aufnahme wurde gestartet, aber es liegen Konflikte vor"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> wird aufgenommen."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> wird aufgenommen."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Teile von <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> werden nicht aufgenommen."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Teile von <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> und <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> werden nicht aufgenommen."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Teile von <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> und einer weiteren geplanten Aufnahme werden nicht aufgenommen."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Teile von <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> und %3$d weiteren geplanten Aufnahmen werden nicht aufgenommen.</item>
+ <item quantity="one">Teile von <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> und %4$d weiteren geplanten Aufnahme werden nicht aufgenommen.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Was möchten Sie aufnehmen?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Wie lange möchten Sie aufnehmen?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Schon dem Aufnahmeplan hinzugefügt"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Diese Sendung wurde dem Aufnahmeplan schon hinzugefügt und wird um <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> aufgenommen."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Schon aufgenommen"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Diese Sendung wurde schon aufgenommen. Sie ist in der DVR-Bibliothek verfügbar."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Aufgenommenes Programm wurde nicht gefunden."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Ähnliche Aufnahmen"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Keine Programmbeschreibung)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d Aufnahmen</item>
+ <item quantity="one">%1$d Aufnahme</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> wurde vom Aufnahmeplan entfernt"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Wird aufgrund von Tunerkonflikten nur teilweise aufgenommen."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Wird aufgrund von Tunerkonflikten nicht aufgenommen."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Es sind noch keine Aufnahmen geplant.\nDu kannst von der Programmübersicht einen Aufnahmeplan erstellen."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d Konflikte bei der Aufnahme</item>
+ <item quantity="one">%1$d Konflikt bei der Aufnahme</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Serieneinstellungen"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Serienaufnahme starten"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Serienaufnahme beenden"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Sie möchten die Serienaufnahme beenden?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Die aufgenommenen Folgen werden in der DVR-Bibliothek gespeichert."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Beenden"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Keine Folgen verfügbar.\nSie werden aufgenommen, sobald sie verfügbar sind."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d Minuten)</item>
+ <item quantity="one">(%1$d Minute) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Heute"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Morgen"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Gestern"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Heute <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Morgen <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Punkte"</string>
</resources>
diff --git a/res/values-el/arrays.xml b/res/values-el/arrays.xml
index 2978fa85..15114cc8 100644
--- a/res/values-el/arrays.xml
+++ b/res/values-el/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Πλήρης"</item>
<item msgid="8568284598210500589">"Ζουμ"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Όλα τα κανάλια"</item>
- <item msgid="6897460857821394118">"Οικογένεια/παιδικά"</item>
- <item msgid="551257741825778215">"Αθλητικά"</item>
- <item msgid="452133796804325879">"Αγορές"</item>
- <item msgid="3296058637230163031">"Ταινίες"</item>
- <item msgid="1054540282883891201">"Κωμωδία"</item>
- <item msgid="7900158429062595471">"Ταξίδια"</item>
- <item msgid="3768998587825611787">"Δραματικές"</item>
- <item msgid="8340620094959282881">"Εκπαίδευση"</item>
- <item msgid="7396447839483867269">"Ζώα/άγρια φύση"</item>
- <item msgid="4738043455148062673">"Ειδήσεις"</item>
- <item msgid="7405041316051047427">"Παιχνίδια"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Όλα τα κανάλια"</item>
- <item msgid="7909003973960375395">"Οικογένεια/παιδικά"</item>
- <item msgid="3185279732911635789">"Αθλητικά"</item>
- <item msgid="4704858492065325964">"Αγορές"</item>
- <item msgid="6083795019290250078">"Ταινίες"</item>
- <item msgid="8302638329222449550">"Κωμωδία"</item>
- <item msgid="3803709976021475052">"Ταξίδια"</item>
- <item msgid="8116747365234169059">"Δραματικές"</item>
- <item msgid="7356447541595315913">"Εκπαίδευση"</item>
- <item msgid="7511135485827589547">"Ζώα/άγρια φύση"</item>
- <item msgid="6961248112238009967">"Ειδήσεις"</item>
- <item msgid="6484685553679698447">"Παιχνίδια"</item>
- <item msgid="2737158328243183190">"Τέχνες"</item>
- <item msgid="6577176952650166615">"Διασκέδαση"</item>
- <item msgid="7886693831871777617">"Τρόπος ζωής"</item>
- <item msgid="8145832312485577062">"Μουσική"</item>
- <item msgid="1345789204804308580">"Πρεμιέρες"</item>
- <item msgid="2736680312770771994">"Τεχνολογία/Επιστήμη"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Όλα τα κανάλια"</item>
+ <item msgid="928298872841713530">"Οικογενεικά/παιδικά"</item>
+ <item msgid="2751606947569857164">"Αθλητικά"</item>
+ <item msgid="7345749789651321496">"Αγορές"</item>
+ <item msgid="167201149441442173">"Ταινίες"</item>
+ <item msgid="525966731464264290">"Κωμωδία"</item>
+ <item msgid="6096710741527327836">"Ταξίδια"</item>
+ <item msgid="2851882187117833883">"Δραματική"</item>
+ <item msgid="78492781188719038">"Εκπαίδευση"</item>
+ <item msgid="7221999662426308394">"Ζώα/άγρια φύση"</item>
+ <item msgid="375300513250925001">"Ειδήσεις"</item>
+ <item msgid="7746320336582330410">"Παιχνίδια"</item>
+ <item msgid="1255741860568329178">"Τέχνες"</item>
+ <item msgid="7603949681065702867">"Ψυχαγωγία"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Μουσική"</item>
+ <item msgid="7452153120614274095">"Πρεμιέρες"</item>
+ <item msgid="8215762047341133299">"Τεχνολογία/Επιστήμη"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Ζωντανά κανάλια"</item>
diff --git a/res/values-el/rating_system_strings.xml b/res/values-el/rating_system_strings.xml
index ea494c97..1ebcf6f6 100644
--- a/res/values-el/rating_system_strings.xml
+++ b/res/values-el/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 478c0191..9e8e042c 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Προηγούμενο"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Οδηγός προγράμματος"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Νέα κανάλια διαθέσιμα"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Δεν υπάρχει σύνδεσμος"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Ανοίξτε το <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Υπότιτλοι"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Τρόπος εμφάν."</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Δευτ. αξιολογήσεις"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Εισαγάγετε PIN για να δείτε αυτό το κανάλι"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Εισαγάγετε PIN για να δείτε αυτό το πρόγραμμα"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Αυτό το πρόγραμμα αξιολογήθηκε ως <xliff:g id="RATING">%1$s</xliff:g>. Εισαγάγετε το PIN σας για το παρακολουθήσετε"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Εισαγάγετε το PIN σας"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Για να ορίσετε γονικούς ελέγχους, δημιουργήστε ένα PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Εισαγωγή νέου κωδικού PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Άδειες λογισμικού ανοικτού κώδικα"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Άδειες λογισμικού ανοικτού κώδικα"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Έκδοση"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Συμβολή στη βελτίωση των Zωντανών καναλιών"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Μοιραστείτε ανώνυμα δεδομένα χρήσης και διαγνωστικών στοιχείων με τη Google για να βελτιώσουμε τα Ζωντανά κανάλια και να αποτρέψουμε προβλήματα όπως διακοπές λειτουργίας και πάγωμα της εφαρμογής."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Για να παρακολουθήσετε αυτό το κανάλι, πατήστε το δεξιά και εισαγάγετε το PIN σας"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Για να παρακολουθήσετε αυτό το πρόγραμμα, πατήστε δεξιά και εισαγάγετε το PIN σας"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Αυτό το πρόγραμμα αξιολογήθηκε ως <xliff:g id="RATING">%1$s</xliff:g>.\nΓια να παρακολουθήσετε αυτό το πρόγραμμα, πατήστε δεξιά και εισαγάγετε το PIN σας"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Μόνο ήχος"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Ασθενές σήμα"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Δεν είναι δυνατή η αναπαραγωγή αυτού του καναλιού μέχρι τις <xliff:g id="END_TIME_1">%1$s</xliff:g> επειδή πραγματοποιείται εγγραφή άλλων καναλιών. \n\nΠατήστε το στοιχείο \"Δεξιά\" για να προσαρμόσετε το χρονοδιάγραμμα εγγραφής.</item>
+ <item quantity="one">Δεν είναι δυνατή η αναπαραγωγή αυτού του καναλιού μέχρι τις <xliff:g id="END_TIME_0">%1$s</xliff:g> επειδή πραγματοποιείται εγγραφή κάποιου άλλου καναλιού. \n\nΠατήστε το στοιχείο \"Δεξιά\" για να προσαρμόσετε το χρονοδιάγραμμα εγγραφής.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Χωρίς τίτλο"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Το κανάλι αποκλείστηκε"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Νέα"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Δεν υπάρχουν διαθέσιμα κανάλια"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Νέα"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Δεν ρυθμίστηκε"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Λήψη περισσότερων πηγών"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Περιήγηση σε εφαρμογές που προσφέρουν ζωντανά κανάλια"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Λήψη περισσότερων πηγών"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Περιήγηση σε εφαρμογές που προσφέρουν ζωντανά κανάλια"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Υπάρχουν νέες διαθέσιμες πηγές καναλιών"</string>
<string name="new_sources_description" msgid="749649005588426813">"Οι νέες πηγές καναλιών προσφέρουν κανάλια.\nΡυθμίστε τες τώρα ή αργότερα μέσω των ρυθμίσεων πηγών καναλιών."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Ρύθμιση τώρα"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Όλα τα κανάλια προέλευσης είναι κρυφά.\nΕπιλέξτε τουλάχιστον ένα κανάλι για να παρακολουθήσετε."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Το βίντεο δεν είναι διαθέσιμο απροσδόκητα"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Το πλήκτρο BACK αφορά τη συνδεδεμένη συσκευή. Πατήστε το πλήκτρο HOME για έξοδο."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Τα ζωντανά κανάλια δεν υποστηρίζονται σε αυτήν τη συσκευή με Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Τα ζωντανά κανάλια χρειάζονται άδεια για να διαβάσουν τις τηλεοπτικές καταχωρίσεις."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Ρυθμίστε τις πηγές σας"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Τα Ζωντανά κανάλια συνδυάζουν την εμπειρία των παραδοσιακών τηλεοπτικών καναλιών με τα κανάλια μετάδοσης ροής που παρέχονται από τις εφαρμογές. \n\nΞεκινήστε με τη ρύθμιση των πηγών καναλιών που είναι ήδη εγκατεστημένα. Εναλλακτικά, περιηγηθείτε στο Google Play Store για να βρείτε περισσότερες εφαρμογές που προσφέρουν ζωντανά κανάλια."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Εγγραφές και χρονοδιαγράμματα"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 λεπτά"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 λεπτά"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ώρα"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ώρες"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Πρόσφατα"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Προγραμματισμένα"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Σειρά"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Άλλα"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Δεν είναι δυνατή η εγγραφή του καναλιού."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Δεν είναι δυνατή η εγγραφή του προγράμματος."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Το πρόγραμμα <xliff:g id="PROGRAMNAME">%1$s</xliff:g> έχει προγραμματιστεί για εγγραφή"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Εγγραφή του προγράμματος <xliff:g id="PROGRAMNAME">%1$s</xliff:g> από τώρα έως <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Πλήρες χρονοδιάγραμμα"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Επόμενες %1$d ημέρες</item>
+ <item quantity="one">Επόμενη %1$d ημέρα</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d λεπτά</item>
+ <item quantity="one">%1$d λεπτό</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d νέες εγγραφές</item>
+ <item quantity="one">%1$d νέα εγγραφή</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d εγγραφές</item>
+ <item quantity="one">%1$d εγγραφή</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d προγραμματ. εγγραφές</item>
+ <item quantity="one">%1$d προγραμματ. εγγραφή</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Παρακολούθηση"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Αναπαραγωγή από την αρχή"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Συνέχ. αναπαραγωγής"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Διαγραφή"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Διαγραφή εγγραφών"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Συνέχιση"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Σεζόν <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Προβ. προγραμμ."</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Διαβάστε περισσότερα"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Διαγραφή εγγραφών"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Επιλέξτε τα επεισόδια που θέλετε να διαγράψετε. Δεν είναι δυνατή η ανάκτησή τους μετά τη διαγραφή."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Δεν υπάρχουν εγγραφές για διαγραφή."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Επιλέξτε επεισόδια που παρακ."</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Επιλογή όλων των επεισοδίων"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Αποεπιλογή όλων των επεισοδίων"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Παρακολούθηση <xliff:g id="WATCHED">%1$d</xliff:g> λεπτών από <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Παρακολούθηση <xliff:g id="WATCHED">%1$d</xliff:g> δευτερολέπτων από <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Δεν έγινε παρακολούθηση"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">Διαγράφηκαν %1$d επεισόδια από %2$d</item>
+ <item quantity="one">Διαγράφηκε %1$d επεισόδιο από %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Προτεραιότητα"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Υψηλότερη"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Χαμηλότερη"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Όχι. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Κανάλια"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Οποιοδήποτε"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Επιλέξτε προτεραιότητα"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Όταν υπάρχουν πολλά προγράμματα για εγγραφή την ίδια ώρα, θα γίνει εγγραφή μόνο των προγραμμάτων με τις υψηλότερες προτεραιότητες."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Αποθήκευση"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Οι εγγραφές μίας φοράς έχουν την υψηλότερη προτεραιότητα"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Ακύρωση"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Ακύρωση"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Διαγραφή"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Διακοπή"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Προβολή προγραμματισ. εγγραφών"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Αυτό το συγκεκριμένο επεισόδιο"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"τώρα - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Ολόκληρη τη σειρά…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Να προγραμματιστεί ούτως ή άλλως"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Αντί αυτού, εγγρ. αυτού του πρ."</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Ακύρωση αυτής της εγγραφής"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Προβολή τώρα"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Με δυνατότητα εγγραφής"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Η εγγραφή προγραμματίστηκε"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Διένεξη εγγραφής"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Εγγραφή"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Αποτυχία εγγραφής"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Γίνεται ανάγνωση προγραμμάτων για δημιουργία προγραμματισμών εγγραφής"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Ανάγνωση προγραμμάτων"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Το DVR χρειάζεται περισσότερο αποθηκευτικό χώρο"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Θα μπορείτε να εγγράψετε προγράμματα με το DVR. Ωστόσο, αυτήν τη στιγμή δεν υπάρχει αρκετός αποθηκευτικός χώρος στη συσκευή σας έτσι ώστε να λειτουργήσει το DVR. Συνδέστε έναν εξωτερικό δίσκο με χωρητικότητα <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB ή μεγαλύτερη και ακολουθήστε τα βήματα για να τον μορφοποιήσετε και να τον ορίσετε ως αποθηκευτικό χώρο της συσκευής."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Ο αποθηκευτικός χώρος λείπει"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Κάποιο τμήμα του αποθηκευτικού χώρου που χρησιμοποιείται από το DVR λείπει. Συνδέστε τον εξωτερικό δίσκο που χρησιμοποιήσατε στο παρελθόν για να ενεργοποιήσετε εκ νέου το DVR. Εναλλακτικά, μπορείτε να επιλέξετε να διαγράψετε τον αποθηκευτικό χώρο αν δεν είναι πλέον διαθέσιμος."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Να διαγραφεί ο αποθηκευτικός χώρος;"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Όλο το εγγεγραμμένο περιεχόμενο και τα χρονοδιαγράμματα θα χαθούν."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Να διακοπεί η εγγραφή;"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Θα γίνει αποθήκευση του περιεχομένου που έχει εγγραφεί."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Η εγγραφή προγραμματίστηκε, αλλά έχει διενέξεις"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Η εγγραφή ξεκίνησε αλλά υπάρχουν διενέξεις"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Θα γίνει εγγραφή του προγράμματος <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Πραγματοποιείται εγγραφή του καναλιού <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Δεν θα γίνει εγγραφή ορισμένων αποσπασμάτων του προγράμματος <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Δεν θα γίνει εγγραφή ορισμένων αποσπασμάτων των προγραμμάτων <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> και <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Δεν θα γίνει εγγραφή ορισμένων αποσπασμάτων των προγραμμάτων <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> και ενός ακόμη προγράμματος."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Δεν θα γίνει εγγραφή ορισμένων αποσπασμάτων των προγραμμάτων <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> και <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> και %3$d ακόμη χρονοδιαγραμμάτων.</item>
+ <item quantity="one">Δεν θα γίνει εγγραφή ορισμένων αποσπασμάτων των προγραμμάτων <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g> και <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> και %3$d ακόμη χρονοδιαγράμματος.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Τι θέλετε να κάνετε εγγραφή;"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Πόση ώρα επιθυμείτε να κρατήσει η εγγραφή;"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Έχει ήδη προγραμματιστεί"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Το ίδιο πρόγραμμα έχει προγραμματιστεί για εγγραφή στις <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Έχει ήδη εγγραφεί"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Αυτό το πρόγραμμα έχει ήδη εγγραφεί. Είναι διαθέσιμο στη βιβλιοθήκη DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Το εγγεγραμμένο πρόγραμμα δεν βρέθηκε."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Σχετικές εγγραφές"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Καμία περιγραφή προγράμματος)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d εγγραφές</item>
+ <item quantity="one">%1$d εγγραφή</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Το πρόγραμμα <xliff:g id="PROGRAMNAME">%1$s</xliff:g> καταργήθηκε από τις προγραμματισμένες εγγραφές"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Θα γίνει μερική εγγραφή λόγω διενέξεων δέκτη."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Δεν θα γίνει εγγραφή λόγω διενέξεων δέκτη."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Προς το παρόν, δεν υπάρχουν προγραμματισμένες εγγραφές.\nΜπορείτε να προγραμματίσετε εγγραφές από τον οδηγό προγράμματος."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d διενέξεις εγγραφής</item>
+ <item quantity="one">%1$d διένεξη εγγραφής</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Ρυθμίσεις σειράς"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Έναρξη εγγραφής σειράς"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Διακοπή εγγραφής σειράς"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Διακοπή εγγραφής σειράς;"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Τα επεισόδια που έχουν εγγραφεί θα εξακολουθήσουν να είναι διαθέσιμα στη βιβλιοθήκη DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Διακοπή"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Δεν υπάρχουν διαθέσιμα επεισόδια.\nΗ εγγραφή τους θα πραγματοποιηθεί όταν θα είναι διαθέσιμα."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d λεπτά)</item>
+ <item quantity="one">(%1$d λεπτό) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Σήμερα"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Αύριο"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Χθες"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> σήμερα"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> αύριο"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Μουσική επένδυση"</string>
</resources>
diff --git a/res/values-en-rAU/arrays.xml b/res/values-en-rAU/arrays.xml
index 3c2ac8c6..082a7de4 100644
--- a/res/values-en-rAU/arrays.xml
+++ b/res/values-en-rAU/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Full"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"All channels"</item>
- <item msgid="6897460857821394118">"Family/Children\'s"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Comedy"</item>
- <item msgid="7900158429062595471">"Travel"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Education"</item>
- <item msgid="7396447839483867269">"Animal/Wildlife"</item>
- <item msgid="4738043455148062673">"News"</item>
- <item msgid="7405041316051047427">"Gaming"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"All channels"</item>
- <item msgid="7909003973960375395">"Family/Children\'s"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Comedy"</item>
- <item msgid="3803709976021475052">"Travel"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Education"</item>
- <item msgid="7511135485827589547">"Animal/Wildlife"</item>
- <item msgid="6961248112238009967">"News"</item>
- <item msgid="6484685553679698447">"Gaming"</item>
- <item msgid="2737158328243183190">"Arts"</item>
- <item msgid="6577176952650166615">"Entertainment"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Music"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Tech/Science"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"All channels"</item>
+ <item msgid="928298872841713530">"Family/Kids"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Comedy"</item>
+ <item msgid="6096710741527327836">"Travel"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Education"</item>
+ <item msgid="7221999662426308394">"Animal/Wildlife"</item>
+ <item msgid="375300513250925001">"News"</item>
+ <item msgid="7746320336582330410">"Gaming"</item>
+ <item msgid="1255741860568329178">"Arts"</item>
+ <item msgid="7603949681065702867">"Entertainment"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Music"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Tech/Science"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live TV"</item>
diff --git a/res/values-en-rAU/rating_system_strings.xml b/res/values-en-rAU/rating_system_strings.xml
index 1eece436..f19fa02f 100644
--- a/res/values-en-rAU/rating_system_strings.xml
+++ b/res/values-en-rAU/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 987b4505..bda4e1ea 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Previous"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programme guide"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"New channels available"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"No link available"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Closed captions"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Display mode"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sub-ratings"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Enter your PIN to watch this channel"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Enter your PIN to watch this programme"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>. Enter your PIN to watch this programme"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Enter your PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"To set parental controls, create a PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Enter new PIN"</string>
@@ -141,11 +141,9 @@
<string name="settings_channel_source_item_setup" msgid="4566190088656419070">"Channel sources"</string>
<string name="settings_channel_source_item_setup_new_inputs" msgid="4845822152617430787">"New channels available"</string>
<string name="settings_parental_controls" msgid="5449397921700749317">"Parental controls"</string>
- <string name="settings_menu_licenses" msgid="1257646083838406103">"Open source licences"</string>
- <string name="dialog_title_licenses" msgid="4471754920475076623">"Open source licences"</string>
+ <string name="settings_menu_licenses" msgid="1257646083838406103">"Open-source licences"</string>
+ <string name="dialog_title_licenses" msgid="4471754920475076623">"Open-source licences"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Help improve Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Share anonymous usage and diagnostics data with Google so we can make Live TV better and prevent issues such as crashing and freezing."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"To watch this channel, press Right and enter your PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"To watch this program, press Right and enter your PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>.\nTo watch this programme, press Right and enter your PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio only"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Weak signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"No Internet connection"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">This channel can\'t be played until <xliff:g id="END_TIME_1">%1$s</xliff:g>, because other channels are being recorded. \n\nPress Right to adjust recording schedule.</item>
+ <item quantity="one">This channel can\'t be played until <xliff:g id="END_TIME_0">%1$s</xliff:g>, because another channel is being recorded. \n\nPress Right to adjust recording schedule.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"No title"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Channel blocked"</string>
<string name="setup_category_new" msgid="2899355289563443627">"N"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No channels available"</string>
<string name="setup_input_new" msgid="3337725672277046798">"New"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Not set up"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Get more sources"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Browse apps that offer live channels"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Get more sources"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Browse apps that offer live channels"</string>
<string name="new_sources_title" msgid="3878933676500061895">"New channel sources available"</string>
<string name="new_sources_description" msgid="749649005588426813">"New channel sources have channels to offer.\nSet them up now, or do this later in the channel sources setting."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Set up now"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"All source channels are hidden.\nSelect at least one channel to watch."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"The video is unexpectedly unavailable"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK key is for connected device. Press HOME button to exit."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV is not supported on this device with Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV needs permission to read the TV listings."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Set up your sources"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"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 Google Play Store for more apps that offer live channels."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Recordings &amp; schedules"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hour"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hours"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recent"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Scheduled"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Series"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Others"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"The channel cannot be recorded."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"The programme cannot be recorded."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> has been scheduled to be recorded"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Recording <xliff:g id="PROGRAMNAME">%1$s</xliff:g> from now to <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Full schedule"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Next %1$d days</item>
+ <item quantity="one">Next %1$d day</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutes</item>
+ <item quantity="one">%1$d minute</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d new recordings</item>
+ <item quantity="one">%1$d new recording</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d recordings scheduled</item>
+ <item quantity="one">%1$d recording scheduled</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Watch"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Play from beginning"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Resume playing"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Delete"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Delete recordings"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"CV"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Series <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"View schedule"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Read more"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Delete recordings"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Select the episodes that you would like to delete. They can\'t be recovered once deleted."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"There are no recordings to delete."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Select watched episodes"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Select all episodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Deselect all episodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> minutes watched"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> seconds watched"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Never watched"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d of %2$d episodes are deleted</item>
+ <item quantity="one">%1$d of %2$d episode is deleted</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priority"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Highest"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lowest"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"No. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Channels"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Any"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Choose priority"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"When there are too many programmes to be recorded at the same time, only the ones with higher priorities will be recorded."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Save"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"One-time recordings have the highest priority"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancel"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancel"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Forget"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stop"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"View recording schedule"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"This single programme"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"now – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Entire series…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Schedule anyway"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Record this one instead"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancel this recording"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Watch now"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Recordable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Recording scheduled"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Recording conflict"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Recording"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Recording failed"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Reading programs to create recording schedules"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Reading programmes"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR needs more storage"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"You will be able to record programmes with DVR. At the moment there is not enough storage on your device for DVR to work. Please connect an external drive that is <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB or larger and follow the steps to format it as device storage."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Missing storage"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Some of the storage used by DVR is missing. Please connect the external drive that you used before to re-enable DVR. Alternatively, you can choose to forget the storage if it\'s no longer available."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Forget storage?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"All your recorded content and schedules will be lost."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Stop recording?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"The recorded content will be saved."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Recording scheduled but has conflicts"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Recording has started but has conflicts"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> will be recorded."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> is being recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> and <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> and one more schedule will not be recorded."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> and %3$d more schedules will not be recorded.</item>
+ <item quantity="one">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> and %3$d more schedule will not be recorded.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"What would you like to record?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"How long would you like to record?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Already scheduled"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"The same programme has already been scheduled to be recorded at <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Already recorded"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"This programme has already been recorded. It’s available in the DVR library."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Recorded programme not found."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Related recordings"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(No programme description)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> removed from recording schedule"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Will be partially recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Won\'t be recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"There are no recordings on schedule yet.\nYou can schedule recording from the programme guide."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d recording conflicts</item>
+ <item quantity="one">%1$d recording conflict</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Series settings"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Start series recording"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stop series recording"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Stop series recording?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Recorded episodes will remain available in the DVR library."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stop"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No episodes are available.\nThey will be recorded once they are available."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutes)</item>
+ <item quantity="one">(%1$d minute) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Today"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Tomorrow"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Yesterday"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> today"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> tomorrow"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Score"</string>
</resources>
diff --git a/res/values-en-rGB/arrays.xml b/res/values-en-rGB/arrays.xml
index 3c2ac8c6..082a7de4 100644
--- a/res/values-en-rGB/arrays.xml
+++ b/res/values-en-rGB/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Full"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"All channels"</item>
- <item msgid="6897460857821394118">"Family/Children\'s"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Comedy"</item>
- <item msgid="7900158429062595471">"Travel"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Education"</item>
- <item msgid="7396447839483867269">"Animal/Wildlife"</item>
- <item msgid="4738043455148062673">"News"</item>
- <item msgid="7405041316051047427">"Gaming"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"All channels"</item>
- <item msgid="7909003973960375395">"Family/Children\'s"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Comedy"</item>
- <item msgid="3803709976021475052">"Travel"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Education"</item>
- <item msgid="7511135485827589547">"Animal/Wildlife"</item>
- <item msgid="6961248112238009967">"News"</item>
- <item msgid="6484685553679698447">"Gaming"</item>
- <item msgid="2737158328243183190">"Arts"</item>
- <item msgid="6577176952650166615">"Entertainment"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Music"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Tech/Science"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"All channels"</item>
+ <item msgid="928298872841713530">"Family/Kids"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Comedy"</item>
+ <item msgid="6096710741527327836">"Travel"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Education"</item>
+ <item msgid="7221999662426308394">"Animal/Wildlife"</item>
+ <item msgid="375300513250925001">"News"</item>
+ <item msgid="7746320336582330410">"Gaming"</item>
+ <item msgid="1255741860568329178">"Arts"</item>
+ <item msgid="7603949681065702867">"Entertainment"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Music"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Tech/Science"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live TV"</item>
diff --git a/res/values-en-rGB/rating_system_strings.xml b/res/values-en-rGB/rating_system_strings.xml
index 1eece436..f19fa02f 100644
--- a/res/values-en-rGB/rating_system_strings.xml
+++ b/res/values-en-rGB/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 987b4505..bda4e1ea 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Previous"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programme guide"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"New channels available"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"No link available"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Closed captions"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Display mode"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sub-ratings"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Enter your PIN to watch this channel"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Enter your PIN to watch this programme"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>. Enter your PIN to watch this programme"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Enter your PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"To set parental controls, create a PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Enter new PIN"</string>
@@ -141,11 +141,9 @@
<string name="settings_channel_source_item_setup" msgid="4566190088656419070">"Channel sources"</string>
<string name="settings_channel_source_item_setup_new_inputs" msgid="4845822152617430787">"New channels available"</string>
<string name="settings_parental_controls" msgid="5449397921700749317">"Parental controls"</string>
- <string name="settings_menu_licenses" msgid="1257646083838406103">"Open source licences"</string>
- <string name="dialog_title_licenses" msgid="4471754920475076623">"Open source licences"</string>
+ <string name="settings_menu_licenses" msgid="1257646083838406103">"Open-source licences"</string>
+ <string name="dialog_title_licenses" msgid="4471754920475076623">"Open-source licences"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Help improve Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Share anonymous usage and diagnostics data with Google so we can make Live TV better and prevent issues such as crashing and freezing."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"To watch this channel, press Right and enter your PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"To watch this program, press Right and enter your PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>.\nTo watch this programme, press Right and enter your PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio only"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Weak signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"No Internet connection"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">This channel can\'t be played until <xliff:g id="END_TIME_1">%1$s</xliff:g>, because other channels are being recorded. \n\nPress Right to adjust recording schedule.</item>
+ <item quantity="one">This channel can\'t be played until <xliff:g id="END_TIME_0">%1$s</xliff:g>, because another channel is being recorded. \n\nPress Right to adjust recording schedule.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"No title"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Channel blocked"</string>
<string name="setup_category_new" msgid="2899355289563443627">"N"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No channels available"</string>
<string name="setup_input_new" msgid="3337725672277046798">"New"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Not set up"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Get more sources"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Browse apps that offer live channels"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Get more sources"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Browse apps that offer live channels"</string>
<string name="new_sources_title" msgid="3878933676500061895">"New channel sources available"</string>
<string name="new_sources_description" msgid="749649005588426813">"New channel sources have channels to offer.\nSet them up now, or do this later in the channel sources setting."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Set up now"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"All source channels are hidden.\nSelect at least one channel to watch."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"The video is unexpectedly unavailable"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK key is for connected device. Press HOME button to exit."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV is not supported on this device with Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV needs permission to read the TV listings."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Set up your sources"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"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 Google Play Store for more apps that offer live channels."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Recordings &amp; schedules"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hour"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hours"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recent"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Scheduled"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Series"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Others"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"The channel cannot be recorded."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"The programme cannot be recorded."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> has been scheduled to be recorded"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Recording <xliff:g id="PROGRAMNAME">%1$s</xliff:g> from now to <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Full schedule"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Next %1$d days</item>
+ <item quantity="one">Next %1$d day</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutes</item>
+ <item quantity="one">%1$d minute</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d new recordings</item>
+ <item quantity="one">%1$d new recording</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d recordings scheduled</item>
+ <item quantity="one">%1$d recording scheduled</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Watch"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Play from beginning"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Resume playing"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Delete"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Delete recordings"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"CV"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Series <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"View schedule"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Read more"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Delete recordings"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Select the episodes that you would like to delete. They can\'t be recovered once deleted."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"There are no recordings to delete."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Select watched episodes"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Select all episodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Deselect all episodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> minutes watched"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> seconds watched"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Never watched"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d of %2$d episodes are deleted</item>
+ <item quantity="one">%1$d of %2$d episode is deleted</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priority"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Highest"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lowest"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"No. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Channels"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Any"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Choose priority"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"When there are too many programmes to be recorded at the same time, only the ones with higher priorities will be recorded."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Save"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"One-time recordings have the highest priority"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancel"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancel"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Forget"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stop"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"View recording schedule"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"This single programme"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"now – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Entire series…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Schedule anyway"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Record this one instead"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancel this recording"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Watch now"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Recordable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Recording scheduled"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Recording conflict"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Recording"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Recording failed"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Reading programs to create recording schedules"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Reading programmes"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR needs more storage"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"You will be able to record programmes with DVR. At the moment there is not enough storage on your device for DVR to work. Please connect an external drive that is <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB or larger and follow the steps to format it as device storage."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Missing storage"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Some of the storage used by DVR is missing. Please connect the external drive that you used before to re-enable DVR. Alternatively, you can choose to forget the storage if it\'s no longer available."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Forget storage?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"All your recorded content and schedules will be lost."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Stop recording?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"The recorded content will be saved."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Recording scheduled but has conflicts"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Recording has started but has conflicts"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> will be recorded."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> is being recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> and <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> and one more schedule will not be recorded."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> and %3$d more schedules will not be recorded.</item>
+ <item quantity="one">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> and %3$d more schedule will not be recorded.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"What would you like to record?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"How long would you like to record?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Already scheduled"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"The same programme has already been scheduled to be recorded at <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Already recorded"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"This programme has already been recorded. It’s available in the DVR library."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Recorded programme not found."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Related recordings"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(No programme description)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> removed from recording schedule"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Will be partially recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Won\'t be recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"There are no recordings on schedule yet.\nYou can schedule recording from the programme guide."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d recording conflicts</item>
+ <item quantity="one">%1$d recording conflict</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Series settings"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Start series recording"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stop series recording"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Stop series recording?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Recorded episodes will remain available in the DVR library."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stop"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No episodes are available.\nThey will be recorded once they are available."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutes)</item>
+ <item quantity="one">(%1$d minute) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Today"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Tomorrow"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Yesterday"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> today"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> tomorrow"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Score"</string>
</resources>
diff --git a/res/values-en-rIN/arrays.xml b/res/values-en-rIN/arrays.xml
index 3c2ac8c6..082a7de4 100644
--- a/res/values-en-rIN/arrays.xml
+++ b/res/values-en-rIN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Full"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"All channels"</item>
- <item msgid="6897460857821394118">"Family/Children\'s"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Comedy"</item>
- <item msgid="7900158429062595471">"Travel"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Education"</item>
- <item msgid="7396447839483867269">"Animal/Wildlife"</item>
- <item msgid="4738043455148062673">"News"</item>
- <item msgid="7405041316051047427">"Gaming"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"All channels"</item>
- <item msgid="7909003973960375395">"Family/Children\'s"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Comedy"</item>
- <item msgid="3803709976021475052">"Travel"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Education"</item>
- <item msgid="7511135485827589547">"Animal/Wildlife"</item>
- <item msgid="6961248112238009967">"News"</item>
- <item msgid="6484685553679698447">"Gaming"</item>
- <item msgid="2737158328243183190">"Arts"</item>
- <item msgid="6577176952650166615">"Entertainment"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Music"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Tech/Science"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"All channels"</item>
+ <item msgid="928298872841713530">"Family/Kids"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Comedy"</item>
+ <item msgid="6096710741527327836">"Travel"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Education"</item>
+ <item msgid="7221999662426308394">"Animal/Wildlife"</item>
+ <item msgid="375300513250925001">"News"</item>
+ <item msgid="7746320336582330410">"Gaming"</item>
+ <item msgid="1255741860568329178">"Arts"</item>
+ <item msgid="7603949681065702867">"Entertainment"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Music"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Tech/Science"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live TV"</item>
diff --git a/res/values-en-rIN/rating_system_strings.xml b/res/values-en-rIN/rating_system_strings.xml
index 1eece436..f19fa02f 100644
--- a/res/values-en-rIN/rating_system_strings.xml
+++ b/res/values-en-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 987b4505..bda4e1ea 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Previous"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programme guide"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"New channels available"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"No link available"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Closed captions"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Display mode"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sub-ratings"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Enter your PIN to watch this channel"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Enter your PIN to watch this programme"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>. Enter your PIN to watch this programme"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Enter your PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"To set parental controls, create a PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Enter new PIN"</string>
@@ -141,11 +141,9 @@
<string name="settings_channel_source_item_setup" msgid="4566190088656419070">"Channel sources"</string>
<string name="settings_channel_source_item_setup_new_inputs" msgid="4845822152617430787">"New channels available"</string>
<string name="settings_parental_controls" msgid="5449397921700749317">"Parental controls"</string>
- <string name="settings_menu_licenses" msgid="1257646083838406103">"Open source licences"</string>
- <string name="dialog_title_licenses" msgid="4471754920475076623">"Open source licences"</string>
+ <string name="settings_menu_licenses" msgid="1257646083838406103">"Open-source licences"</string>
+ <string name="dialog_title_licenses" msgid="4471754920475076623">"Open-source licences"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Help improve Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Share anonymous usage and diagnostics data with Google so we can make Live TV better and prevent issues such as crashing and freezing."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"To watch this channel, press Right and enter your PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"To watch this program, press Right and enter your PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"This programme is rated <xliff:g id="RATING">%1$s</xliff:g>.\nTo watch this programme, press Right and enter your PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio only"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Weak signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"No Internet connection"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">This channel can\'t be played until <xliff:g id="END_TIME_1">%1$s</xliff:g>, because other channels are being recorded. \n\nPress Right to adjust recording schedule.</item>
+ <item quantity="one">This channel can\'t be played until <xliff:g id="END_TIME_0">%1$s</xliff:g>, because another channel is being recorded. \n\nPress Right to adjust recording schedule.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"No title"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Channel blocked"</string>
<string name="setup_category_new" msgid="2899355289563443627">"N"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No channels available"</string>
<string name="setup_input_new" msgid="3337725672277046798">"New"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Not set up"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Get more sources"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Browse apps that offer live channels"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Get more sources"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Browse apps that offer live channels"</string>
<string name="new_sources_title" msgid="3878933676500061895">"New channel sources available"</string>
<string name="new_sources_description" msgid="749649005588426813">"New channel sources have channels to offer.\nSet them up now, or do this later in the channel sources setting."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Set up now"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"All source channels are hidden.\nSelect at least one channel to watch."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"The video is unexpectedly unavailable"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK key is for connected device. Press HOME button to exit."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV is not supported on this device with Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV needs permission to read the TV listings."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Set up your sources"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"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 Google Play Store for more apps that offer live channels."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Recordings &amp; schedules"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hour"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hours"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recent"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Scheduled"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Series"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Others"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"The channel cannot be recorded."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"The programme cannot be recorded."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> has been scheduled to be recorded"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Recording <xliff:g id="PROGRAMNAME">%1$s</xliff:g> from now to <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Full schedule"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Next %1$d days</item>
+ <item quantity="one">Next %1$d day</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutes</item>
+ <item quantity="one">%1$d minute</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d new recordings</item>
+ <item quantity="one">%1$d new recording</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d recordings scheduled</item>
+ <item quantity="one">%1$d recording scheduled</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Watch"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Play from beginning"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Resume playing"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Delete"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Delete recordings"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"CV"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Series <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"View schedule"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Read more"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Delete recordings"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Select the episodes that you would like to delete. They can\'t be recovered once deleted."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"There are no recordings to delete."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Select watched episodes"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Select all episodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Deselect all episodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> minutes watched"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> of <xliff:g id="DURATION">%2$d</xliff:g> seconds watched"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Never watched"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d of %2$d episodes are deleted</item>
+ <item quantity="one">%1$d of %2$d episode is deleted</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priority"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Highest"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lowest"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"No. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Channels"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Any"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Choose priority"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"When there are too many programmes to be recorded at the same time, only the ones with higher priorities will be recorded."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Save"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"One-time recordings have the highest priority"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancel"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancel"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Forget"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stop"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"View recording schedule"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"This single programme"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"now – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Entire series…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Schedule anyway"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Record this one instead"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancel this recording"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Watch now"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Recordable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Recording scheduled"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Recording conflict"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Recording"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Recording failed"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Reading programs to create recording schedules"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Reading programmes"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR needs more storage"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"You will be able to record programmes with DVR. At the moment there is not enough storage on your device for DVR to work. Please connect an external drive that is <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB or larger and follow the steps to format it as device storage."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Missing storage"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Some of the storage used by DVR is missing. Please connect the external drive that you used before to re-enable DVR. Alternatively, you can choose to forget the storage if it\'s no longer available."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Forget storage?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"All your recorded content and schedules will be lost."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Stop recording?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"The recorded content will be saved."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Recording scheduled but has conflicts"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Recording has started but has conflicts"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> will be recorded."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> is being recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> and <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> will not be recorded."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> and one more schedule will not be recorded."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> and %3$d more schedules will not be recorded.</item>
+ <item quantity="one">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> and %3$d more schedule will not be recorded.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"What would you like to record?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"How long would you like to record?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Already scheduled"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"The same programme has already been scheduled to be recorded at <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Already recorded"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"This programme has already been recorded. It’s available in the DVR library."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Recorded programme not found."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Related recordings"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(No programme description)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d recordings</item>
+ <item quantity="one">%1$d recording</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> removed from recording schedule"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Will be partially recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Won\'t be recorded due to tuner conflicts."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"There are no recordings on schedule yet.\nYou can schedule recording from the programme guide."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d recording conflicts</item>
+ <item quantity="one">%1$d recording conflict</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Series settings"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Start series recording"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stop series recording"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Stop series recording?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Recorded episodes will remain available in the DVR library."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stop"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No episodes are available.\nThey will be recorded once they are available."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutes)</item>
+ <item quantity="one">(%1$d minute) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Today"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Tomorrow"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Yesterday"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> today"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> tomorrow"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Score"</string>
</resources>
diff --git a/res/values-es-rUS/arrays.xml b/res/values-es-rUS/arrays.xml
index 522e6352..de5b7910 100644
--- a/res/values-es-rUS/arrays.xml
+++ b/res/values-es-rUS/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Completa"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Todos los canales"</item>
- <item msgid="6897460857821394118">"Infantil y familiar"</item>
- <item msgid="551257741825778215">"Deportes"</item>
- <item msgid="452133796804325879">"Compras"</item>
- <item msgid="3296058637230163031">"Películas"</item>
- <item msgid="1054540282883891201">"Comedia"</item>
- <item msgid="7900158429062595471">"Viajes"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Educación"</item>
- <item msgid="7396447839483867269">"Vida salvaje"</item>
- <item msgid="4738043455148062673">"Noticias"</item>
- <item msgid="7405041316051047427">"Videojuegos"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Todos los canales"</item>
- <item msgid="7909003973960375395">"Infantil y familiar"</item>
- <item msgid="3185279732911635789">"Deportes"</item>
- <item msgid="4704858492065325964">"Compras"</item>
- <item msgid="6083795019290250078">"Películas"</item>
- <item msgid="8302638329222449550">"Comedia"</item>
- <item msgid="3803709976021475052">"Viajes"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Educación"</item>
- <item msgid="7511135485827589547">"Vida salvaje"</item>
- <item msgid="6961248112238009967">"Noticias"</item>
- <item msgid="6484685553679698447">"Videojuegos"</item>
- <item msgid="2737158328243183190">"Arte"</item>
- <item msgid="6577176952650166615">"Entretenimiento"</item>
- <item msgid="7886693831871777617">"Estilo de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"Estrenos"</item>
- <item msgid="2736680312770771994">"Ciencia y tecnología"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Todos los canales"</item>
+ <item msgid="928298872841713530">"Familiar/Infantil"</item>
+ <item msgid="2751606947569857164">"Deportes"</item>
+ <item msgid="7345749789651321496">"Compras"</item>
+ <item msgid="167201149441442173">"Películas"</item>
+ <item msgid="525966731464264290">"Comedia"</item>
+ <item msgid="6096710741527327836">"Viajes"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educación"</item>
+ <item msgid="7221999662426308394">"Animal/Vida salvaje"</item>
+ <item msgid="375300513250925001">"Noticias"</item>
+ <item msgid="7746320336582330410">"Juegos"</item>
+ <item msgid="1255741860568329178">"Arte"</item>
+ <item msgid="7603949681065702867">"Entretenimiento"</item>
+ <item msgid="4453821994746804366">"Estilo de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"Estrenos"</item>
+ <item msgid="8215762047341133299">"Ciencia y tecnología"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canales en vivo"</item>
diff --git a/res/values-es-rUS/rating_system_strings.xml b/res/values-es-rUS/rating_system_strings.xml
index 8beadacf..97db3a72 100644
--- a/res/values-es-rUS/rating_system_strings.xml
+++ b/res/values-es-rUS/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 1a52b29e..14e9f506 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guía de programas"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nuevos canales disp."</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Sin vínculo disponible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtítulos"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Modo pantalla"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subclasificaciones"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Ingresa tu PIN para ver este canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Ingresa tu PIN para ver este programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Este programa está clasificado como <xliff:g id="RATING">%1$s</xliff:g>. Ingresa tu PIN para mirarlo."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Ingresa tu PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Para configurar controles parentales, debes crear un PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Ingresar nuevo PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licencias de código abierto"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licencias de código abierto"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versión"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Ayudar a mejorar Canales en vivo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Comparte datos anónimos acerca del uso y el diagnóstico con Google para que podamos mejorar Canales en vivo y evitar problemas como el bloqueo o el congelamiento de la imagen."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Para mirar este canal, presiona la tecla hacia la derecha e ingresa el PIN."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Para mirar este programa, presiona la tecla hacia la derecha e ingresa el PIN."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Este programa se calificó como <xliff:g id="RATING">%1$s</xliff:g>.\nPara mirarlo, presiona la tecla hacia la derecha e ingresa el PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Solo audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Señal débil"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Sin conexión a Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Este canal no puede reproducirse hasta las <xliff:g id="END_TIME_1">%1$s</xliff:g> porque se están grabando otros canales. \n\nPresiona el botón derecho para ajustar el cronograma de grabación.</item>
+ <item quantity="one">Este canal no puede reproducirse hasta las <xliff:g id="END_TIME_0">%1$s</xliff:g> porque se está grabando otro canal. \n\nPresiona el botón derecho para ajustar el cronograma de grabación.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sin título"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal bloqueado"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nuevas"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No hay canales disponibles."</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nueva"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Sin configurar"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Obtener más fuentes"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Explorar apps que ofrecen Canales en vivo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Obtener más fuentes"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Explorar apps que ofrecen Canales en vivo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nuevas fuentes de canales disponibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Nuevas fuentes de canales con canales disponibles.\nPuedes configurarlas ahora o más tarde en la configuración de fuentes de canales."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurar ahora"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Todos los canales de salida están ocultos.\nSelecciona al menos un canal para mirar."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"El video no está disponible por motivos inesperados."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"La tecla ATRÁS es para el dispositivo conectado. Presiona el botón INICIO para salir."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"\"Canales en vivo\" no es compatible con este dispositivo con Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"\"Canales en vivo\" necesita permiso para leer las listas de canales de televisión."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configura tus fuentes"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Canales en vivo combina la experiencia de los canales de TV tradicionales con la transmisión de canales que ofrecen las apps.\n\nPara comenzar, configura las fuentes de canales que ya están instaladas o explora Google Play Store para obtener más apps que ofrecen canales en vivo."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Grabaciones y cronograma"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutos"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutos"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 horas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recientes"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programada"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Otros"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"No se puede grabar el canal."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"No se puede grabar el programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Se programó la grabación de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Grabando <xliff:g id="PROGRAMNAME">%1$s</xliff:g> desde ahora hasta las <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Cronograma completo"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d días más</item>
+ <item quantity="one">%1$d día más</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutos</item>
+ <item quantity="one">%1$d minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d grabaciones nuevas</item>
+ <item quantity="one">%1$d grabación nueva</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d grabaciones</item>
+ <item quantity="one">%1$d grabación</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d grabaciones programadas</item>
+ <item quantity="one">%1$d grabación programada</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Mirar"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproducir desde comienzo"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reanudar reproducción"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Borrar"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Borrar grabaciones"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reanudar"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ver programación"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Leer más"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Borra grabaciones"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecciona los episodios que quieres borrar. Una vez que los borres, no podrás recuperarlos."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"No hay ninguna grabación para borrar."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Seleccionar episodios mirados"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Seleccionar los episodios"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Quitar selección de episodios"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Miraste <xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> minutos"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Miraste <xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> segundos"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Grabaciones sin mirar"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">Se borraron %1$d episodios de %2$d</item>
+ <item quantity="one">Se borró %1$d episodio de %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioridad"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Máxima"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Muy baja"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"N.º <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canales"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Cualquiera"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Selecciona la prioridad"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Cuando hay demasiados programas para grabar al mismo tiempo, solo se grabarán los que tengan mayor prioridad."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Guardar"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Las grabaciones únicas tienen mayor prioridad"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancelar"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancelar"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Borrar"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Detener"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ver cronograma de grabación"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Solo este programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ahora - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Serie completa…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programar de todos modos"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Grabar este programa en su lugar"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancelar esta grabación"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Mirar ahora"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Se puede grabar"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Grabación programada"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Error de grabación"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Grabando"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Se produjo un error al grabar"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Leyendo programas para crear programaciones de grabación"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Leyendo programas"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"El DVR necesita más espacio de almacenamiento"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Si bien puedes grabar programas con el DVR, no hay espacio de almacenamiento suficiente en tu dispositivo para usar esta opción. Conecta una unidad externa de <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB como mínimo y sigue los pasos para formatearla como almacenamiento del dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Falta almacenamiento"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Falta parte del almacenamiento que se usa para DVR. Conecta la unidad externa que usaste anteriormente para volver a habilitar esta función. También puedes borrar el almacenamiento si ya no está disponible."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"¿Borrar almacenamiento?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Se perderán todas las programaciones y los contenidos grabados."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"¿Deseas detener la grabación?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Se guardará el contenido grabado."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Grabación programada con conflictos"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Comenzó la grabación, pero tiene problemas"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Se grabará <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Se está grabando <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"No se grabarán algunas partes de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"No se grabarán algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> y <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"No se grabarán algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> y una programación más."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">No se grabarán algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> y %3$d programaciones más.</item>
+ <item quantity="one">No se grabarán algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> y %3$d programación más.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"¿Qué contenido quieres grabar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"¿Cuánto tiempo deseas grabar?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Ya está programado"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"El mismo programa se grabará a las <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Programa grabado"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Este programa ya está grabado. Está disponible en la biblioteca de DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"No se encontró el programa grabado."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Grabaciones relacionadas"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Sin descripción del programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d grabaciones</item>
+ <item quantity="one">%1$d grabación</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Se quitó <xliff:g id="PROGRAMNAME">%1$s</xliff:g> del cronograma de grabación"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Se grabará parcialmente debido a problemas del sintonizador."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"No se grabará debido a problemas con el sintonizador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aún no hay grabaciones programadas.\nPuedes programar grabaciones en la guía de programas."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d problemas de grabación</item>
+ <item quantity="one">%1$d problema de grabación</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Configuración de la serie"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Iniciar grabación"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Detener grabación"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"¿Detener grabación de la serie?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Los episodios grabados estarán disponibles en la biblioteca de DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Detener"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No hay episodios disponibles.\nSe grabarán cuando lo estén."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutos)</item>
+ <item quantity="one">(%1$d minuto) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hoy"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Mañana"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ayer"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Hoy: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Mañana: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puntuación"</string>
</resources>
diff --git a/res/values-es/arrays.xml b/res/values-es/arrays.xml
index 3bc164ca..20d54571 100644
--- a/res/values-es/arrays.xml
+++ b/res/values-es/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Completa"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Todos los canales"</item>
- <item msgid="6897460857821394118">"Familiar/Infantil"</item>
- <item msgid="551257741825778215">"Deportes"</item>
- <item msgid="452133796804325879">"Compras"</item>
- <item msgid="3296058637230163031">"Películas"</item>
- <item msgid="1054540282883891201">"Comedia"</item>
- <item msgid="7900158429062595471">"Viajes"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Formación"</item>
- <item msgid="7396447839483867269">"Animales/Vida salvaje"</item>
- <item msgid="4738043455148062673">"Noticias"</item>
- <item msgid="7405041316051047427">"Juegos"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Todos los canales"</item>
- <item msgid="7909003973960375395">"Familiar/Infantil"</item>
- <item msgid="3185279732911635789">"Deportes"</item>
- <item msgid="4704858492065325964">"Compras"</item>
- <item msgid="6083795019290250078">"Películas"</item>
- <item msgid="8302638329222449550">"Comedia"</item>
- <item msgid="3803709976021475052">"Viajes"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Formación"</item>
- <item msgid="7511135485827589547">"Animales/Vida salvaje"</item>
- <item msgid="6961248112238009967">"Noticias"</item>
- <item msgid="6484685553679698447">"Juegos"</item>
- <item msgid="2737158328243183190">"Arte"</item>
- <item msgid="6577176952650166615">"Entretenimiento"</item>
- <item msgid="7886693831871777617">"Estilo de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"De primera línea"</item>
- <item msgid="2736680312770771994">"Ciencia y tecnología"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Todos los canales"</item>
+ <item msgid="928298872841713530">"Familiar/Infantil"</item>
+ <item msgid="2751606947569857164">"Deportes"</item>
+ <item msgid="7345749789651321496">"Compras"</item>
+ <item msgid="167201149441442173">"Películas"</item>
+ <item msgid="525966731464264290">"Comedia"</item>
+ <item msgid="6096710741527327836">"Viajes"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educación"</item>
+ <item msgid="7221999662426308394">"Animales/Vida salvaje"</item>
+ <item msgid="375300513250925001">"Noticias"</item>
+ <item msgid="7746320336582330410">"Juegos"</item>
+ <item msgid="1255741860568329178">"Arte"</item>
+ <item msgid="7603949681065702867">"Ocio"</item>
+ <item msgid="4453821994746804366">"Estilo de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"De primera línea"</item>
+ <item msgid="8215762047341133299">"Ciencia y tecnología"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"TV en directo"</item>
diff --git a/res/values-es/rating_system_strings.xml b/res/values-es/rating_system_strings.xml
index 974146b0..725eeeb7 100644
--- a/res/values-es/rating_system_strings.xml
+++ b/res/values-es/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 29e62228..badab6a4 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guía de programas"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nuevos canales disponibles"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ningún enlace disponible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtítulos"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Modo de pantalla"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subclasificaciones"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Introduce el PIN para ver este canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Introduce el PIN para ver este programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Este programa está clasificado como <xliff:g id="RATING">%1$s</xliff:g>. Introduce el PIN para verlo"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Introduce el número PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Para establecer controles parentales, debes crear un PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Introduce el nuevo PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licencias de software libre"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licencias software libre"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versión"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Ayudar a mejorar Canales en directo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Comparte datos de uso y de diagnóstico anónimos con Google para mejorar TV en directo y evitar bloqueos y fallos."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Para ver este canal, pulsa la tecla hacia la derecha e introduce el número PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Para ver este programa, pulsa la tecla hacia la derecha e introduce el número PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Este programa se ha clasificado como <xliff:g id="RATING">%1$s</xliff:g>.\nPara verlo, pulsa la tecla hacia la derecha e introduce el número PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Solo audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Señal débil"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Sin conexión a Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Este canal no se puede reproducir hasta <xliff:g id="END_TIME_1">%1$s</xliff:g> porque se están grabando otros canales. \n\nPulsa la flecha hacia la derecha para modificar la programación de grabaciones.</item>
+ <item quantity="one">Este canal no se puede reproducir hasta <xliff:g id="END_TIME_0">%1$s</xliff:g> porque se está grabando otro canal. \n\nPulsa la flecha hacia la derecha para modificar la programación de grabaciones.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sin título"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal bloqueado"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nuevas"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"No hay canales disponibles"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nuevas"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Sin configurar"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Obtener más fuentes"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Explorar aplicaciones que ofrecen TV en directo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Obtener más fuentes"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Explorar aplicaciones que ofrecen TV en directo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nuevas fuentes de canales disponibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Hay canales disponibles en las nuevas fuentes de canales.\nPuedes configurarlos ahora o más tarde en los ajustes correspondientes."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurar ahora"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Todos los canales de origen están ocultos.\nSelecciona al menos un canal para verlo."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"El vídeo no está disponible por motivos desconocidos"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"La tecla VOLVER es para dispositivos conectados. Pulsa el botón de inicio para salir."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Canales en directo no se admite en este dispositivo con Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Canales en directo necesita permiso para consultar las programaciones de TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configura las fuentes de canales"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"TV en directo combina la experiencia de los canales de TV tradicionales con los canales de reproducción en streaming que proporcionan las aplicaciones. \n\nPara empezar, configura las fuentes de canales que ya están instaladas. También puedes buscar más aplicaciones que ofrezcan TV en directo en Google Play Store."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Grabaciones y programaciones"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutos"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutos"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 horas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recientes"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programadas"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Otros"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"No se puede grabar el canal."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"No se puede grabar el programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Se ha programado la grabación de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Grabando <xliff:g id="PROGRAMNAME">%1$s</xliff:g> desde ahora hasta <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programación completa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Los %1$d días siguientes</item>
+ <item quantity="one">El día siguiente</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutos</item>
+ <item quantity="one">%1$d minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nuevas grabaciones</item>
+ <item quantity="one">%1$d nueva grabación</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d grabaciones</item>
+ <item quantity="one">%1$d grabación</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d grabaciones programadas</item>
+ <item quantity="one">%1$d grabación programada</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Ver"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproducir desde inicio"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reanudar reproducción"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Eliminar"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Eliminar grabaciones"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reanudar"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ver programación"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Más información"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Eliminar grabaciones"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecciona los episodios que quieras eliminar. Una vez eliminados, no se pueden recuperar."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"No hay grabaciones para eliminar."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Seleccionar episodios vistos"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Seleccionar todos los episodios"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Desmarcar todos los episodios"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Has visto <xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> minutos"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Has visto <xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> segundos"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Grabaciones no vistas"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">Se eliminan %1$d de %2$d episodios</item>
+ <item quantity="one">Se elimina %1$d de %2$d episodio</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioridad"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"La más alta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"La más baja"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"N.º <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canales"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Cualquiera"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Elegir prioridad"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Cuando haya demasiados programas que grabar al mismo tiempo, solo se grabarán aquellos con mayor prioridad."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Guardar"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Las grabaciones únicas son las que tienen mayor prioridad"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancelar"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancelar"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Olvidar"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Detener"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ver programación de grabación"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Este programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ahora - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Serie completa…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programar de todos modos"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Grabar esta en su lugar"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancelar esta grabación"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Ver ahora"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Se puede grabar"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Grabación programada"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Problema de grabación"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Grabación"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"No se ha podido grabar"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Leyendo programas para crear programaciones de grabación"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Leyendo programas"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Se necesita más almacenamiento para el DVR"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Puedes grabar programas con el DVR, pero no tienes suficiente espacio de almacenamiento en el dispositivo para que el DVR funcione. Conecta una unidad externa que tenga <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB como mínimo y sigue los pasos para formatearlo como almacenamiento del dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"No se puede acceder al almacenamiento"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"No se puede acceder a parte del almacenamiento utilizado por el DVR. Para volver a habilitarlo, conecta la unidad externa que has utilizado anteriormente. También puedes indicar que se olvide el almacenamiento si ya no está disponible."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"¿Olvidar almacenamiento?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Se perderán todo el contenido grabado y las programaciones."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"¿Detener grabación?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"El contenido grabado se guardará."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Grabación programada con conflictos"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"La grabación se ha iniciado, pero tiene conflictos"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Se grabará <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Se está grabando <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Algunas partes de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> no se grabarán."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> y <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> no se grabarán."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> y una programación más no se grabarán."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> y %3$d programaciones más no se grabarán.</item>
+ <item quantity="one">Algunas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> y %3$d programación más no se grabarán.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"¿Qué quieres grabar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"¿Cuánto tiempo quieres grabar?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Ya se ha programado"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Ya se ha programado la grabación del mismo programa para esta hora: <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Ya se ha grabado"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Este programa ya se ha grabado y está disponible en la colección del DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"No se ha encontrado el programa grabado."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Grabaciones relacionadas"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(No hay ninguna descripción)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d grabaciones</item>
+ <item quantity="one">%1$d grabación</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Se ha quitado <xliff:g id="PROGRAMNAME">%1$s</xliff:g> de la programación de grabación"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Se grabará parcialmente por problemas del sintonizador."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"No se grabará por problemas del sintonizador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aún no has programado ninguna grabación.\nPuedes hacerlo en la programación."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d conflictos de grabación</item>
+ <item quantity="one">%1$d conflicto de grabación</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Ajustes de series"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Iniciar grabación serie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Detener grabación serie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"¿Detener la grabación de series?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Los episodios grabados seguirán estando disponibles en la colección del DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Detener"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"No hay episodios disponibles.\nSe grabarán cuando estén disponibles."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutos)</item>
+ <item quantity="one">(%1$d minuto) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hoy"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Mañana"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ayer"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Hoy de <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Mañana de <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puntuación"</string>
</resources>
diff --git a/res/values-et-rEE/arrays.xml b/res/values-et-rEE/arrays.xml
index 23f3dc9c..2d1d11fd 100644
--- a/res/values-et-rEE/arrays.xml
+++ b/res/values-et-rEE/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Täis"</item>
<item msgid="8568284598210500589">"Suumimine"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Kõik kanalid"</item>
- <item msgid="6897460857821394118">"Pere/lapsed"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Ostud"</item>
- <item msgid="3296058637230163031">"Filmid"</item>
- <item msgid="1054540282883891201">"Komöödia"</item>
- <item msgid="7900158429062595471">"Reisimine"</item>
- <item msgid="3768998587825611787">"Draama"</item>
- <item msgid="8340620094959282881">"Haridus"</item>
- <item msgid="7396447839483867269">"Loomad/loodus"</item>
- <item msgid="4738043455148062673">"Uudised"</item>
- <item msgid="7405041316051047427">"Mängud"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Kõik kanalid"</item>
- <item msgid="7909003973960375395">"Pere/lapsed"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Ostud"</item>
- <item msgid="6083795019290250078">"Filmid"</item>
- <item msgid="8302638329222449550">"Komöödia"</item>
- <item msgid="3803709976021475052">"Reisimine"</item>
- <item msgid="8116747365234169059">"Draama"</item>
- <item msgid="7356447541595315913">"Haridus"</item>
- <item msgid="7511135485827589547">"Loomad/loodus"</item>
- <item msgid="6961248112238009967">"Uudised"</item>
- <item msgid="6484685553679698447">"Mängud"</item>
- <item msgid="2737158328243183190">"Kunst"</item>
- <item msgid="6577176952650166615">"Meelelahutus"</item>
- <item msgid="7886693831871777617">"Elustiil"</item>
- <item msgid="8145832312485577062">"Muusika"</item>
- <item msgid="1345789204804308580">"Esilinastus"</item>
- <item msgid="2736680312770771994">"Tehnika/teadus"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Kõik kanalid"</item>
+ <item msgid="928298872841713530">"Pere/lapsed"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Ostud"</item>
+ <item msgid="167201149441442173">"Filmid"</item>
+ <item msgid="525966731464264290">"Komöödia"</item>
+ <item msgid="6096710741527327836">"Reisimine"</item>
+ <item msgid="2851882187117833883">"Draama"</item>
+ <item msgid="78492781188719038">"Haridus"</item>
+ <item msgid="7221999662426308394">"Loomad/loodus"</item>
+ <item msgid="375300513250925001">"Uudised"</item>
+ <item msgid="7746320336582330410">"Mängud"</item>
+ <item msgid="1255741860568329178">"Kunstid"</item>
+ <item msgid="7603949681065702867">"Meelelahutus"</item>
+ <item msgid="4453821994746804366">"Elustiil"</item>
+ <item msgid="3488534597567932843">"Muusika"</item>
+ <item msgid="7452153120614274095">"Esilinastus"</item>
+ <item msgid="8215762047341133299">"Tehnika/teadus"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Reaalajakanalid"</item>
diff --git a/res/values-et-rEE/rating_system_strings.xml b/res/values-et-rEE/rating_system_strings.xml
index f7a34763..5cee5abd 100644
--- a/res/values-et-rEE/rating_system_strings.xml
+++ b/res/values-et-rEE/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-et-rEE/strings.xml b/res/values-et-rEE/strings.xml
index e28f2ccb..83022b8e 100644
--- a/res/values-et-rEE/strings.xml
+++ b/res/values-et-rEE/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Eelmine"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Saatekava"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Saadaval on uued kanalid"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ühtegi linki pole saadaval"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Ava <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtiitrid"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Kuvarežiim"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Alamreitingud"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Kanali vaatamiseks sisestage PIN-kood"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Saate vaatamiseks sisestage PIN-kood"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Selle saate reiting on <xliff:g id="RATING">%1$s</xliff:g>. Selle saate vaatamiseks sisestage oma PIN-kood"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Sisestage PIN-kood"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Vanemliku järelevalve määramiseks looge PIN-kood"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Sisestage uus PIN-kood"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Avatud lähtekoodi litsentsid"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Avatud lähtekoodi litsentsid"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versioon"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Aita täiustada reaalajas kanaleid"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Jagage Google\'iga anonüümseid kasutus- ja diagnostikaandmeid, et saaksime rakenduse Reaalajakanalid paremaks muuta ning vältida näiteks kokkujooksmist ja hangumist."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Kanali vaatamiseks vajutage paremale ja sisestage PIN-kood"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Saate vaatamiseks vajutage paremale ja sisestage PIN-kood"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Saate reiting on <xliff:g id="RATING">%1$s</xliff:g>\nSaate vaatamiseks vajutage valikut Paremale ja sisestage PIN-kood."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Ainult heli"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Nõrk signaal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Interneti-ühendus puudub"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Seda kanalit ei saa kuni kellani <xliff:g id="END_TIME_1">%1$s</xliff:g> esitada, kuna salvestatakse teisi kanaleid. \n\nSalvestamise ajakava kohandamiseks vajutage paremnoolt.</item>
+ <item quantity="one">Seda kanalit ei saa kuni kellani <xliff:g id="END_TIME_0">%1$s</xliff:g> esitada, kuna salvestatakse teist kanalit. \n\nSalvestamise ajakava kohandamiseks vajutage paremnoolt.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Pealkiri puudub"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal on blokeeritud"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Uus"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ühtegi kanalit pole saadaval"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Uus"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Pole seadistatud"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Hankige rohkem allikaid"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Sirvige rakendusi, mis pakuvad reaalajakanaleid"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Hankige rohkem allikaid"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Sirvige rakendusi, mis pakuvad reaalajakanaleid"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Saadaval on uued kanaliallikad"</string>
<string name="new_sources_description" msgid="749649005588426813">"Uutel kanaliallikatel on kanaleid pakkuda.\nSeadistage need kohe või tehke seda hiljem kanaliallikate seadetes."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Seadista kohe"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Kõik allikakanalid on peidetud.\nValige vaatamiseks vähemalt üks kanal."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video pole ootamatult saadaval"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Klahv TAGASI on mõeldud ühendatud seadme jaoks. Väljumiseks vajutage nuppu AVAEKRAAN."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Reaalajas kanaleid selles seadmes operatsioonisüsteemiga Android Lollipop ei toetata."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Reaalajas kanalid vajavad telekavade lugemiseks luba."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Allikate seadistamine"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Reaalajakanalid ühendavad tavaliste telekanalite kasutuskogemuse ja rakendustes kanalite voogesitamise. \n\nAlustamiseks seadistage juba installitud kanaliallikad. Võite ka sirvida Google Play poodi, et hankida rakendusi, mis pakuvad reaalajakanaleid."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Salvestised ja ajakavad"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutit"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutit"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 tund"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 tundi"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Hiljutised"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ajakavas´"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seeria"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Muud"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanalit ei saa salvestada."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programmi ei saa salvestada."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> on salvestamiseks ajastatud"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Saate <xliff:g id="PROGRAMNAME">%1$s</xliff:g> salvestamine praegusest kuni <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Kogu ajakava"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Järgmised %1$d päeva</item>
+ <item quantity="one">Järgmine %1$d päev</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutit</item>
+ <item quantity="one">%1$d minut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d uut salvestust</item>
+ <item quantity="one">%1$d uus salvestus</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d salvestust</item>
+ <item quantity="one">%1$d salvestus</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d salvestust on ajakavas</item>
+ <item quantity="one">%1$d salvestus on ajakavas</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Käekell"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Esita algusest"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Jätka esitust"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Kustuta"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Kustuta salvestised"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Jätka"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. hooaeg"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Kuva ajakava"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Lisateave"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Salvestuste kustutamine"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Valige jaod, mille soovite kustutada. Pärast kustutamist ei saa neid enam taastada."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Kustutamiseks pole salvestusi."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Vali vaadatud jaod"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Vali kõik jaod"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Tühista kõigi jagude valik"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> <xliff:g id="DURATION">%2$d</xliff:g>-st minutist on vaadatud"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> <xliff:g id="DURATION">%2$d</xliff:g>-st sekundist on vaadatud"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Pole kunagi vaadatud"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d %2$d-st jaost kustutati</item>
+ <item quantity="one">%1$d %2$d-st jaost kustutati</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioriteet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Kõige kõrgem"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Kõige madalam"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanalid"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Kõik"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Prioriteedi valimine"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Kui samal ajal salvestamiseks on liiga palju programme, salvestatakse ainult prioriteetsed programmid."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Salvesta"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Ühekordsete salvestiste prioriteet on kõige kõrgem"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Tühista"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Tühista"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Unusta"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Peata"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Kuva salvestamise ajakava"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Ainult see saade"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"praegu kuni <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Kogu seeria …"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Lisa ikkagi ajakavva"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Salvesta hoopis see"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Tühista see salvestus"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Kuva nüüd"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Salvestatav"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Salvestamine on ajastatud"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflikt salvestamisel"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Salvestamine"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Salvestamine ebaõnnestus"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Programmide lugemine salvestusajakavade loomiseks"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Programmide lugemine"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR vajab rohkem salvestusruumi"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Saateid saate salvestada DVR-iga. Praegu pole teie seadmes DVR-i töötamiseks siiski piisavalt salvestusruumi. Ühendage väline ketas, mille maht on vähemalt <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB, ja järgige juhiseid selle vormindamiseks salvestusseadmena."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Puuduv salvestusruum"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Osa DVR-i kasutatavast salvestusruumist on puudu. DVR-i uuesti lubamiseks ühendage väline ketas, mida varem kasutasite. Teise võimalusena saate salvestusruumi unustada, kui see enam saadaval pole."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Kas unustada salvestusruum?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Kogu teie salvestatud sisu ja ajakavad lähevad kaotsi."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Kas peatada salvestamine?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Salvestatud sisu talletatakse."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Salvestamine on ajastatud, ent ilmnesid vastuolud"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Salvestamine on alanud, kuid ilmnesid vastuolud"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Saadet <xliff:g id="PROGRAMNAME">%1$s</xliff:g> salvestatakse."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Kanalit <xliff:g id="CHANNELNAME">%1$s</xliff:g> salvestatakse."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Saate <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> teatud osi ei salvestata."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Saadete <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ja <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> teatud osi ei salvestata."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Saadete <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ja veel ühe ajakava teatud osi ei salvestata."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Saadete <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ja veel %3$d ajakavade teatud osi ei salvestata.</item>
+ <item quantity="one">Saadete <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ja veel %3$d ajakava teatud osi ei salvestata.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Mida soovite salvestada?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Kui kaua soovite salvestada?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Juba ajakavas"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Sama saate salvestus on juba lisatud ajakavva algusega <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Juba salvestatud"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"See saade on juba salvestatud. See on saadaval DVR-i kogus."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Salvestatud programmi ei leitud."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Seotud salvestised"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Programmi kirjeldust pole)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d salvestist</item>
+ <item quantity="one">%1$d salvestis</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> on salvestamise ajakavast eemaldatud"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Salvestatakse tuuneri konfliktide tõttu osaliselt."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ei salvestata tuuneri konfliktide tõttu."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Ajakavas ei ole veel salvestusi.\nSalvestuse saate ajakavva lisada saatekavas."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d salvestamise konflikti</item>
+ <item quantity="one">%1$d salvestamise konflikt</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Seeria seaded"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Alusta seeria salvestam."</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Peata seeria salvestamine"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Kas peatada seeria salvestamine?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Salvestatud jaod jäävad saadavale DVR-i kogusse."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Peata"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Ükski osa pole saadaval.\nNeed salvestatakse siis, kui need kättesaadavaks muutuvad."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutit)</item>
+ <item quantity="one">(%1$d minut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Täna"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Homme"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Eile"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Täna vahemikus <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Homme vahemikus <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Tulemus"</string>
</resources>
diff --git a/res/values-eu-rES/arrays.xml b/res/values-eu-rES/arrays.xml
index e17ea273..89b32135 100644
--- a/res/values-eu-rES/arrays.xml
+++ b/res/values-eu-rES/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Osoa"</item>
<item msgid="8568284598210500589">"Zooma"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Kanal guztiak"</item>
- <item msgid="6897460857821394118">"Familia/Umeak"</item>
- <item msgid="551257741825778215">"Kirolak"</item>
- <item msgid="452133796804325879">"Erosketak"</item>
- <item msgid="3296058637230163031">"Filmak"</item>
- <item msgid="1054540282883891201">"Komedia"</item>
- <item msgid="7900158429062595471">"Bidaiak"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Hezkuntza"</item>
- <item msgid="7396447839483867269">"Animaliak/Basabizitza"</item>
- <item msgid="4738043455148062673">"Albisteak"</item>
- <item msgid="7405041316051047427">"Jokoak"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Kanal guztiak"</item>
- <item msgid="7909003973960375395">"Familia/Umeak"</item>
- <item msgid="3185279732911635789">"Kirolak"</item>
- <item msgid="4704858492065325964">"Erosketak"</item>
- <item msgid="6083795019290250078">"Filmak"</item>
- <item msgid="8302638329222449550">"Komedia"</item>
- <item msgid="3803709976021475052">"Bidaiak"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Hezkuntza"</item>
- <item msgid="7511135485827589547">"Animaliak/Basabizitza"</item>
- <item msgid="6961248112238009967">"Albisteak"</item>
- <item msgid="6484685553679698447">"Jokoak"</item>
- <item msgid="2737158328243183190">"Artea"</item>
- <item msgid="6577176952650166615">"Denbora-pasak"</item>
- <item msgid="7886693831871777617">"Bizimodua"</item>
- <item msgid="8145832312485577062">"Musika"</item>
- <item msgid="1345789204804308580">"Estreinaldiak"</item>
- <item msgid="2736680312770771994">"Zientzia/Teknologia"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Kanal guztiak"</item>
+ <item msgid="928298872841713530">"Familia/Umeak"</item>
+ <item msgid="2751606947569857164">"Kirolak"</item>
+ <item msgid="7345749789651321496">"Erosketak"</item>
+ <item msgid="167201149441442173">"Filmak"</item>
+ <item msgid="525966731464264290">"Komedia"</item>
+ <item msgid="6096710741527327836">"Bidaiak"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Hezkuntza"</item>
+ <item msgid="7221999662426308394">"Animaliak/Basabizitza"</item>
+ <item msgid="375300513250925001">"Albisteak"</item>
+ <item msgid="7746320336582330410">"Jokoak"</item>
+ <item msgid="1255741860568329178">"Artea"</item>
+ <item msgid="7603949681065702867">"Ikuskizunak"</item>
+ <item msgid="4453821994746804366">"Bizimodua"</item>
+ <item msgid="3488534597567932843">"Musika"</item>
+ <item msgid="7452153120614274095">"Onenak"</item>
+ <item msgid="8215762047341133299">"Zientzia/Teknologia"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Telebista zuzenean"</item>
diff --git a/res/values-eu-rES/rating_system_strings.xml b/res/values-eu-rES/rating_system_strings.xml
index cb629c14..ae0d84d4 100644
--- a/res/values-eu-rES/rating_system_strings.xml
+++ b/res/values-eu-rES/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-eu-rES/strings.xml b/res/values-eu-rES/strings.xml
index 1eea239e..19a00433 100644
--- a/res/values-eu-rES/strings.xml
+++ b/res/values-eu-rES/strings.xml
@@ -19,7 +19,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="audio_channel_mono" msgid="8812941280022167428">"mono"</string>
<string name="audio_channel_stereo" msgid="5798223286366598036">"estereo"</string>
- <string name="menu_title_play_controls" msgid="2490237359425190652">"Erreprodukzio-kontrolak"</string>
+ <string name="menu_title_play_controls" msgid="2490237359425190652">"Erreprodukzioa kontrolatzeko aukerak"</string>
<string name="menu_title_channels" msgid="1801845517674690003">"Azken kanalak"</string>
<string name="menu_title_options" msgid="7184594626814914022">"Telebistaren aukerak"</string>
<string name="menu_title_pip_options" msgid="4252934960762407689">"Pantaila txikia"</string>
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Aurrekoa"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Telesaioen gida"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Kanal berriak daude"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ez dago estekarik"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Azpitituluak"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Bistaratzeko modua"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Azpisailkapenak"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Kanal hau ikusi nahi baduzu, idatzi PIN kodea."</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Telesaio hau ikusi nahi baduzu, idatzi PIN kodea."</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Programaren balorazioa: <xliff:g id="RATING">%1$s</xliff:g>. Idatzi PIN kodea programa ikusteko."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Idatzi PIN kodea"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Gurasoen kontrol-aukerak zehazteko, sortu PIN kode bat"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Idatzi PIN kode berria"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Kode irekiko lizentziak"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Kode irekiko lizentziak"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Bertsioa"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Lagundu Zuzeneko kanalak hobetzen"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Partekatu erabilerari buruzko datu eta diagnostiko anonimoak Google-rekin, Telebista zuzenean zerbitzua hobe dezagun, besteak beste, hutsegiteak gertatzea edo irudia izoztuta geratzea ekiditeko."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Kanal hau ikusteko, sakatu Eskuinera tekla eta idatzi PIN kodea."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Telesaio hau ikusteko, sakatu Eskuinera tekla eta idatzi PIN kodea."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Telesaioa \"<xliff:g id="RATING">%1$s</xliff:g>\" gisa sailkatu da.\nIkusi ahal izateko, sakatu Eskuinera tekla eta idatzi PIN kodea."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audioa soilik"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Seinale ahula"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Ez zaude Internetera konektatuta"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Kanal hau ezin da erreproduzitu <xliff:g id="END_TIME_1">%1$s</xliff:g> arte, beste kanal batzuk grabatzen ari garelako. \n\nGrabaketaren orduak aldatzeko, sakatu Eskuinera tekla.</item>
+ <item quantity="one">Kanal hau ezin da erreproduzitu <xliff:g id="END_TIME_0">%1$s</xliff:g> arte, beste kanal bat ari garelako grabatzen. \n\nGrabaketaren orduak aldatzeko, sakatu Eskuinera tekla.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Izenik ez"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanala blokeatuta dago"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Berriak"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ez dago kanalik erabilgarri"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Berriak"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Konfiguratu gabe"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Lortu iturburu gehiago"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Arakatu zuzenean igortzen duten kanalak eskaintzen dituzten aplikazioak"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Lortu iturburu gehiago"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Arakatu edukia zuzenean igortzen duten kanalak eskaintzen dituzten aplikazioak"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Kanalen iturburu berriak daude erabilgarri"</string>
<string name="new_sources_description" msgid="749649005588426813">"Beste kanal batzuk eskaintzen dituzten iturburu berriak dituzu eskura.\nKonfigura itzazu oraintxe bertan edo egin ezazu beste uneren batean kanalen iturburuen ezarpenera joanda."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Konfiguratu"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Iturburuko kanal guztiak ezkutuan daude.\nHautatu gutxienez kanal bat ikusteko."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Bideoa ez dago erabilgarri"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Atzera tekla konektatutako gailuari dagokio. Irteteko, sakatu Hasiera botoia."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop duen gailu honetan ezin da erabili Zuzeneko kanalak aplikazioa."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Zuzeneko kanalak aplikazioak baimena behar du telebistako programazioa irakurtzeko."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Konfiguratu iturburuak"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Telebista zuzenean zerbitzuarekin, aplikazioek zuzenean erreproduzitzen dituzten kanalak ohiko telebistaren moduan ikus ditzakezu. \n\nLehen urratsak emateko, konfiguratu instalatutako kanal-iturburuak. Bestela, arakatu Google Play Store denda zuzeneko kanalak eskaintzen dituzten aplikazio gehiago aurkitzeko."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Grabaketak eta grabaketen programazioa"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutu"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutu"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ordu"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ordu"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Azkenak"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programatutakoak"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Telesailak"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Beste batzuk"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Ezin da grabatu kanal hau."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Ezin da grabatu programa hau."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> grabatzeko programatu da"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> grabatuko da <xliff:g id="ENDTIME">%2$s</xliff:g> arte"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programazio osoa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Beste %1$d egun</item>
+ <item quantity="one">Beste %1$d egun</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutu</item>
+ <item quantity="one">%1$d minutu</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d grabaketa berri</item>
+ <item quantity="one">%1$d grabaketa berri</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d grabaketa</item>
+ <item quantity="one">%1$d grabaketa</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d grabaketa antolatuta</item>
+ <item quantity="one">%1$d grabaketa antolatuta</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Ikusi"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Erreproduzitu hasieratik"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Berrekin"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Ezabatu"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Ezabatu grabaketak"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Berrekin"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. denboraldia"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ikusi agenda"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Irakurri gehiago"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Ezabatu grabaketak"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Hautatu ezabatu nahi dituzun atalak. Ezabatu ondoren, ezingo dituzu berreskuratu."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Ez dago ezaba daitekeen grabaketarik."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Hautatu ikusitako atalak"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Hautatu atal guztiak"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Ezabatu atal guztiak"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> minutu ikusi dituzu"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> segundo ikusi dituzu"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Inoiz ikusi gabe"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d/%2$d atal ezabatu dira</item>
+ <item quantity="one">%1$d/%2$d atal ezabatu da</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Lehentasuna"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Handiena"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Txikiena"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"<xliff:g id="RANK">%1$d</xliff:g>.a"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanalak"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Edozein"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Aukeratu lehentasuna"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Aldi berean programa gehiegi grabatu behar badira, lehentasun handieneko programak bakarrik grabatuko dira."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Gorde"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Grabaketa solteek dute lehentasun handiena"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Utzi"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Utzi"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Ahaztu"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Gelditu"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ikusi grabaketen agenda"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Programa hau bakarrik"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"orain – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Telesail osoa…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programatu, hala ere"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Grabatu beste hau haren ordez"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Utzi grabaketa hau bertan behera"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Ikusi"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Graba daiteke"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Grabatzeko antolatuta"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Grabatzeko gatazka"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Grabatzen"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Ezin izan da grabatu"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Programak irakurtzen ari gara grabaketa-ordutegiak sortzeko"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Programazioa irakurtzen"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Bideo-grabagailu digitalak ez dauka behar adina memoria erabilgarri"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Bideo-grabagailu digitalarekin programak grabatu ahal izango dituzu. Dena dela, une honetan ez daukazu bideo-grabagailua erabili ahal izateko behar adina memoria erabilgarri. Konektatu <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB edo gehiago dituen unitate aldagarri bat eta formatea ezazu gailuaren memoria gisa erabiltzeko."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Memoria-unitatea falta da"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Bideo-grabagailu digitalak erabili duen memoria-unitateren bat falta da. Bideo-grabagailu digitala gaitu ahal izateko, konektatu aurrez erabilitako unitate aldagarria. Memoria-unitate hura eskura ez baduzu, berriz, aukera ezazu unitatea ahazteko aukera."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Memoria-unitate hau ahaztea nahi duzu?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Grabatuta edo programatuta duzun eduki guztia galduko da."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Grabaketa gelditu nahi duzu?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Grabatutako edukia gordeta geratuko da."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Grabatzeko programatu da baina gatazkan dago beste grabaketa batzuekin"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Grabatzen hasi da, baina gatazkak ditu"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> grabatuko da."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> grabatzen ari da."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ez da osorik grabatuko."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> eta <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ez dira osorik grabatuko."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> eta grabatzeko programatuta dagoen beste saio bat ez dira osorik grabatuko."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> eta grabatzeko programatuta dauden beste %3$d saio ez dira osorik grabatuko.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> eta grabatzeko programatuta dagoen beste %3$d saio ez dira osorik grabatuko.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Zer grabatu nahi duzu?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Zenbat denboran grabatu nahi duzu?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Programatuta dago dagoeneko"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Programa hau bera grabatzeko programatu duzu dagoeneko (<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>)."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Grabatuta dago dagoeneko"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Programa hau grabatuta daukazu dagoeneko. DVR liburutegian duzu ikusgai."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Ez da aurkitu grabatutako programa."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Erlazionatutako grabaketak"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ez dago programaren azalpenik)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d grabaketa</item>
+ <item quantity="one">%1$d grabaketa</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> kendu egin da programatutako grabaketen zerrendatik"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Partzialki grabatuko da, sintonizadoreak gatazkak baititu."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ez da grabatuko, sintonizadoreak gatazkak baititu."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Oraindik ez duzu programatu grabaketarik.\nProgramazio-gidan programa ditzakezu grabaketak."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d grabaketa-gatazka</item>
+ <item quantity="one">%1$d grabaketa-gatazka</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Seriearen ezarpenak"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Hasi seriea grabatzen"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Utzi seriea grabatzeari"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Seriea grabatzeari utzi nahi diozu?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"DVR liburutegian gordeta geratuko dira grabatutako atalak."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Gelditu"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Ez dago atalik ikusgai.\nIkusgai ezartzen dituztenean grabatuko ditugu."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutu)</item>
+ <item quantity="one">(%1$d minutu) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Gaur"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Bihar"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Atzo"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Gaur, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Bihar, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puntuazioa"</string>
</resources>
diff --git a/res/values-fa/arrays.xml b/res/values-fa/arrays.xml
index 7b288615..a9b956f5 100644
--- a/res/values-fa/arrays.xml
+++ b/res/values-fa/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"کامل"</item>
<item msgid="8568284598210500589">"بزرگ‌نمایی"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"همه کانال‌ها"</item>
- <item msgid="6897460857821394118">"خانواده/کودکان"</item>
- <item msgid="551257741825778215">"ورزش"</item>
- <item msgid="452133796804325879">"خرید"</item>
- <item msgid="3296058637230163031">"فیلم‌"</item>
- <item msgid="1054540282883891201">"کمدی"</item>
- <item msgid="7900158429062595471">"سفر"</item>
- <item msgid="3768998587825611787">"درام"</item>
- <item msgid="8340620094959282881">"آموزشی"</item>
- <item msgid="7396447839483867269">"حیوانات/حیات وحش"</item>
- <item msgid="4738043455148062673">"اخبار"</item>
- <item msgid="7405041316051047427">"بازی"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"همه کانال‌ها"</item>
- <item msgid="7909003973960375395">"خانواده/کودکان"</item>
- <item msgid="3185279732911635789">"ورزش"</item>
- <item msgid="4704858492065325964">"خرید"</item>
- <item msgid="6083795019290250078">"فیلم‌"</item>
- <item msgid="8302638329222449550">"کمدی"</item>
- <item msgid="3803709976021475052">"سفر"</item>
- <item msgid="8116747365234169059">"درام"</item>
- <item msgid="7356447541595315913">"آموزشی"</item>
- <item msgid="7511135485827589547">"حیوانات/حیات وحش"</item>
- <item msgid="6961248112238009967">"اخبار"</item>
- <item msgid="6484685553679698447">"بازی"</item>
- <item msgid="2737158328243183190">"هنر"</item>
- <item msgid="6577176952650166615">"سرگرمی"</item>
- <item msgid="7886693831871777617">"سبک زندگی"</item>
- <item msgid="8145832312485577062">"موسیقی"</item>
- <item msgid="1345789204804308580">"برتر"</item>
- <item msgid="2736680312770771994">"فناوری/علم"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"همه کانال‌ها"</item>
+ <item msgid="928298872841713530">"خانواده/کودکان"</item>
+ <item msgid="2751606947569857164">"ورزش"</item>
+ <item msgid="7345749789651321496">"خرید"</item>
+ <item msgid="167201149441442173">"فیلم"</item>
+ <item msgid="525966731464264290">"کمدی"</item>
+ <item msgid="6096710741527327836">"سفر"</item>
+ <item msgid="2851882187117833883">"درام"</item>
+ <item msgid="78492781188719038">"آموزش"</item>
+ <item msgid="7221999662426308394">"حیوانات/حیات وحش"</item>
+ <item msgid="375300513250925001">"اخبار"</item>
+ <item msgid="7746320336582330410">"بازی"</item>
+ <item msgid="1255741860568329178">"هنر"</item>
+ <item msgid="7603949681065702867">"سرگرمی"</item>
+ <item msgid="4453821994746804366">"روش زندگی"</item>
+ <item msgid="3488534597567932843">"موسیقی"</item>
+ <item msgid="7452153120614274095">"برتر"</item>
+ <item msgid="8215762047341133299">"فناوری/علم"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"کانال‌های زنده"</item>
diff --git a/res/values-fa/rating_system_strings.xml b/res/values-fa/rating_system_strings.xml
index fdc5a75d..17f0f42a 100644
--- a/res/values-fa/rating_system_strings.xml
+++ b/res/values-fa/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 46a58f15..7dd59c28 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"قبلی"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"راهنمای برنامه"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"کانال‌های جدید در دسترس است"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"پیوندی موجود نیست"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"باز کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"زیرنویس‌ها"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"حالت نمایش"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"رتبه‌بندی‌های فرعی"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"برای تماشای این کانال، پین خودتان را وارد کنید"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"برای تماشای این برنامه، پین خودتان را وارد کنید"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"به این برنامه <xliff:g id="RATING">%1$s</xliff:g> رتبه داده شده است. برای تماشای این برنامه کد پین را وارد کنید"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"پین خودتان را وارد کنید"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"برای تنظیم کنترل‌های والدین، پین ایجاد کنید"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"پین جدید را وارد کنید"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"مجوزهای منبع آزاد"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"مجوزهای منبع آزاد"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"نسخه"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"کمک به بهبود «کانال‌های مستقیم»"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"‏داده‌های عیب‌یابی و مصرف بی‌نام را با Google به اشتراک بگذارید تا ما کانال‌های زنده را بهتر کنیم و از مشکلاتی مانند خرابی و ثابت ماندن تصویر جلوگیری کنیم."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"برای مشاهده این کانال، راست را فشار دهید و پین خودتان را وارد کنید"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"برای مشاهده این برنامه، راست را فشار دهید و پین خودتان را وارد کنید"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"‏رتبه‌بندی این برنامه <xliff:g id="RATING">%1$s</xliff:g> است.\nبرای تماشای این برنامه، Right (راست) را فشار دهید و پین خودتان را وارد کنید."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"فقط صدا"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"سیگنال ضعیف است"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"اتصال اینترنت قطع است"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">این کانال تا <xliff:g id="END_TIME_1">%1$s</xliff:g> قابل پخش نیست، زیرا کانال‌های دیگری درحال ضبط هستند. \n\nبرای تنظیم زمان‌بندی ضبط، «راست» را فشار دهید.</item>
+ <item quantity="other">این کانال تا <xliff:g id="END_TIME_1">%1$s</xliff:g> قابل پخش نیست، زیرا کانال‌های دیگری درحال ضبط هستند. \n\nبرای تنظیم زمان‌بندی ضبط، «راست» را فشار دهید.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"بدون عنوان"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"کانال مسدود شد"</string>
<string name="setup_category_new" msgid="2899355289563443627">"جدید"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"هیچ کانالی موجود نیست"</string>
<string name="setup_input_new" msgid="3337725672277046798">"جدید"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"تنظیم نشده است"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"دریافت منابع بیشتر"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"مرور برنامه‌هایی که کانال‌های زنده ارائه می‌کنند"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"دریافت منابع بیشتر"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"مرور برنامه‌هایی که کانال‌های زنده ارائه می‌کنند"</string>
<string name="new_sources_title" msgid="3878933676500061895">"منابع کانال جدید در دسترس هستند"</string>
<string name="new_sources_description" msgid="749649005588426813">"منابع کانال جدید کانال‌هایی برای ارائه دارند.\nهم‌اکنون آن‌ها را راه‌اندازی کنید یا این کار را بعداً در تنظیم منابع کانال انجام دهید."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"هم‌اکنون راه‌اندازی شود"</string>
@@ -185,10 +187,164 @@
<string name="msg_tune_failed" msgid="3277419551849972252">"تنظیم نشد"</string>
<string name="msg_missing_app" msgid="8291542072400042076">"برنامه‌ای برای انجام این اقدام پیدا نشد."</string>
<string name="msg_all_channels_hidden" msgid="777397634062471936">"همه کانال‌های منبع پنهان هستند.\nحداقل یک کانال را برای تماشا انتخاب کنید."</string>
- <string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"این ویدیو به‌طور غیر منتظره‌ای در دسترس نیست."</string>
+ <string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"این ویدئو به‌طور غیر منتظره‌ای در دسترس نیست."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"کلید بازگشت برای دستگاه‌ متصل است. برای خروج دکمه صفحه اصلی را فشار دهید."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"‏کانال‌های مستقیم در این دستگاه دارای Android Lollipop پشتیبانی نمی‌شوند."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"کانال‌های مستقیم به مجوز خواندن فهرست‌های تلویزیون نیاز دارند."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"راه‌اندازی منابع"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"‏کانال‌های زنده تجربه کانال‌های تلویزیونی قدیمی را با کانال‌های پخش جریانی ارائه‌شده توسط برنامه‌ها ادغام می‌کند. \n\nبا راه‌اندازی منابع کانالی که قبلاً نصب شده‌اند شروع کنید. یا برای پیدا کردن برنامه‌های بیشتری که کانال‌های زنده ارائه می‌کنند، فروشگاه Google Play را مرور کنید."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ضبط و زمان‌بندی"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"۱۰ دقیقه"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"۳۰ دقیقه"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"۱ ساعت"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"۳ ساعت"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"اخیر"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"زمان‌بندی‌شده"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"سری"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"موارد دیگر"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"کانال را نمی‌توان ضبط کرد."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"برنامه را نمی‌توان ضبط کرد."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> برای ضبط زمان‌بندی شده است"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ضبط <xliff:g id="PROGRAMNAME">%1$s</xliff:g> از اکنون تا <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"زمان‌بندی کامل"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">‏%1$d روز بعد</item>
+ <item quantity="other">‏%1$d روز بعد</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">‏%1$d دقیقه</item>
+ <item quantity="other">‏%1$d دقیقه</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">‏%1$d ضبط جدید</item>
+ <item quantity="other">‏%1$d ضبط جدید</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">‏%1$d ضبط</item>
+ <item quantity="other">‏%1$d ضبط</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">‏%1$d ضبط زمان‌بندی‌شده</item>
+ <item quantity="other">‏%1$d ضبط زمان‌بندی‌شده</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ساعت مچی"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"پخش از اول"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ازسرگیری پخش"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"حذف"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"حذف موارد ضبط‌شده"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"ازسر‌گیری"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"فصل <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"مشاهده زمان‌بندی"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"بیشتر بخوانید"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"حذف موارد ضبط‌شده"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"قسمت‌هایی را که می‌خواهید حذف کنید انتخاب کنید. این قسمت‌ها را پس از حذف نمی‌توان بازیابی کرد."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"مورد ضبط‌شده‌ای برای حذف وجود ندارد."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"انتخاب قسمت‌های تماشاشده"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"انتخاب همه قسمت‌ها"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"لغو انتخاب همه قسمت‌ها"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> از <xliff:g id="DURATION">%2$d</xliff:g> دقیقه تماشاشده است"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> از <xliff:g id="DURATION">%2$d</xliff:g> ثانیه تماشا شده است"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"هرگز تماشانشده"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">‏%1$d قسمت از %1$d قسمت حذف می‌شود</item>
+ <item quantity="other">‏%1$d قسمت از %1$d قسمت حذف می‌شود</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"اولویت‌دار"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"بالاترین"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"پایین‌ترین"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"شماره <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"کانال‌ها"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"هرکدام"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"انتخاب اولویت"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"اگر برنامه‌های زیادی برای ضبط هم‌زمان وجود داشته باشد، فقط برنامه‌های با بیشترین اولویت ضبط خواهند شد."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"ذخیره"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ضبط‌های تکی بالاترین اولویت را دارند"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"لغو"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"لغو"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"فراموش شود"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"توقف"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"مشاهده زمان‌بندی ضبط"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"فقط همین برنامه"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"اکنون - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"کل مجموعه‌ها…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"درهرحال زمان‌بندی شود"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"درعوض این مورد ضبط شود"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"لغو این ضبط"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"اکنون تماشا کنید"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"قابل ضبط"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ضبط برنامه‌ریزی‌شده"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ضبط متناقض با زمان‌بندی"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"درحال ضبط"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ضبط ناموفق بود"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"درحال خواندن برنامه‌ها برای ایجاد زمان‌بندی ضبط"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"درحال خواندن برنامه‌ها"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"‏DVR به فضای بیشتری نیاز دارد"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"‏با DVR می‌توانید برنامه‌ها را ضبط کنید. اما اکنون فضای ذخیره‌سازی کافی در دستگاهتان وجود ندارد و DVR کار نمی‌کند. لطفاً درایو خارجی‌‌ای با حجم <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> گیگابایت یا بیشتر متصل کنید و برای قالب‌بندی آن‌ به‌عنوان حافظه دستگاه این مراحل را دنبال کنید."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"حافظه دردسترس نیست"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"‏مقداری از حافظه‌ای که توسط DVR استفاده می‌شود از بین می‌رود. لطفاً برای فعال‌سازی مجدد DVR، درایو خارجی را که قبلاً‌ استفاده کردید متصل کنید. یا اگر این حافظه دیگر دردسترس نیست می‌توانید انتخاب کنید فراموش شود."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"حافظه فراموش شود؟"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"همه زمان‌بندی‌ها و محتوای ضبط‌شده‌ شما از دست می‌رود."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ضبط متوقف شود؟"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"محتوای ضبط‌شده ذخیره خواهد شد."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ضبط، زمان‌بندی شده است اما متناقض است"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ضبط شروع شده است اما متناقض است"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ضبط خواهد شد."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> درحال ضبط است."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"بعضی از قسمت‌های <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ضبط نخواهد شد."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"بعضی از قسمت‌های <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> و <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ضبط نخواهد شد."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"بعضی از قسمت‌های <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> و یک زمان‌بندی دیگر ضبط نخواهد شد."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">‏بعضی از قسمت‌های <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و %3$d زمان‌بندی دیگر ضبط نخواهد شد.</item>
+ <item quantity="other">‏بعضی از قسمت‌های <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> و %3$d زمان‌بندی دیگر ضبط نخواهد شد.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"می‌خواهید چه چیزی را ضبط کنید؟"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"چه مدت می‌خواهید ضبط کنید؟"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"قبلاً‌ زمان‌بندی شده است"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"این برنامه قبلاً‌ برای ضبط در <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> زمان‌بندی شده است."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"قبلاً‌ ضبط شده است"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"‏این برنامه قبلاً‌ ضبط شده است و در کتابخانه DVR موجود است."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"برنامه ضبط‌شده پیدا نشد."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ضبط‌های مرتبط"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(بدون شرح برنامه)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">‏%1$d ضبط</item>
+ <item quantity="other">‏%1$d ضبط</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> از زمان‌بندی ضبط برداشته شد"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"به دلیل تداخل‌های تنظیم‌کننده، به‌طور کامل ضبط نمی‌شود."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"به دلیل تداخل‌های تنظیم‌کننده، ضبط نمی‌شود."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"هنوز موردی برای ضبط زمان‌بندی نشده است.\nمی‌توانید از «راهنمای برنامه» ضبط را زمان‌بندی کنید."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">‏%1$d ضبط متناقض با زمان‌بندی</item>
+ <item quantity="other">‏%1$d ضبط متناقض با زمان‌بندی</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"تنظیمات مجموعه"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"شروع ضبط مجموعه"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"توقف ضبط مجموعه"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"ضبط مجموعه متوقف شود؟"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"‏قسمت‌های ضبط‌شده در کتابخانه DVR دردسترس باقی می‌ماند."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"توقف"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"هیچ قسمتی موجود نیست.\nهر قسمتی در دسترس قرار بگیرد ضبط خواهد شد."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">‏(%1$d دقیقه)</item>
+ <item quantity="other">‏(%1$d دقیقه)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"امروز"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"فردا"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"دیروز"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> امروز"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> فردا"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"امتیاز"</string>
</resources>
diff --git a/res/values-fi/arrays.xml b/res/values-fi/arrays.xml
index c13f5788..01266b27 100644
--- a/res/values-fi/arrays.xml
+++ b/res/values-fi/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Täysi"</item>
<item msgid="8568284598210500589">"Zoomattu"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Kaikki kanavat"</item>
- <item msgid="6897460857821394118">"Perhe ja lapset"</item>
- <item msgid="551257741825778215">"Urheilu"</item>
- <item msgid="452133796804325879">"Ostokset"</item>
- <item msgid="3296058637230163031">"Elokuvat"</item>
- <item msgid="1054540282883891201">"Komedia"</item>
- <item msgid="7900158429062595471">"Matkailu"</item>
- <item msgid="3768998587825611787">"Draama"</item>
- <item msgid="8340620094959282881">"Opetus"</item>
- <item msgid="7396447839483867269">"Eläimet ja luonto"</item>
- <item msgid="4738043455148062673">"Uutiset"</item>
- <item msgid="7405041316051047427">"Pelit"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Kaikki kanavat"</item>
- <item msgid="7909003973960375395">"Perhe ja lapset"</item>
- <item msgid="3185279732911635789">"Urheilu"</item>
- <item msgid="4704858492065325964">"Ostokset"</item>
- <item msgid="6083795019290250078">"Elokuvat"</item>
- <item msgid="8302638329222449550">"Komedia"</item>
- <item msgid="3803709976021475052">"Matkailu"</item>
- <item msgid="8116747365234169059">"Draama"</item>
- <item msgid="7356447541595315913">"Opetus"</item>
- <item msgid="7511135485827589547">"Eläimet ja luonto"</item>
- <item msgid="6961248112238009967">"Uutiset"</item>
- <item msgid="6484685553679698447">"Pelit"</item>
- <item msgid="2737158328243183190">"Taide"</item>
- <item msgid="6577176952650166615">"Viihde"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Musiikki"</item>
- <item msgid="1345789204804308580">"Ensiesitys"</item>
- <item msgid="2736680312770771994">"Tekniikka ja tiede"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Kaikki kanavat"</item>
+ <item msgid="928298872841713530">"Perhe/lapset"</item>
+ <item msgid="2751606947569857164">"Urheilu"</item>
+ <item msgid="7345749789651321496">"Ostokset"</item>
+ <item msgid="167201149441442173">"Elokuvat"</item>
+ <item msgid="525966731464264290">"Komedia"</item>
+ <item msgid="6096710741527327836">"Matkailu"</item>
+ <item msgid="2851882187117833883">"Draama"</item>
+ <item msgid="78492781188719038">"Opetus"</item>
+ <item msgid="7221999662426308394">"Eläimet/luonto"</item>
+ <item msgid="375300513250925001">"Uutiset"</item>
+ <item msgid="7746320336582330410">"Pelit"</item>
+ <item msgid="1255741860568329178">"Taiteet"</item>
+ <item msgid="7603949681065702867">"Viihde"</item>
+ <item msgid="4453821994746804366">"Elämäntapa"</item>
+ <item msgid="3488534597567932843">"Musiikki"</item>
+ <item msgid="7452153120614274095">"Ensiesitys"</item>
+ <item msgid="8215762047341133299">"Tekniikka/tiede"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live-kanavat"</item>
diff --git a/res/values-fi/rating_system_strings.xml b/res/values-fi/rating_system_strings.xml
index 50851dfb..ee2ea1f0 100644
--- a/res/values-fi/rating_system_strings.xml
+++ b/res/values-fi/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index bb0a0000..b6f5fb7e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Edellinen"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Ohjelmaopas"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Uusia kanavia"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ei linkkiä saatavilla"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Avaa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Tekstitykset"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Näyttötila"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Aliluokitukset"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Anna PIN-koodi, jotta voit katsella tätä kanavaa"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Anna PIN-koodi, jotta voit katsella tätä ohjelmaa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Tämän ohjelman ikärajoitus on <xliff:g id="RATING">%1$s</xliff:g>. Anna PIN-koodi, jos haluat katsoa tätä ohjelmaa."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Anna PIN-koodi"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Aseta lapsilukko luomalla PIN-koodi"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Anna uusi PIN-koodi"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Avoimen lähdekoodin käyttöluvat"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Avoimen lähdekoodin käyttöluvat"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versio"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Auta parantamaan live-kanavia"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Jakamalla Googlelle anonyymejä käyttö- ja diagnostiikkatietoja autat meitä parantamaan livekanavia ja estämään kaatumisen ja pysähtymisen kaltaisia ongelmia."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Katsele tätä kanavaa painamalla näppäimellä oikealle ja antamalla PIN-koodi"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Katsele tämä ohjelma painamalla näppäimellä oikealle ja antamalla PIN-koodi"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Tämän ohjelman luokitus on <xliff:g id="RATING">%1$s</xliff:g>.\nKatso ohjelma painamalla näppäimellä oikealle ja antamalla PIN-koodi."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Vain ääni"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Heikko signaali"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Ei internetyhteyttä"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Voit katsella tätä kanavaa aikaisintaan klo <xliff:g id="END_TIME_1">%1$s</xliff:g>, sillä muita kanavia tallennetaan. \n\nMuokkaa tallennusaikataulua painamalla oikeanpuoleista painiketta.</item>
+ <item quantity="one">Voit katsella tätä kanavaa aikaisintaan klo <xliff:g id="END_TIME_0">%1$s</xliff:g>, sillä toista kanavaa tallennetaan. \n\nMuokkaa tallennusaikataulua painamalla oikeanpuoleista painiketta.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Ei nimeä"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanava estetty"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Uudet"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ei käytettävissä olevia kanavia"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Uusi"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Ei määritetty"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Hae lisää lähteitä"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Selaa sovelluksia, jotka tarjoavat livekanavia."</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Hae lisää lähteitä"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Selaa sovelluksia, jotka tarjoavat livekanavia."</string>
<string name="new_sources_title" msgid="3878933676500061895">"Uusia kanavalähteitä on saatavilla"</string>
<string name="new_sources_description" msgid="749649005588426813">"Tarjolla on kanavia uusista lähteistä.\nVoit määrittää kanavalähteet nyt tai tehdä sen myöhemmin kanavalähdeasetuksien kautta."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Määritä nyt"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Kaikki lähdekanavat on piilotettu.\nValitse vähintään yksi katseltava kanava."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video ei yllättäen ole käytettävissä."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"EDELLINEN-painike koskee liitettyä laitetta. Poistu painamalla ETUSIVU-painiketta."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live-kanavia ei tueta tällä Android Lollipop -laitteella."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live-kanavat tarvitsee luvan TV-ohjelmatietojen lukemiseen."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Määritä lähteesi"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Live-kanavat yhdistävät perinteisen TV-kanavakokemuksen suoratoistoon sovelluksilla. \n\nAloita määrittämällä asennetut kanavalähteet tai etsi livekanavia tarjoavia sovelluksia Google Play Kaupasta."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Tallenteet ja aikataulut"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuuttia"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuuttia"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 tunti"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 tuntia"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Viimeisimmät"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ajastetut"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Sarja"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Muut"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Tämän kanavan sisältöä ei voida tallentaa."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Tätä ohjelmaa ei voida tallentaa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> on ajastettu tallennettavaksi."</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Tallennetaan ohjelmaa <xliff:g id="PROGRAMNAME">%1$s</xliff:g> tästä hetkestä klo <xliff:g id="ENDTIME">%2$s</xliff:g> asti."</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Koko aikataulu"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d seuraavaa päivää</item>
+ <item quantity="one">%1$d seuraava päivä</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minuuttia</item>
+ <item quantity="one">%1$d minuutti</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d uutta tallennetta</item>
+ <item quantity="one">%1$d uusi tallenne</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d tallennetta</item>
+ <item quantity="one">%1$d tallenne</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d tallenn. ajastettu</item>
+ <item quantity="one">%1$d tallennus ajastettu</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Katso"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Toista alusta"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Jatka toistoa"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Poista"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Poista tallenteet"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Jatka"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Kausi <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Näytä aikataulu"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Lisätietoja"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Tallenteiden poisto"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Valitse poistettavat jaksot. Kun ne on poistettu, niitä ei voi palauttaa."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Ei poistettavia tallenteita"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Valitse katsotut jaksot"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Valitse kaikki jaksot"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Poista kaik. jaksojen valinta"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> minuuttia katsottu"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> sekuntia katsottu"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Ei katsottu"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d/%2$d jaksoa poistettu</item>
+ <item quantity="one">%1$d/%2$d jakso poistettu</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Tärkeät"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Korkein"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Matalin"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"<xliff:g id="RANK">%1$d</xliff:g>."</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanavat"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Kaikki"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Valitse tärkeysjärjestys"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Jos ohjelmia on ajastettu enemmän kuin samalla kertaa voidaan tallentaa, vain tärkeimmät ohjelmat tallennetaan."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Tallenna"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Kertaluotoiset tallennukset ovat tärkeimpiä."</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Peruuta"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Peruuta"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Unohda"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Lopeta"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Näytä tallennusaikataulu"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Vain tämä jakso"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"Tästä hetkestä klo <xliff:g id="ENDTIME">%1$s</xliff:g> asti"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Koko sarja…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Ajasta siitä huolimatta"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Nauhoita tämä sen sijaan"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Peruuta tämä nauhoitus"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Katso nyt"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Tallennettavissa"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Tallennus ajastettu"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Tallennusristiriita"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Tallennetaan"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Nauhoitus epäonnistui"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Luetaan ohjelmatietoja tallennusaikataulujen luomista varten."</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Luetaan ohjelmatietoja"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR tarvitsee lisää tilaa"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Voit tallentaa ohjelmia DVR:llä. Laitteellasi ei kuitenkaan ole tarpeeksi tilaa DVR:n käyttöön. Yhdistä vähintään <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> Gt:n kokoinen ulkoinen tallennuslaite ja alusta se laitteen tallennustilaksi ohjeiden mukaisesti."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Tallennustila puuttuu"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Osa DVR:n käytössä olleesta tallennustilasta puuttuu. Palauta DVR käyttöön liittämällä aiemmin käyttämäsi ulkoinen asema. Voit myös unohtaa tallennustilan, jos asema ei ole enää käytettävissä."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Unohdetaanko tallennustila?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Kaikki tallennettu sisältö ja aikataulut menetetään."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Lopetetaanko tallennus?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Tallennettu sisältö lisätään kirjastoon."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Tallennus ajastettu – ristiriitoja havaittu"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Tallennus käynnissä – ristiriitoja havaittu"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> tallennetaan"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Tallennetaan: <xliff:g id="CHANNELNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Osia ohjelmasta <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ei tallenneta."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Osia ohjelmista <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ja <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ei tallenneta."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Osia ohjelmista <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ja 1 muusta ajastuksesta ei tallenneta."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Osia ohjelmista <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ja %3$d muusta ajastuksesta ei tallenneta.</item>
+ <item quantity="one">Osia ohjelmista <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ja %3$d muusta ajastuksesta ei tallenneta.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Mitä haluat tallentaa?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Miten pitkään tallennusta jatketaan?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Jo ajastettu"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Sama ohjelma on jo ajastettu nauhoitettavaksi klo <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Jo nauhoitettu"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Tämä ohjelma on jo nauhoitettu. Se on käytettävissä DVR-kirjastossa."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Tallennettua ohjelmaa ei löytynyt."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Aiheeseen liittyvät tallenteet"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ohjelmalla ei ole kuvausta.)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d tallennetta</item>
+ <item quantity="one">%1$d tallenne</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> poistettiin tallennusaikataulusta."</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Tallennetaan osittain virittimen ristiriitojen vuoksi"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ei tallenneta virittimen ristiriitojen vuoksi"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aikataulussa ei ole vielä yhtään nauhoitusta.\nVoit ajastaa nauhoituksen ohjelmaoppaasta."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d tallennusristiriitaa</item>
+ <item quantity="one">%1$d tallennusristiriita</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Sarja-asetukset"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Aloita sarjan tallennus"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Lopeta sarjan tallennus"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Lopetetaanko sarjan tallennus?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Tallennettuja osia voi edelleen katsella DVR:n kirjastossa."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Lopeta"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Yhtään jaksoa ei ole saatavilla.\nNe nauhoitetaan, kun ne ovat saatavilla."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minuuttia)</item>
+ <item quantity="one">(%1$d minuutti) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Tänään"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Huomenna"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Eilen"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> tänään"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> huomenna"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Arvosana"</string>
</resources>
diff --git a/res/values-fr-rCA/arrays.xml b/res/values-fr-rCA/arrays.xml
index 12605879..753019ee 100644
--- a/res/values-fr-rCA/arrays.xml
+++ b/res/values-fr-rCA/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Plein écran"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Toutes les chaînes"</item>
- <item msgid="6897460857821394118">"Famille/Enfants"</item>
- <item msgid="551257741825778215">"Sports"</item>
- <item msgid="452133796804325879">"Magasinage"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Humour"</item>
- <item msgid="7900158429062595471">"Voyage"</item>
- <item msgid="3768998587825611787">"Drame"</item>
- <item msgid="8340620094959282881">"Éducation"</item>
- <item msgid="7396447839483867269">"Animaux/Faune sauvage"</item>
- <item msgid="4738043455148062673">"Actualités"</item>
- <item msgid="7405041316051047427">"Jeux"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Toutes les chaînes"</item>
- <item msgid="7909003973960375395">"Famille/Enfants"</item>
- <item msgid="3185279732911635789">"Sports"</item>
- <item msgid="4704858492065325964">"Magasinage"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Humour"</item>
- <item msgid="3803709976021475052">"Voyage"</item>
- <item msgid="8116747365234169059">"Drame"</item>
- <item msgid="7356447541595315913">"Éducation"</item>
- <item msgid="7511135485827589547">"Animaux/Faune sauvage"</item>
- <item msgid="6961248112238009967">"Actualités"</item>
- <item msgid="6484685553679698447">"Jeux"</item>
- <item msgid="2737158328243183190">"Arts"</item>
- <item msgid="6577176952650166615">"Divertissement"</item>
- <item msgid="7886693831871777617">"Style de vie"</item>
- <item msgid="8145832312485577062">"Musique"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Technologies et sciences"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Toutes les chaînes"</item>
+ <item msgid="928298872841713530">"Famille/Enfants"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Produits"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Humour"</item>
+ <item msgid="6096710741527327836">"Voyages et déplacements"</item>
+ <item msgid="2851882187117833883">"Drame"</item>
+ <item msgid="78492781188719038">"Éducation"</item>
+ <item msgid="7221999662426308394">"Animaux/Faune sauvage"</item>
+ <item msgid="375300513250925001">"Actualités"</item>
+ <item msgid="7746320336582330410">"Jeux"</item>
+ <item msgid="1255741860568329178">"Arts"</item>
+ <item msgid="7603949681065702867">"Divertissement"</item>
+ <item msgid="4453821994746804366">"Style de vie"</item>
+ <item msgid="3488534597567932843">"Musique"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Technologies et sciences"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Chaînes en direct"</item>
diff --git a/res/values-fr-rCA/rating_system_strings.xml b/res/values-fr-rCA/rating_system_strings.xml
index 737e8d2d..03f9c8a1 100644
--- a/res/values-fr-rCA/rating_system_strings.xml
+++ b/res/values-fr-rCA/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 7d3b9900..1fc794e3 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Précédent"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guide des programmes"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nouvelles chaînes"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Aucun lien disponible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Ouvrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Sous-titres"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mode d\'affichage"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sous-catégories"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Entrez votre NIP pour regarder cette chaîne"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Entrez votre NIP pour regarder ce programme"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Ce programme est classé <xliff:g id="RATING">%1$s</xliff:g>. Entrez votre NIP pour regarder ce programme"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Entrez votre NIP"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Créez un NIP pour régler les contrôles parentaux"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Entrez le nouveau NIP"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licences de logiciels libres"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licences de logiciels libres"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Aider à améliorer les chaînes en direct"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Envoyez-nous des données anonymes d\'utilisation et de diagnostic pour nous aider à améliorer Chaîne en direct et à éviter les problèmes de plantage ou de blocage."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Pour regarder cette chaîne, touchez la droite, puis entrez votre NIP."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Pour regarder ce programme, touchez la droite, puis entrez votre NIP."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ce programme est classé « <xliff:g id="RATING">%1$s</xliff:g> ». \nPour le regarder, touchez la droite, puis entrez votre NIP."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio uniquement"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Signal faible"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Aucune connexion Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Impossible de visionner cette chaîne jusqu\'à <xliff:g id="END_TIME_1">%1$s</xliff:g>, car un autre programme est en cours d\'enregistrement. \n\nAppuyez sur la touche de droite pour modifier l\'horaire d\'enregistrement.</item>
+ <item quantity="other">Impossible de visionner cette chaîne jusqu\'à <xliff:g id="END_TIME_1">%1$s</xliff:g>, car d\'autres programmes sont en cours d\'enregistrement. \n\nAppuyez sur la touche de droite pour modifier l\'horaire d\'enregistrement.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sans titre"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Chaîne bloquée"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nouveau"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Aucune chaîne disponible"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nouveau"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Non configuré"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Trouver plus de sources"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Parcourir les applications qui offrent des chaînes en direct"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Trouver plus de sources"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Parcourir les applications qui offrent des chaînes en direct"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nouvelles sources de chaînes disponibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Découvrez des chaînes issues de nouvelles sources.\nConfigurez-les dès maintenant, ou plus tard, à l\'aide du paramètre « Sources des chaînes »."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurer maintenant"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Toutes les chaînes source sont masquées.\nSélectionnez au moins une chaîne à regarder."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Indisponibilité inattendue de la vidéo"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"La touche RETOUR concerne l\'appareil connecté. Appuyez sur le bouton ACCUEIL pour quitter."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Les chaînes en direct ne sont pas prises en charge sur cet appareil avec Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Les chaînes en direct ont besoin de l\'autorisation nécessaire pour lire les programmes télé."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configurez vos sources"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Avec Télé en direct, diffusez les chaînes proposées par des applications comme s\'il s\'agissait de chaînes de télévision traditionnelles. \n\nCommencez par configurer les sources de chaînes déjà installées. Vous pouvez également parcourir la boutique Google Play Store et rechercher d\'autres applications qui proposent des chaînes en direct."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Enregistrements et horaires"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 heure"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 heures"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Récents"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Prévu"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Série"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Autres"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Impossible d\'enregistrer ce canal"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Impossible d\'enregistrer ce programme."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Vous avez planifié l\'enregistrement du programme « <xliff:g id="PROGRAMNAME">%1$s</xliff:g> »"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Enregistrement du programme <xliff:g id="PROGRAMNAME">%1$s</xliff:g> de maintenant jusqu\'à <xliff:g id="ENDTIME">%2$s</xliff:g>…"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Calendrier complet"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">%1$d jour suivant</item>
+ <item quantity="other">%1$d jours suivants</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minute</item>
+ <item quantity="other">%1$d minutes</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d nouvel enregistrement</item>
+ <item quantity="other">%1$d nouveaux enregistrements</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d enregistrement</item>
+ <item quantity="other">%1$d enregistrements</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d enreg. programmé</item>
+ <item quantity="other">%1$d enreg. programmés</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Regarder"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Lire du début"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reprendre la lecture"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Supprimer"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Supprimer les enregistrements"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reprendre"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Voir l\'horaire"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"En savoir plus"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Supprim. enregistr."</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Sélectionnez les épisodes que vous souhaitez supprimer. Ceux-ci ne peuvent pas être récupérés une fois cette opération effectuée."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Aucun enregistrement à supprimer."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Sélect. les épisodes visionnés"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Sélectionner tous les épisodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Désélect. tous les épisodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Vous avez regardé <xliff:g id="WATCHED">%1$d</xliff:g> minute(s) sur <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Vous avez regardé <xliff:g id="WATCHED">%1$d</xliff:g> seconde(s) sur <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Jamais visionnés"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d épisode sur %2$d est supprimé.</item>
+ <item quantity="other">%1$d épisodes sur %2$d sont supprimés.</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorité"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"La plus élevée"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"La plus faible"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Non. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Chaînes"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Tout"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Choisissez la priorité"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Quand il y a trop de programmes à enregistrer en même temps, seuls ceux aux priorités les plus élevées sont enregistrés."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Enregistrer"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Les enregistrements ponctuels ont la plus haute priorité"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Annuler"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Annuler"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Supprimer"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Arrêter"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Voir le programme d\'enregistrement"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Uniquement ce programme"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"de maintenant à <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"La série au complet…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Planifier quand même"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Enregistrez celui-ci à la place"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Annuler cet enregistrement"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Regarder"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Enregistrable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Enregistrement programmé"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflit d\'enregistrement"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Enregistrement en cours"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Échec de l\'enregistrement"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lecture des programmes pour créer des horaires d\'enregistrement…"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Lecture des programmes en cours…"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Le magnétoscope numérique a besoin de plus d\'espace"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Vous pourrez enregistrer des programmes avec le magnétoscope numérique. Toutefois, l\'espace de stockage est insuffisant sur votre appareil pour que le magnétoscope numérique puisse fonctionner actuellement. Veuillez brancher un disque externe d\'au moins <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> Go ou suivez les étapes pour le formater en tant qu\'espace de stockage de l\'appareil."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Espace de stockage manquant"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Une partie de l\'espace de stockage utilisé par le magnétoscope numérique est manquante. Veuillez connecter de nouveau le disque externe que vous avez utilisé auparavant afin de réactiver le magnétoscope numérique. Vous pouvez également supprimer cet espace de stockage s\'il n\'est plus disponible."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Supprimer l\'espace de stockage?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tous vos contenus enregistrés et vos enregistrements planifiés seront perdus."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Arrêter l\'enregistrement?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Le contenu enregistré sera gardé."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Enregistrement planifié, mais d\'autres enregistrements sont prévus en même temps."</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"L\'enregistrement a commencé, mais d\'autres enregistrements sont prévus en même temps"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Le programme « <xliff:g id="PROGRAMNAME">%1$s</xliff:g> » sera enregistré."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> est en cours d\'enregistrement."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Certaines parties de « <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> » ne seront pas enregistrées."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Certaines parties de « <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> » et de « <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> » ne seront pas enregistrées."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Certaines parties de « <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> », « <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> » et d\'un autre programme ne seront pas enregistrées."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Certaines parties de « <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> », « <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> » et %4$d autre programme ne seront pas enregistrées.</item>
+ <item quantity="other">Certaines parties de « <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> », « <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> » et %4$d autres programmes ne seront pas enregistrées.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Que souhaitez-vous enregistrer?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Pendant combien de temps voulez-vous enregistrer?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Déjà planifié"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Vous avez déjà planifié l\'enregistrement de ce programme à <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Déjà enregistré"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Ce programme a déjà été enregistré. Il est accessible dans la bibliothèque du magnétoscope numérique."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programme enregistré non trouvé."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Enregistrements connexes"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Programme sans description)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d enregistrement</item>
+ <item quantity="other">%1$d enregistrements</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> a été supprimé du programme d\'enregistrement"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Sera partiellement enreg. en raison de conflits de syntoniseur"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ne sera pas enregistré en raison de conflits de syntoniseur"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aucun enregistrement n\'est encore planifié.\nVous pouvez programmer des enregistrements à partir du guide des programmes."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d conflit d\'enregistrement</item>
+ <item quantity="other">%1$d conflits d\'enregistrement</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Paramètres de la série"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Commencer à enregistrer la série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Arrêter d\'enregistrer la série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Arrêter l\'enregistrement de la série?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Les épisodes enregistrés resteront accessibles dans la bibliothèque du magnétoscope numérique."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Arrêter"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Aucun épisode.\nLes épisodes seront enregistrés lorsqu\'ils seront diffusés."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minute)</item>
+ <item quantity="other">(%1$d minutes)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Aujourd\'hui"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Demain"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Hier"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Aujourd\'hui, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Demain, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Note"</string>
</resources>
diff --git a/res/values-fr/arrays.xml b/res/values-fr/arrays.xml
index bce4a116..c893079f 100644
--- a/res/values-fr/arrays.xml
+++ b/res/values-fr/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Plein écran"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Toutes les chaînes"</item>
- <item msgid="6897460857821394118">"Famille/Enfants"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Achats"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Humour"</item>
- <item msgid="7900158429062595471">"Voyage"</item>
- <item msgid="3768998587825611787">"Drame"</item>
- <item msgid="8340620094959282881">"Éducation"</item>
- <item msgid="7396447839483867269">"Animaux/Faune sauvage"</item>
- <item msgid="4738043455148062673">"Actualités"</item>
- <item msgid="7405041316051047427">"Jeux"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Toutes les chaînes"</item>
- <item msgid="7909003973960375395">"Famille/Enfants"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Achats"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Humour"</item>
- <item msgid="3803709976021475052">"Voyage"</item>
- <item msgid="8116747365234169059">"Drame"</item>
- <item msgid="7356447541595315913">"Éducation"</item>
- <item msgid="7511135485827589547">"Animaux/Faune sauvage"</item>
- <item msgid="6961248112238009967">"Actualités"</item>
- <item msgid="6484685553679698447">"Jeux"</item>
- <item msgid="2737158328243183190">"Arts"</item>
- <item msgid="6577176952650166615">"Divertissements"</item>
- <item msgid="7886693831871777617">"Style de vie"</item>
- <item msgid="8145832312485577062">"Musique"</item>
- <item msgid="1345789204804308580">"Contenu premium"</item>
- <item msgid="2736680312770771994">"Technologie/Science"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Toutes les chaînes"</item>
+ <item msgid="928298872841713530">"Famille/Enfants"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Humour"</item>
+ <item msgid="6096710741527327836">"Voyage"</item>
+ <item msgid="2851882187117833883">"Drame"</item>
+ <item msgid="78492781188719038">"Enseignement"</item>
+ <item msgid="7221999662426308394">"Animaux/Faune sauvage"</item>
+ <item msgid="375300513250925001">"Actualités"</item>
+ <item msgid="7746320336582330410">"Jeux"</item>
+ <item msgid="1255741860568329178">"Arts"</item>
+ <item msgid="7603949681065702867">"Divertissement"</item>
+ <item msgid="4453821994746804366">"Style de vie"</item>
+ <item msgid="3488534597567932843">"Musique"</item>
+ <item msgid="7452153120614274095">"Haut de gamme"</item>
+ <item msgid="8215762047341133299">"Technologie/Science"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"TV en direct"</item>
diff --git a/res/values-fr/rating_system_strings.xml b/res/values-fr/rating_system_strings.xml
index 97cbad73..4c1d1a55 100644
--- a/res/values-fr/rating_system_strings.xml
+++ b/res/values-fr/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 96133a8e..c140aa62 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Précédent"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guide des programmes"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nouvelles chaînes disponibles"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Aucun lien disponible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Ouvrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Sous-titres"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mode d\'affichage"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sous-catégories"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Saisir votre code d\'accès pour regarder cette chaîne"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Saisir votre code d\'accès pour regarder ce programme"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Classification de ce programme : <xliff:g id="RATING">%1$s</xliff:g>. Saisissez votre code pour le regarder."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Saisir votre code d\'accès"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Créer un code d\'accès pour paramétrer le contrôle parental"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Saisir le nouveau code d\'accès"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licences Open Source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licences Open Source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Contribuer à l\'amélioration de l\'application Chaînes en direct"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Envoyez-nous des données anonymes d\'utilisation et de diagnostic pour nous aider à améliorer TV en direct et à éviter les problèmes de plantage ou de blocage."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Pour regarder cette chaîne, appuyez sur le bouton droit, puis saisissez votre code d\'accès."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Pour regarder ce programme, appuyez sur la droite, puis saisissez votre code d\'accès."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Classification de ce programme : <xliff:g id="RATING">%1$s</xliff:g>.\nPour le regarder, appuyez sur la touche droite, puis saisissez votre code d\'accès."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio uniquement"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Signal faible"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Aucune connexion Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Impossible de lire cette chaîne jusqu\'à <xliff:g id="END_TIME_1">%1$s</xliff:g>, car une autre chaîne est en cours d\'enregistrement. \n\nAppuyez sur le bouton droit pour modifier le planning d\'enregistrement.</item>
+ <item quantity="other">Impossible de lire cette chaîne jusqu\'à <xliff:g id="END_TIME_1">%1$s</xliff:g>, car d\'autres chaînes sont en cours d\'enregistrement. \n\nAppuyez sur le bouton droit pour modifier le planning d\'enregistrement.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sans titre"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Chaîne bloquée"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nouvelle"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Aucune chaîne disponible"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nouveau"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Non configurée"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Découvrir plus de sources"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Parcourir les applications qui proposent des chaînes en direct"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Découvrir plus de sources"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Parcourir les applications qui proposent des chaînes en direct"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nouvelles sources de chaînes disponibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Découvrez des chaînes issues de nouvelles sources.\nConfigurez-les dès maintenant, ou plus tard, à l\'aide du paramètre \"Sources des chaînes\"."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurer"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Toutes les chaînes source sont masquées.\nSélectionnez au moins une chaîne à regarder."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Indisponibilité inattendue de la vidéo"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"La touche RETOUR concerne l\'appareil connecté. Appuyez sur le bouton ACCUEIL pour quitter."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"L\'application Chaînes en direct n\'est pas compatible avec les appareils équipés d\'Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"L\'application Chaînes en direct a besoin d\'une autorisation pour accéder au programme TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configurez vos sources."</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Avec TV en direct, regardez en streaming les chaînes proposées par des applications comme s\'il s\'agissait de chaînes de télévision traditionnelles. \n\nCommencez par configurer les sources de chaînes déjà installées. Vous pouvez également parcourir le Google Play Store et rechercher d\'autres applications qui proposent des chaînes en direct."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Enregistrements et plannings"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 heure"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 heures"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Récents"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Planifiés"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Séries"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Autres"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Impossible d\'enregistrer la chaîne."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Impossible d\'enregistrer le programme."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Vous avez planifié l\'enregistrement du programme \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\"."</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Enregistrement de \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" de maintenant jusqu\'à <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Agenda complet"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">%1$d jour suivant</item>
+ <item quantity="other">%1$d jours suivants</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minute</item>
+ <item quantity="other">%1$d minutes</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d nouvel enregistrement</item>
+ <item quantity="other">%1$d nouv. enregistrements</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d enregistrement</item>
+ <item quantity="other">%1$d enregistrements</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d enregistr. planifié</item>
+ <item quantity="other">%1$d enregistr. planifiés</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Regarder"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Lire depuis le début"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reprendre la lecture"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Supprimer"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Supprimer les enregistrements"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reprendre"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Saison <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Voir planning"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Lire la suite"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Suppr. enregistrements"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Sélectionnez les épisodes que vous souhaitez supprimer. Ceux-ci ne peuvent pas être récupérés une fois cette opération effectuée."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Aucun enregistrement à supprimer."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Sélectionner épisodes regardés"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Sélectionner tous les épisodes"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Désélectionner tous épisodes"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Vous avez regardé <xliff:g id="WATCHED">%1$d</xliff:g> minute(s) sur <xliff:g id="DURATION">%2$d</xliff:g>."</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Vous avez regardé <xliff:g id="WATCHED">%1$d</xliff:g> seconde(s) sur <xliff:g id="DURATION">%2$d</xliff:g>."</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Jamais regardés"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d épisode sur %2$d est supprimé.</item>
+ <item quantity="other">%1$d épisodes sur %2$d sont supprimés.</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorité"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"La plus élevée"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"La plus faible"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Numéro <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Chaînes"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Toutes"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Sélectionner la priorité"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Lorsqu\'il y a trop de programmes à enregistrer simultanément, seuls les programmes aux priorités les plus élevées sont enregistrés."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Enregistrer"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Les enregistrements ponctuels ont la plus haute priorité."</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Annuler"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Annuler"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Supprimer"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Arrêter"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Voir planning d\'enregistrement"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Ce programme uniquement"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"De maintenant jusqu\'à <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"La série complète"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Planifier quand même"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Enregistrer ce programme"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Annuler cet enregistrement"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Regarder"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Enregistrable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Enregistrement programmé"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflit d\'enregistrement"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Enregistrement…"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Échec de l\'enregistrement"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lecture des programmes pour créer des plannings d\'enregistrement…"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Lecture des programmes…"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Le magnétoscope numérique a besoin de plus d\'espace"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Vous pourrez enregistrer des programmes avec le magnétoscope numérique. Toutefois, l\'espace de stockage est insuffisant sur votre appareil pour que le magnétoscope numérique puisse fonctionner actuellement. Veuillez brancher un disque externe d\'au moins <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> Go ou suivre les étapes pour le formater en tant qu\'espace de stockage de l\'appareil."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Espace de stockage manquant"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Une partie de l\'espace de stockage utilisé par le magnétoscope numérique est manquante. Veuillez connecter de nouveau le disque externe que vous avez utilisé auparavant afin de réactiver le magnétoscope numérique. Vous pouvez également supprimer cet espace de stockage s\'il n\'est plus disponible."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Supprimer l\'espace de stockage ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tous vos contenus enregistrés et vos enregistrements planifiés seront perdus."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Arrêter l\'enregistrement ?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Le contenu enregistré sera sauvegardé."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Enregistrement planifié, mais d\'autres enregistrements sont prévus en même temps."</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"L\'enregistrement a commencé, mais présente des conflits"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Le programme \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" sera enregistré."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"La chaîne \"<xliff:g id="CHANNELNAME">%1$s</xliff:g>\" est en cours d\'enregistrement."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Certaines parties du programme \"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>\" ne seront pas enregistrées."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Certaines parties des programmes \"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\" et \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" ne seront pas enregistrées."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Certaines parties des programmes \"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\" et \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" et d\'un autre programme ne seront pas enregistrées."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Certaines parties de \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", de \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" et de %3$d autre programme ne seront pas enregistrées.</item>
+ <item quantity="other">Certaines parties de \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", de \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" et de %3$d autres programmes ne seront pas enregistrées.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Que voulez-vous enregistrer ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Pendant combien de temps souhaitez-vous enregistrer la chaîne ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Déjà planifié"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Vous avez déjà planifié l\'enregistrement de ce programme à <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Déjà enregistré"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Ce programme a déjà été enregistré. Il est disponible dans la bibliothèque DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programme enregistré introuvable."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Enregistrements associés"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Programme sans description)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d enregistrement</item>
+ <item quantity="other">%1$d enregistrements</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"\"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" supprimé du programme d\'enregistrement"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Ne sera que partiellement enregistré (conflit de tuners)."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ne sera pas enregistré en raison d\'un conflit de tuners."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aucun enregistrement n\'est encore planifié.\nVous pouvez programmer des enregistrements à partir du guide des programmes."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d conflit d\'enregistrement</item>
+ <item quantity="other">%1$d conflits d\'enregistrement</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Paramètres de la série"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Lancer enregistrement série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Arrêter enregistr. série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Arrêter l\'enregistrement de la série ?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Les épisodes enregistrés resteront disponibles dans la bibliothèque DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Arrêter"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Aucun épisode disponible.\nLes épisodes seront enregistrés lorsqu\'ils seront disponibles."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minute)</item>
+ <item quantity="other">(%1$d minutes)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Aujourd\'hui"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Demain"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Hier"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> aujourd\'hui"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> demain"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Score"</string>
</resources>
diff --git a/res/values-gl-rES/arrays.xml b/res/values-gl-rES/arrays.xml
index e9a308fa..0bbc3853 100644
--- a/res/values-gl-rES/arrays.xml
+++ b/res/values-gl-rES/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Completa"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Todas as canles"</item>
- <item msgid="6897460857821394118">"Familiar/infantil"</item>
- <item msgid="551257741825778215">"Deportes"</item>
- <item msgid="452133796804325879">"Compras"</item>
- <item msgid="3296058637230163031">"Películas"</item>
- <item msgid="1054540282883891201">"Comedia"</item>
- <item msgid="7900158429062595471">"Viaxe"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Educación"</item>
- <item msgid="7396447839483867269">"Animais/vida salvaxe"</item>
- <item msgid="4738043455148062673">"Noticias"</item>
- <item msgid="7405041316051047427">"Xogos"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Todas as canles"</item>
- <item msgid="7909003973960375395">"Familiar/infantil"</item>
- <item msgid="3185279732911635789">"Deportes"</item>
- <item msgid="4704858492065325964">"Compras"</item>
- <item msgid="6083795019290250078">"Películas"</item>
- <item msgid="8302638329222449550">"Comedia"</item>
- <item msgid="3803709976021475052">"Viaxe"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Educación"</item>
- <item msgid="7511135485827589547">"Animais/vida salvaxe"</item>
- <item msgid="6961248112238009967">"Noticias"</item>
- <item msgid="6484685553679698447">"Xogos"</item>
- <item msgid="2737158328243183190">"Arte"</item>
- <item msgid="6577176952650166615">"Entretemento"</item>
- <item msgid="7886693831871777617">"Estilo de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"Estrea"</item>
- <item msgid="2736680312770771994">"Ciencia e tecnoloxía"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Todas as canles"</item>
+ <item msgid="928298872841713530">"Familiar/infantil"</item>
+ <item msgid="2751606947569857164">"Deportes"</item>
+ <item msgid="7345749789651321496">"Compras"</item>
+ <item msgid="167201149441442173">"Películas"</item>
+ <item msgid="525966731464264290">"Comedia"</item>
+ <item msgid="6096710741527327836">"Viaxes"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educación"</item>
+ <item msgid="7221999662426308394">"Animais/vida salvaxe"</item>
+ <item msgid="375300513250925001">"Noticias"</item>
+ <item msgid="7746320336582330410">"Xogos"</item>
+ <item msgid="1255741860568329178">"Arte"</item>
+ <item msgid="7603949681065702867">"Entretemento"</item>
+ <item msgid="4453821994746804366">"Estilo de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"Estrea"</item>
+ <item msgid="8215762047341133299">"Ciencia e tecnoloxía"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"TV en directo"</item>
diff --git a/res/values-gl-rES/rating_system_strings.xml b/res/values-gl-rES/rating_system_strings.xml
index c320636f..20456b34 100644
--- a/res/values-gl-rES/rating_system_strings.xml
+++ b/res/values-gl-rES/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-gl-rES/strings.xml b/res/values-gl-rES/strings.xml
index dc1624a4..7ce0ac2d 100644
--- a/res/values-gl-rES/strings.xml
+++ b/res/values-gl-rES/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guía de programas"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Novas canles dispoñib."</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Sen ligazón dispoñible"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtítulos"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Modo visualiz."</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subclasificacións"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Introduce o teu PIN para ver esta canle"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Introduce o teu PIN para ver este programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Este programa está clasificado como <xliff:g id="RATING">%1$s</xliff:g>. Para velo, introduce o teu PIN"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Introduce o teu PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Para definir controis parentais, crea un PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Introduce o novo PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licenzas de código aberto"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licenzas de código aberto"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versión"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Axudar a mellorar Canles en directo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Comparte datos de uso e de diagnóstico anónimos con Google para que poidamos mellorar a TV en directo e evitar bloqueos e fallos."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Para ver esta canle, preme na tecla cara á dereita e introduce o PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Para ver esta programa, preme na tecla cara á dereita e introduce o PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Este programa está clasificado como <xliff:g id="RATING">%1$s</xliff:g>.\nPara ver esta programa, preme na tecla cara á dereita e introduce o PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Só audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Sinal feble"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Non hai conexión a Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Esta canle non se pode reproducir ata as <xliff:g id="END_TIME_1">%1$s</xliff:g> porque se están gravando outras canles. \n\nPreme na tecla cara á dereita para axustar o programa de gravación.</item>
+ <item quantity="one">Esta canle non se pode reproducir ata as <xliff:g id="END_TIME_0">%1$s</xliff:g> porque se está gravando outra canle. \n\nPreme na tecla cara á dereita para axustar o programa de gravación.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sen título"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canle bloqueada"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Novas"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Non hai canles dispoñibles"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Novo"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Sen configurar"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Obter máis fontes"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Examinar aplicacións que ofrecen canles en directo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Obter máis fontes"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Examina aplicacións que ofrecen canles en directo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Novas fontes de canles dispoñibles"</string>
<string name="new_sources_description" msgid="749649005588426813">"Hai novas fontes de canles que teñen canles para ofrecer.\nConfigúraas agora ou faino máis tarde nos axustes das fontes de canles."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurar agora"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Todas as canles de orixe están ocultas.\nSelecciona polo menos unha canle para ver."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"O vídeo deixou de estar dispoñible de forma inesperada"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"A tecla Atrás aplícase ao dispositivo conectado. Preme o botón de inicio para saír."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"As canles en directo non son compatibles neste dispositivo con Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"As canles en directo necesitan permiso para ler a programación da televisión."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configura as túas fontes"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"As canles en directo combinan a experiencia das canles de televisión tradicionais coas canles de emisión que proporcionan as aplicacións. \n\nComeza configurando as fontes de canles que xa están instaladas ou ben examina Google Play Store para obter máis aplicacións que ofrezan canles en directo."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Gravacións e programacións"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutos"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutos"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 horas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recentes"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programados"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Series"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Outros"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Non se pode gravar a canle."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Non se pode gravar o programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Programouse a gravación de <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Gravarase <xliff:g id="PROGRAMNAME">%1$s</xliff:g> desde agora ata as <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programación completa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d días</item>
+ <item quantity="one">%1$d día</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutos</item>
+ <item quantity="one">%1$d minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d gravacións novas</item>
+ <item quantity="one">%1$d gravación nova</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d gravacións</item>
+ <item quantity="one">%1$d gravación</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d gravacións programadas</item>
+ <item quantity="one">%1$d gravación programada</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Visualizar"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproducir desde o inicio"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Retomar reprodución"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Eliminar"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Eliminar gravacións"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Retomar"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Tempada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ver programac."</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Máis información"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Eliminar gravacións"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecciona os vídeos que queres eliminar e ten en conta que non se poden recuperar unha vez eliminados."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Non hai gravacións para eliminar."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Seleccionar episodios vistos"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Seleccionar todos os episodios"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Desmarcar todos os episodios"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> minutos vistos"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> segundos vistos"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Gravacións nunca vistas"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">Elimináronse %1$d de %2$d episodios</item>
+ <item quantity="one">Eliminouse %1$d de %2$d episodio</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioridade"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Máis alta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Máis baixa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Non. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canles"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Calquera"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Seleccionar prioridade"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Cando hai demasiados programas para gravar á vez, só se gravarán os programas con máis prioridade."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Gardar"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"As gravacións realizadas unha soa vez teñen máis prioridade"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancelar"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancelar"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Borrar"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Deter"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ver programación de gravación"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Só este programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"agora - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Toda a serie…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programar de todas formas"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Gravar isto no seu lugar"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancelar esta gravación"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Visualizar agora"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Gravable"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Gravación programada"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflito de gravación"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Gravando"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Erro na gravación"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lendo programas para crear programacións de gravacións"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Lendo programas"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"O DVR precisa máis almacenamento"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Poderás gravar programas con DVR. Non obstante, o teu dispositivo non ten almacenamento suficiente para que funcione DVR. Conecta unha unidade externa de <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB ou máis e sigue os pasos para formatala como almacenamento do dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Falta o almacenamento"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Falta parte do almacenamento que utiliza DVR. Conecta a unidade externa que utilizaches antes para volver activar DVR. Tamén podes decidir borrar o almacenamento se xa non está dispoñible."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Queres borrar o almacenamento?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Perderase toda a programación e o contido gravados."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Queres deter a gravación?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Gardarase o contido gravado."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Programouse a gravación, pero presenta conflitos"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Iniciouse a gravación pero presenta conflitos"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Gravarase <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Estase gravando <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Non se gravarán algunhas partes de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Non se gravarán algunhas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> e <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Non se gravarán algunhas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> e unha programación máis."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Non se gravarán algunhas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> e %3$d programacións máis.</item>
+ <item quantity="one">Non se gravarán algunhas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> e %3$d programación máis.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Que che gustaría gravar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Canto tempo queres gravar?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Xa se programou"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Xa se programou a gravación do mesmo programa para a seguinte hora: <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Xa está gravado"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Este programa xa está gravado e está dispoñible na mediateca de DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Non se atopou o programa gravado."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Gravacións relacionadas"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Non hai descrición do programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d gravacións</item>
+ <item quantity="one">%1$d gravación</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Eliminouse <xliff:g id="PROGRAMNAME">%1$s</xliff:g> da programación de gravación"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Gravarase parcialmente debido aos conflitos co sintonizador."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Non se gravará debido aos conflitos co sintonizador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Aínda non hai gravacións programadas.\nPodes programalas desde a guía de programas."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d conflitos de gravación</item>
+ <item quantity="one">%1$d conflito de gravación</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Configuración da serie"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Iniciar gravación serie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Deter gravación da serie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Queres deter a gravación da serie?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Os episodios gravados seguirán dispoñibles na mediateca de DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Deter"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Non hai episodios dispoñibles.\nGravaranse unha vez que estean dispoñibles."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutos)</item>
+ <item quantity="one">(%1$d minuto) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hoxe"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Mañá"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Onte"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> hoxe"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> mañá"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puntuación"</string>
</resources>
diff --git a/res/values-hi/arrays.xml b/res/values-hi/arrays.xml
index 5d91d9f2..37e4222c 100644
--- a/res/values-hi/arrays.xml
+++ b/res/values-hi/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"पूर्ण"</item>
<item msgid="8568284598210500589">"ज़ूम करें"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"सभी चैनल"</item>
- <item msgid="6897460857821394118">"परिवार/बच्चे"</item>
- <item msgid="551257741825778215">"खेलकूद"</item>
- <item msgid="452133796804325879">"शॉपिंग"</item>
- <item msgid="3296058637230163031">"फ़िल्में"</item>
- <item msgid="1054540282883891201">"हास्य"</item>
- <item msgid="7900158429062595471">"यात्रा"</item>
- <item msgid="3768998587825611787">"ड्रामा"</item>
- <item msgid="8340620094959282881">"शिक्षा"</item>
- <item msgid="7396447839483867269">"पशु/वन्य जीवन"</item>
- <item msgid="4738043455148062673">"समाचार"</item>
- <item msgid="7405041316051047427">"गेमिंग"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"सभी चैनल"</item>
- <item msgid="7909003973960375395">"परिवार/बच्चे"</item>
- <item msgid="3185279732911635789">"खेलकूद"</item>
- <item msgid="4704858492065325964">"शॉपिंग"</item>
- <item msgid="6083795019290250078">"फ़िल्में"</item>
- <item msgid="8302638329222449550">"हास्य"</item>
- <item msgid="3803709976021475052">"यात्रा"</item>
- <item msgid="8116747365234169059">"ड्रामा"</item>
- <item msgid="7356447541595315913">"शिक्षा"</item>
- <item msgid="7511135485827589547">"पशु/वन्य जीवन"</item>
- <item msgid="6961248112238009967">"समाचार"</item>
- <item msgid="6484685553679698447">"गेमिंग"</item>
- <item msgid="2737158328243183190">"कला"</item>
- <item msgid="6577176952650166615">"मनोरंजन"</item>
- <item msgid="7886693831871777617">"जीवनशैली"</item>
- <item msgid="8145832312485577062">"संगीत"</item>
- <item msgid="1345789204804308580">"प्रीमियर"</item>
- <item msgid="2736680312770771994">"तकनीक/विज्ञान"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"सभी चैनल"</item>
+ <item msgid="928298872841713530">"परिवार/बच्चे"</item>
+ <item msgid="2751606947569857164">"खेलकूद"</item>
+ <item msgid="7345749789651321496">"खरीदारी"</item>
+ <item msgid="167201149441442173">"फ़िल्में"</item>
+ <item msgid="525966731464264290">"हास्य"</item>
+ <item msgid="6096710741527327836">"यात्रा"</item>
+ <item msgid="2851882187117833883">"नाटक"</item>
+ <item msgid="78492781188719038">"शिक्षा"</item>
+ <item msgid="7221999662426308394">"पशु/वन्य जीवन"</item>
+ <item msgid="375300513250925001">"समाचार"</item>
+ <item msgid="7746320336582330410">"गेमिंग"</item>
+ <item msgid="1255741860568329178">"कला"</item>
+ <item msgid="7603949681065702867">"मनोरंजन"</item>
+ <item msgid="4453821994746804366">"जीवनशैली"</item>
+ <item msgid="3488534597567932843">"संगीत"</item>
+ <item msgid="7452153120614274095">"प्रीमियर"</item>
+ <item msgid="8215762047341133299">"तकनीक/विज्ञान"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"लाइव चैनल"</item>
diff --git a/res/values-hi/rating_system_strings.xml b/res/values-hi/rating_system_strings.xml
index 09419c68..33bfab2b 100644
--- a/res/values-hi/rating_system_strings.xml
+++ b/res/values-hi/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 09d4567a..d6db8677 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"पिछला"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"कार्यक्रम गाइड"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"नए चैनल उपलब्‍ध हैं"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"कोई लिंक उपलब्ध नहीं है"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> खोलें"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"उपशीर्षक"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"प्रदर्शन मोड"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"उप-रेटिंग"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"इस चैनल को देखने के लिए अपना पिन डालें"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"इस कार्यक्रम को देखने के लिए अपना पिन डालें"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"इस कार्यक्रम को <xliff:g id="RATING">%1$s</xliff:g> रेट किया गया है. यह कार्यक्रम देखने के लिए अपना पिन डालें"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"अपना पिन डालें"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"अभिभावकीय नियंत्रण सेट करने के लिए, पिन बनाएं"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"नया पिन डालें"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ओपन सोर्स लाइसेंस"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ओपन सोर्स लाइसेंस"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"वर्शन"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"लाइव चैनल बेहतर बनाने में सहायता करें"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google के साथ अनाम उपयोग और निदान डेटा साझा करें ताकि हम लाइव चैनल को बेहतर बना सकें और क्रैश होने तथा फ़्रीज होने जैसी समस्‍याओं को रोक सकें."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"इस चैनल को देखने के लिए, दाईं ओर दबाएं और अपना पिन डालें"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"इस कार्यक्रम को देखने के लिए, दाईं ओर दबाएं और अपना पिन डालें"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"इस कार्यक्रम को <xliff:g id="RATING">%1$s</xliff:g> रेट किया गया है.\nइस कार्यक्रम को देखने के लिए, Right दबाएं और अपना पिन डालें."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"केवल ऑडियो"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"कमज़ोर सिग्नल"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"कोई इंटरनेट कनेक्शन नहीं"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">यह चैनल <xliff:g id="END_TIME_1">%1$s</xliff:g> तक नहीं चलाया जा सकता क्योंकि अन्य चैनल रिकॉर्ड हो रहे हैं. \n\nरिकॉर्डिंग शेड्यूल समायोजित करने के लिए दाएं दबाएं.</item>
+ <item quantity="other">यह चैनल <xliff:g id="END_TIME_1">%1$s</xliff:g> तक नहीं चलाया जा सकता क्योंकि अन्य चैनल रिकॉर्ड हो रहे हैं. \n\nरिकॉर्डिंग शेड्यूल समायोजित करने के लिए दाएं दबाएं.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"कोई शीर्षक नहीं"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"चैनल अवरोधित"</string>
<string name="setup_category_new" msgid="2899355289563443627">"नए"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"कोई चैनल उपलब्‍ध नहीं है"</string>
<string name="setup_input_new" msgid="3337725672277046798">"नया"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"सेट नहीं किया गया है"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"अधिक स्रोत प्राप्‍त करें"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"ऐसे ऐप्‍स ब्राउज़ करें जो लाइव चैनल ऑफ़र करते हैं"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"अधिक स्रोत प्राप्‍त करें"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"ऐसे ऐप्लिकेशन ब्राउज़ करें जो लाइव चैनल ऑफ़र करते हैं"</string>
<string name="new_sources_title" msgid="3878933676500061895">"नए चैनल स्रोत उपलब्ध हैं"</string>
<string name="new_sources_description" msgid="749649005588426813">"नए चैनल स्रोत में ऑफ़र किए जाने वाले चैनल मौजूद हैं.\nउन्हें अभी सेट करें या इसे बाद में चैनल स्रोत सेटिंग में करें."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"अभी सेट करें"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"सभी स्रोत चैनल छिपे हुए हैं.\nदेखने के लिए कम से कम कोई एक चैनल चुनें."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"वीडियो अनपेक्षित रूप से अनुपलब्ध है"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK कुंजी कनेक्ट किए गए डिवाइस के लिए है. बाहर निकलने के लिए HOME बटन दबाएं."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop वाले इस डिवाइस पर लाइव चैनल समर्थित नहीं है."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"लाइव चैनल को टीवी सूची पढ़ने के लिए अनुमति की आवश्यकता होती है."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"अपने स्रोत सेट करें"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"लाइव चैनल परंपरागत टीवी चैनल के अनुभव के साथ ऐप्स के द्वारा प्रदान किए जाने वाले स्ट्रीमिंग चैनल अनुभव को संयोजित करते हैं. \n\nपहले से इंस्टॉल किए गए चैनल स्रोतों को सेट करके प्रारंभ करें. या लाइव चैनल उपलब्ध कराने वाले अधिक ऐप्स के लिए Google Play स्टोर ब्राउज़ करें."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"रिकॉर्डिंग और शेड्यूूल"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 मिनट"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 मिनट"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 घंटा"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 घंटे"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"नवीनतम"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"शेड्यूल की गई"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"श्रृंखला"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"अन्य"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"चैनल रिकॉर्ड नहीं किया जा सकता."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"कार्यक्रम रिकॉर्ड नहीं किया जा सकता."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> को रिकॉर्ड करने के लिए शेड्यूल किया गया है"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> की अभी से <xliff:g id="ENDTIME">%2$s</xliff:g> तक की रिकॉर्डिंग"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"पूर्ण शेड्यूल"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">अगले %1$d दिन</item>
+ <item quantity="other">अगले %1$d दिन</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d मिनट</item>
+ <item quantity="other">%1$d मिनट</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d नईं रिकॉर्डिंग</item>
+ <item quantity="other">%1$d नईं रिकॉर्डिंग</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d रिकॉर्डिंग</item>
+ <item quantity="other">%1$d रिकॉर्डिंग</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d रिकॉर्डिंग शेड्यूल की गईं</item>
+ <item quantity="other">%1$d रिकॉर्डिंग शेड्यूल की गईं</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"देखें"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"शुरू से चलाएं"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"चलाना फिर शुरू करें"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"हटाएं"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"रिकॉर्डिंग हटाएं"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"फिर शुरू करें"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"सीज़न <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"शेड्यूल देखें"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"अधिक पढ़ें"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"रिकॉर्डिंग हटाएं"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"वे एपिसोड चुनें जिन्हें आप हटाना चाहते हैं. हटाए जाने के बाद वे वापस नहीं मिल सकते हैं."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"हटाने के लिए कोई रिकॉर्डिंग नहीं है."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"देखे गए एपिसोड चुनें"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"सभी एपिसोड चुनें"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"सभी एपिसोड का चयन हटाएं"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> में से <xliff:g id="WATCHED">%1$d</xliff:g> मिनट देेखा गया"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> में से <xliff:g id="WATCHED">%1$d</xliff:g> सेकंड देखा गया"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"कभी नहीं देखी गई"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%2$d में से %1$d एपिसोड हटाए गए</item>
+ <item quantity="other">%2$d में से %1$d एपिसोड हटाए गए</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"प्राथमिकता"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"उच्चतम"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"निम्नतम"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"संख्या <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"चैनल"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"कोई भी"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"प्राथमिकता चुनें"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"जब एक ही समय पर कई सारे कार्यक्रम रिकॉर्ड करने हों, तो केवल उच्च प्राथमिकता वाले कार्यक्रम रिकॉर्ड किए जाएंगे."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"सहेजें"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"एक बार की रिकॉर्डिंग को उच्च प्राथमिकता दी जाती है"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"रद्द करें"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"रद्द करें"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"भूल जाएं"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"रोकें"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"रिकॉर्डिंग शेड्यूल देखें"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"यह एक ही कार्यक्रम"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"अब - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"पूरी श्रृंखला…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"फिर भी शेड्यूल करें"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"उसके बजाय इसे रिकॉर्ड करें"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"यह रिकॉर्डिंग रद्द करें"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"अभी देखें"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"रिकॉर्ड करने योग्य"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"रिकॉर्डिंग शेड्यूल की गई"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"रिकॉर्डिंग संबंधी विरोध"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"रिकॉर्ड हो रहा है"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"रिकॉर्डिंग विफल रही"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"रिकॉर्डिंग शेड्यूल बनाने के लिए कार्यक्रम पढ़े जा रहे हैं"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"प्रोग्राम पढ़े जा रहे हैं"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR को अधिक जगह की आवश्यकता है"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"आप DVR से प्रोग्राम रिकॉर्ड कर पाएंगे. हालांकि इस समय आपके डिवाइस पर DVR के काम करने के लिए पर्याप्त जगह नहीं है. कृपया एक बाहरी डिवाइस कनेक्ट करें जिसमें <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB या उससे अधिक जगह हो और उसे डिवाइस जगह के रूप में फ़ॉर्मेट करने के चरणों का अनुसरण करें."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"जगह मिल नहीं रही है"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR द्वारा उपयोग की गई कुछ जगह मिल नहीं रही है. कृपया DVR को दोबारा सक्षम करने से पहले अपनी उपयोग की हुई बाहरी डिस्क कनेक्ट करें. वैकल्पिक रूप से, यदि जगह अब उपलब्ध नहीं है तो आप उसे भूल जाना चुन सकते हैं."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"जगह को भूल जाएं?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"आपकी रिकॉर्ड की हुई सभी सामग्री और शेड्यूल खो जाएंगे."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"रिकॉर्डिंग बंद करें?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"रिकॉर्ड की गई सामग्री सहेज ली जाएगी."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"रिकॉर्डिंग शेड्यूल की गई लेकिन विरोध मौजूद हैं"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"रिकॉर्डिंग शुरू हो गई है लेकिन उसमें विरोध मौजूद हैं"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> रिकॉर्ड किया जाएगा."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> रिकॉर्ड किया जा रहा है."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> के कुछ भाग रिकॉर्ड नहीं किए जाएंगे."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> और <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> के कुछ भाग रिकॉर्ड नहीं किए जाएंगे."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> और एक अन्य शेड्यूल के कुछ भाग रिकॉर्ड नहीं किए जाएंगे."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> और %3$d अन्य शेड्यूल के कुछ भाग रिकॉर्ड नहीं किए जाएंगे.</item>
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> और %3$d अन्य शेड्यूल के कुछ भाग रिकॉर्ड नहीं किए जाएंगे.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"आप क्या रिकॉर्ड करना चाहेंगे?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"आप कितनी देर तक रिकॉर्ड करना चाहते हैं?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"पहले ही शेेड्यूल किया जा चुका है"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"इसी कार्यक्रम को <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> बजे रिकॉर्ड करने के लिए पहले ही शेड्यूल किया जा चुका है."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"पहले ही रिकॉर्ड हो चुका है"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"यह कार्यक्रम पहले ही रिकॉर्ड हो चुका है. वह DVR लाइब्रेरी में उपलब्ध है."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"रिकॉर्ड किया गया प्रोग्राम नहीं मिला."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"संबंधित रिकॉर्डिंग"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(कोई कार्यक्रम वर्णन नहीं)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d रिकॉर्डिंग</item>
+ <item quantity="other">%1$d रिकॉर्डिंग</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> को रिकॉर्डिंग शेड्यूल से निकाला गया"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ट्यूनर संबंधी विरोधों के कारण आंशिक रूप से रिकॉर्ड होगा."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ट्यूनर संबंधी विरोधों के कारण रिकॉर्ड नहीं किया जाएगा."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"अभी कोई भी रिकॉर्डिंग शेड्यूल नहीं की गई है.\nआप कार्यक्रम मार्गदर्शिका से रिकॉर्डिंग शेड्यूल कर सकते हैं."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d रिकॉर्डिंग विरोध</item>
+ <item quantity="other">%1$d रिकॉर्डिंग विरोध</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"श्रृंखला की सेटिंग"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"श्रृंखला रिकॉर्डिंग शुरू करें"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"श्रृंखला रिकॉर्डिंग रोकें"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"श्रृंखला की रिकॉर्डिंग रोकें?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"रिकॉर्ड किए गए एपिसोड DVR लाइब्रेरी में उपलब्ध रहेंगे."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"रोकें"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"कोई भी एपिसोड उपलब्ध नहीं है.\nएपिसोड उपलब्ध होने पर उन्हें रिकॉर्ड कर लिया जाएगा."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d मिनट)</item>
+ <item quantity="other">(%1$d मिनट)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"आज"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"कल"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"कल"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> आज"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> कल"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"स्कोर"</string>
</resources>
diff --git a/res/values-hr/arrays.xml b/res/values-hr/arrays.xml
index 6a8b8709..463686b8 100644
--- a/res/values-hr/arrays.xml
+++ b/res/values-hr/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Cijeli"</item>
<item msgid="8568284598210500589">"Zumiranje"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Svi kanali"</item>
- <item msgid="6897460857821394118">"Obitelj/djeca"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Kupnja"</item>
- <item msgid="3296058637230163031">"Filmovi"</item>
- <item msgid="1054540282883891201">"Komedija"</item>
- <item msgid="7900158429062595471">"Putovanja"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Obrazovanje"</item>
- <item msgid="7396447839483867269">"Životinjski svijet"</item>
- <item msgid="4738043455148062673">"Vijesti"</item>
- <item msgid="7405041316051047427">"Igre"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Svi kanali"</item>
- <item msgid="7909003973960375395">"Obitelj/djeca"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Kupnja"</item>
- <item msgid="6083795019290250078">"Filmovi"</item>
- <item msgid="8302638329222449550">"Komedija"</item>
- <item msgid="3803709976021475052">"Putovanja"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Obrazovanje"</item>
- <item msgid="7511135485827589547">"Životinjski svijet"</item>
- <item msgid="6961248112238009967">"Vijesti"</item>
- <item msgid="6484685553679698447">"Igre"</item>
- <item msgid="2737158328243183190">"Umjetnost"</item>
- <item msgid="6577176952650166615">"Zabava"</item>
- <item msgid="7886693831871777617">"Životni stil"</item>
- <item msgid="8145832312485577062">"Glazba"</item>
- <item msgid="1345789204804308580">"Premijere"</item>
- <item msgid="2736680312770771994">"Tehnologija/znanost"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Svi kanali"</item>
+ <item msgid="928298872841713530">"Obitelj/djeca"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Kupnja"</item>
+ <item msgid="167201149441442173">"Filmovi"</item>
+ <item msgid="525966731464264290">"Komedija"</item>
+ <item msgid="6096710741527327836">"Putovanja"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Obrazovanje"</item>
+ <item msgid="7221999662426308394">"Životinjski svijet"</item>
+ <item msgid="375300513250925001">"Vijesti"</item>
+ <item msgid="7746320336582330410">"Igre"</item>
+ <item msgid="1255741860568329178">"Umjetnost"</item>
+ <item msgid="7603949681065702867">"Zabava"</item>
+ <item msgid="4453821994746804366">"Životni stil"</item>
+ <item msgid="3488534597567932843">"Glazba"</item>
+ <item msgid="7452153120614274095">"Premijere"</item>
+ <item msgid="8215762047341133299">"Tehnologija/znanost"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"TV kanali uživo"</item>
diff --git a/res/values-hr/rating_system_strings.xml b/res/values-hr/rating_system_strings.xml
index 3e7377a7..c8a10da4 100644
--- a/res/values-hr/rating_system_strings.xml
+++ b/res/values-hr/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 52ba8831..596a3f96 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Prethodno"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programski vodič"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Dostupni su novi kanali"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nema dostupnih veza"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Otvori <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Titlovi"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Način prikaza"</string>
@@ -125,6 +124,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Podocjene"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Unesite PIN da biste gledali ovaj kanal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Unesite PIN da biste gledali ovaj program"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Ovaj program ima ocjenu <xliff:g id="RATING">%1$s</xliff:g>. Da biste ga gledali, unesite PIN"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Unesite PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Da biste postavili roditeljski nadzor, stvorite PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Unesite novi PIN"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licence otvorenog izvornog koda"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licence otvorenog izvornog koda"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Verzija"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Pomogni poboljšati Kanale uživo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Dijelite anonimne podatke o upotrebi i dijagnostici s Googleom kako bismo poboljšali TV kanale uživo i spriječili poteškoće kao što su rušenja i zamrzavanja."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Da biste gledali ovaj kanal, pritisnite desno pa unesite PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Da biste gledali ovaj program, pritisnite desno pa unesite PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ovaj program ima ocjenu <xliff:g id="RATING">%1$s</xliff:g>.\nDa biste ga gledali, pritisnite desni gumb pa unesite PIN."</string>
@@ -159,6 +157,11 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Samo zvuk"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Slab signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nema internetske veze"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Ovaj se kanal ne može prikazivati do <xliff:g id="END_TIME_1">%1$s</xliff:g> jer se snimaju drugi kanali. \n\nPritisnite desno da biste prilagodili raspored snimanja.</item>
+ <item quantity="few">Ovaj se kanal ne može prikazivati do <xliff:g id="END_TIME_1">%1$s</xliff:g> jer se snimaju drugi kanali. \n\nPritisnite desno da biste prilagodili raspored snimanja.</item>
+ <item quantity="other">Ovaj se kanal ne može prikazivati do <xliff:g id="END_TIME_1">%1$s</xliff:g> jer se snimaju drugi kanali. \n\nPritisnite desno da biste prilagodili raspored snimanja.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Bez naslova"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal blokiran"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Novi"</string>
@@ -171,8 +174,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nema dostupnih kanala"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Novi"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nije postavljen"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Više izvora"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Pregledajte aplikacije koje nude kanale uživo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Više izvora"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Pregledajte aplikacije koje nude TV kanale uživo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Dostupni su novi izvori kanala"</string>
<string name="new_sources_description" msgid="749649005588426813">"Novi izvori kanala nude kanale.\nMožete ih postaviti odmah ili kasnije u postavkama izvora kanala."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Postavi sada"</string>
@@ -190,8 +193,172 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Skriveni su kanali svih izvora.\nOdaberite barem jedan kanal za gledanje."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videozapis neočekivano nije dostupan"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Tipka NATRAG namijenjena je za povezani uređaj. Pritisnite tipku POČETNA za izlaz."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Kanali uživo nisu podržani na ovom uređaju s Androidom Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Kanali uživo trebaju dopuštenje za čitanje TV unosa."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Postavite izvore"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"TV kanali uživo kombiniraju doživljaj tradicionalnih TV kanala sa strujanjem kanala koje nude aplikacije. \n\nDa biste započeli, postavite izvore kanala koji su već instalirani. U Trgovini Google Play možete potražiti još aplikacija koje nude kanale uživo."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Snimanja i rasporedi"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuta"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuta"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 sat"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 sata"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nedavno"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Zakazano"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serija"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Ostalo"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanal se ne može snimati."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Emisija se ne može snimati."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – snimanje je programirano"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Snimanje emisije <xliff:g id="PROGRAMNAME">%1$s</xliff:g> od sad do <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Cijeli raspored"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Sljedeći %1$d dan</item>
+ <item quantity="few">Sljedeća %1$d dana</item>
+ <item quantity="other">Sljedećih %1$d dana</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minuta</item>
+ <item quantity="few">%1$d minute</item>
+ <item quantity="other">%1$d minuta</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d nova snimka</item>
+ <item quantity="few">%1$d nove snimke</item>
+ <item quantity="other">%1$d novih snimki</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d snimka</item>
+ <item quantity="few">%1$d snimke</item>
+ <item quantity="other">%1$d snimki</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d snimanje zakazano</item>
+ <item quantity="few">%1$d snimanja zakazana</item>
+ <item quantity="other">%1$d snimanja zakazano</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Gledaj"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproduciraj od početka"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Nastavi reprodukciju"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Izbriši"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Izbriši snimke"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Nastavi"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Prikaz rasporeda"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Pročitajte više"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Brisanje snimki"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Odaberite epizode koje želite izbrisati. Nakon brisanja nećete ih moći vratiti."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nema snimki za brisanje."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Odaberi odgledane epizode"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Odaberi sve epizode"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Poništi odabir svih epizoda"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Odgledano <xliff:g id="WATCHED">%1$d</xliff:g> od <xliff:g id="DURATION">%2$d</xliff:g> min"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Odgledano <xliff:g id="WATCHED">%1$d</xliff:g> od <xliff:g id="DURATION">%2$d</xliff:g> s"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nikad gledano"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">Brisanje %1$d od %2$d epizode</item>
+ <item quantity="few">Brisanje %1$d od %2$d epizode</item>
+ <item quantity="other">Brisanje %1$d od %2$d epizoda</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Najviši"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Najniži"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Br. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanali"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Bilo koji"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Odabir prioriteta"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Kada će se se istovremeno trebati snimati previše emisija, snimit će se samo one s najvišim prioritetom."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Spremi"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Jednokratna snimanja imaju najviši prioritet"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Odustani"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Odustani"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Zaboravi"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Zaustavi"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Prikaz rasporeda snimanja"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Samo jedna epizoda"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"sada – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Cijela serija…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Svejedno programiraj"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Snimi ovo"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Otkaži snimanje"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Pogledajte odmah"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Snimanje moguće"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Snimanje programirano"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Sukob rasporeda snimanja"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Snimanje"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Snimanje nije uspjelo"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Čitanje emisija za izradu rasporeda snimanja"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Čitanje emisija"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR treba više prostora za pohranu"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Moći ćete snimati programe DVR-om. No na vašem uređaju trenutačno nema dovoljno prostora za pohranu da bi DVR funkcionirao. Priključite vanjski disk od najmanje <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB i formatirajte ga kao pohranu uređaja prema uputama."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Pohrana nedostaje"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Nedostaje dio pohrane kojom se koristi DVR. Da biste ponovo omogućili DVR, povežite ga s vanjskim diskom koji ste upotrebljavali prethodno. Ako ta pohrana više nije dostupna, možete odabrati da je uređaj zaboravi."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Zaboraviti pohranu?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Izgubit ćete sve snimljene sadržaje i programirana snimanja."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Želite li zaustaviti snimanje?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Snimljeni će se sadržaj spremiti."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Snimanje je programirano, ali ima sukoba"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Snimanje je započelo, ali ima sukoba"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Snimit će se <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Snimanje emisije <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Neki dijelovi emisije <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> neće se snimiti."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Neki dijelovi emisija <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> neće se snimiti."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Neki dijelovi emisija <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> te još jedna emisija neće se snimiti."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Neki dijelovi emisija <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> te još %3$d emisija neće se snimiti.</item>
+ <item quantity="few">Neki dijelovi emisija <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> te još %3$d emisije neće se snimiti.</item>
+ <item quantity="other">Neki dijelovi emisija <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> te još %3$d emisija neće se snimiti.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Što želite snimiti?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Koliko dugo želite snimati?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Već programirano"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Snimanje tog programa već je programirano za <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Već snimljeno"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Taj je program već snimljen. Dostupan je u zbirci DVR-a."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Snimljeni program nije pronađen."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Povezane snimke"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nema opisa programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d snimka</item>
+ <item quantity="few">%1$d snimke</item>
+ <item quantity="other">%1$d snimki</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> – uklonjeno iz rasporeda snimanja"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Snimit će se djelomično zbog sukoba na prijemniku."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Neće se snimiti zbog sukoba na prijemniku."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Još nije programirano nijedno snimanje.\nSnimanje možete programirati u programskom vodiču."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d sukob snimanja</item>
+ <item quantity="few">%1$d sukoba snimanja</item>
+ <item quantity="other">%1$d sukoba snimanja</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Postavke serije"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Pokreni snimanje serije"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Zaustavi snimanje serije"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Želite li zaustaviti snimanje serije?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Snimljene epizode ostat će dostupne u zbirci DVR-a."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Zaustavi"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nije dostupna nijedna epizoda.\nEpizode će se snimiti kada budu dostupne."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minuta)</item>
+ <item quantity="few">(%1$d minute)</item>
+ <item quantity="other">(%1$d minuta)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Danas"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Sutra"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Jučer"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> danas"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> sutra"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Rezultat"</string>
</resources>
diff --git a/res/values-hu/arrays.xml b/res/values-hu/arrays.xml
index eb73d3ba..3eba7e77 100644
--- a/res/values-hu/arrays.xml
+++ b/res/values-hu/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Teljes"</item>
<item msgid="8568284598210500589">"Nagyítás/kicsinyítés"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Minden csatorna"</item>
- <item msgid="6897460857821394118">"Családi/gyermek"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Vásárlás"</item>
- <item msgid="3296058637230163031">"Filmek"</item>
- <item msgid="1054540282883891201">"Vígjátékok"</item>
- <item msgid="7900158429062595471">"Utazás"</item>
- <item msgid="3768998587825611787">"Dráma"</item>
- <item msgid="8340620094959282881">"Oktatás"</item>
- <item msgid="7396447839483867269">"Állatok/vadvilág"</item>
- <item msgid="4738043455148062673">"Hírek"</item>
- <item msgid="7405041316051047427">"Játékok"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Minden csatorna"</item>
- <item msgid="7909003973960375395">"Családi/gyermek"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Vásárlás"</item>
- <item msgid="6083795019290250078">"Filmek"</item>
- <item msgid="8302638329222449550">"Vígjátékok"</item>
- <item msgid="3803709976021475052">"Utazás"</item>
- <item msgid="8116747365234169059">"Dráma"</item>
- <item msgid="7356447541595315913">"Oktatás"</item>
- <item msgid="7511135485827589547">"Állatok/vadvilág"</item>
- <item msgid="6961248112238009967">"Hírek"</item>
- <item msgid="6484685553679698447">"Játékok"</item>
- <item msgid="2737158328243183190">"Művészetek"</item>
- <item msgid="6577176952650166615">"Szórakozás"</item>
- <item msgid="7886693831871777617">"Életstílus"</item>
- <item msgid="8145832312485577062">"Zene"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Technika/tudomány"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Összes csatorna"</item>
+ <item msgid="928298872841713530">"Család/gyermekek"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Vásárlás"</item>
+ <item msgid="167201149441442173">"Filmek"</item>
+ <item msgid="525966731464264290">"Vígjáték"</item>
+ <item msgid="6096710741527327836">"Utazás"</item>
+ <item msgid="2851882187117833883">"Dráma"</item>
+ <item msgid="78492781188719038">"Oktatás"</item>
+ <item msgid="7221999662426308394">"Állatok/vadvilág"</item>
+ <item msgid="375300513250925001">"Hírműsor"</item>
+ <item msgid="7746320336582330410">"Játék"</item>
+ <item msgid="1255741860568329178">"Művészetek"</item>
+ <item msgid="7603949681065702867">"Szórakozás"</item>
+ <item msgid="4453821994746804366">"Életstílus"</item>
+ <item msgid="3488534597567932843">"Zene"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Technika/tudomány"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Élő csatornák"</item>
diff --git a/res/values-hu/rating_system_strings.xml b/res/values-hu/rating_system_strings.xml
index 9282b334..42912179 100644
--- a/res/values-hu/rating_system_strings.xml
+++ b/res/values-hu/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 937d1c42..d007a135 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Vissza"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Műsorfüzet"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Új csatornák"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nincs elérhető link"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> megnyitása"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Feliratok"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Megjelenítés"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Alértékelések"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"A csatorna megtekintéséhez PIN-kód szükséges"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"A műsor megtekintéséhez PIN-kód szükséges"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"A műsor besorolása: <xliff:g id="RATING">%1$s</xliff:g>. A megtekintéséhez adja meg PIN-kódját."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN-kód megadása"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Szülői felügyelet beállításához hozzon létre egy PIN kódot."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Új PIN-kód megadása"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Nyílt forráskódú licencek"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Nyílt forráskódú licencek"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Verzió"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Segítek az élő csatornák javításában"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Névtelen használati és diagnosztikai adatok megosztása a Google-lal, hogy továbbfejleszthessük az Élő csatornák szolgáltatást, és megelőzhessük a rendszer összeomlását és lefagyását."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"A csatorna megtekintéséhez nyomja meg a jobbra gombot, majd adja meg a PIN kódot"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"A műsor megtekintéséhez nyomja meg a jobbra gombot, majd adja meg a PIN kódot"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"A műsor besorolása: <xliff:g id="RATING">%1$s</xliff:g>.\nA megtekintéséhez nyomja meg a jobbra gombot, majd adja meg a PIN kódot."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Csak hang"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Gyenge jel"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nincs internetkapcsolat"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Ez a csatorna nem játszható le <xliff:g id="END_TIME_1">%1$s</xliff:g>-ig, mert más csatornák rögzítése folyamatban van. \n\nNyomja meg a Jobbra gombot a rögzítési ütemterv módosításához.</item>
+ <item quantity="one">Ez a csatorna nem játszható le <xliff:g id="END_TIME_0">%1$s</xliff:g>-ig, mert egy másik csatorna rögzítése folyamatban van. \n\nNyomja meg a Jobbra gombot a rögzítési ütemterv módosításához.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Nincs cím"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Csatorna letiltva"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Új"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nincs elérhető csatorna"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Új"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nincs beállítva"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"További források"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Élő csatornákat szolgáltató alkalmazások tallózása"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"További források"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Élő csatornákat szolgáltató alkalmazások tallózása"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Új csatornaforrások állnak rendelkezésre"</string>
<string name="new_sources_description" msgid="749649005588426813">"Új csatornaforrások új csatornákat kínálnak.\nBeállíthatja őket most, vagy később is megteheti a csatornaforrások beállításában."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Beállítás most"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Minden forráscsatorna rejtve van.\nVálasszon ki legalább egy csatornát, amelyet meg szeretne tekinteni."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"A videó váratlanul nem érhető el."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"A BACK gomb a csatlakoztatott eszközzel használható. A kilépéshez nyomja meg a HOME gombot."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Ezen az Android Lollipopot futtató eszközön nem támogatott az Élő csatornák alkalmazás."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Az Élő csatornák alkalmazásnak engedélyre van szüksége a tévéműsorok listázásának olvasásához."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Források beállítása"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Az Élő csatornák szolgáltatás a hagyományos tévézési élményt ötvözi az alkalmazások által kínált streamelhető csatornákkal. \n\nKezdésként állítsa be a már telepített csatornaforrásokat, vagy tallózzon a Google Play Áruházban az élő csatornákat kínáló alkalmazásokért."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Felvételek és ütemtervek"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 perc"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 perc"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 óra"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 óra"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Legutóbbiak"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ütemezve"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Sorozatok"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Továbbiak"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"A csatornát nem lehet rögzíteni."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"A programot nem lehet rögzíteni."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"A(z) <xliff:g id="PROGRAMNAME">%1$s</xliff:g> rögzítése beütemezve"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"A(z) <xliff:g id="PROGRAMNAME">%1$s</xliff:g> rögzítése mostantól a következő időpontig: <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Teljes rögzítési ütemezés"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">A következő %1$d nap</item>
+ <item quantity="one">A következő %1$d nap</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d perc</item>
+ <item quantity="one">%1$d perc</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d új felvétel</item>
+ <item quantity="one">%1$d új felvétel</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d felvétel</item>
+ <item quantity="one">%1$d felvétel</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d rögzítés beütemezve</item>
+ <item quantity="one">%1$d rögzítés beütemezve</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Megtekintés"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Lejátszás az elejétől"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Lejátszás folytatása"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Törlés"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Felvételek törlése"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Folytatás"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. évad"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ütemezés megtekintése"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Továbbiak"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Felvételek törlése"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Válassza ki a törölni kívánt epizódokat. A műveletet nem lehet visszavonni."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nincsenek törölhető felvételek."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"A megtekintettek kijelölése"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Az összes epizód kijelölése"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Az összes epizód kijelölésének visszavonása"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g>/<xliff:g id="WATCHED">%1$d</xliff:g> perc megtekintve"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g>/<xliff:g id="WATCHED">%1$d</xliff:g> másodperc megtekintve"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nem megtekintett"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d/%1$d epizód törölve</item>
+ <item quantity="one">%2$d/%1$d epizód törölve</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritási szint"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Legmagasabb"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Legalacsonyabb"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"<xliff:g id="RANK">%1$d</xliff:g>."</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Csatornák"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Bármelyik"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Prioritás kiválasztása"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Ha túl sok rögzítendő műsort állít be ugyanarra az időtartamra, kizárólag a magasabb prioritással rendelkezőket rögzíti a rendszer."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Mentés"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Az egyszeri rögzítések rendelkeznek a legmagasabb prioritással"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Mégse"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Mégse"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Elfelejt"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Leállítás"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Rögzítési ütemterv megtekintése"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Ezt az egy műsort"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"most – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Az egész sorozatot…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Beütemezés mindenképpen"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Inkább ez legyen rögzítve"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"A rögzítés törlése"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Nézze meg most"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Felvehető"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"A felvétel beállítva"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Ütközés más felvétellel"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Rögzítés"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"A felvétel nem sikerült"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Műsorok beolvasása a rögzítési ütemterv kialakításához"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Műsorok beolvasása"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"A DVR számára több tárhely szükséges"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"A DVR segítségével műsorokat vehet fel. Azonban eszközén nincs elég szabad tárhely a DVR működéséhez. Csatlakoztasson egy legalább <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB tárhellyel rendelkező külső meghajtót, majd kövesse az utasításokat, hogy az eszköz tárhelyévé formázhassa."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Hiányzó tárhely"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"A DVR által használt tárhely bizonyos része hiányzik. Kérjük, csatlakoztassa a korábban használt külső meghajtót a DVR ismételt engedélyezéséhez. Másik megoldásként megadhatja a rendszernek, hogy ne emlékezzen többé erre a tárhelyre, ha már nem áll a rendelkezésére."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"A rendszer ne emlékezzen többé erre a tárhelyre?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Az összes rögzített tartalom és ütemterv elvész."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Leállítja a rögzítést?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"A rögzített tartalmat elmenti a rendszer."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"A rögzítést beállította, de az ütközik más műsorokkal"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"A rögzítés elindult, de az ütközik más műsorokkal"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"A(z) <xliff:g id="PROGRAMNAME">%1$s</xliff:g> rögzítve lesz."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"A(z) <xliff:g id="CHANNELNAME">%1$s</xliff:g> rögzítése folyamatban van."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"A(z) <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> bizonyos részei nem lesznek rögzítve."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"A(z) <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> és a(z) <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> bizonyos részei nem lesznek rögzítve."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"A(z) <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, a(z) <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> és egy további műsor bizonyos részei nem lesznek rögzítve."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">A(z) <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, a(z) <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> és %3$d további műsor bizonyos részei nem lesznek rögzítve.</item>
+ <item quantity="one">A(z) <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, a(z) <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> és %3$d további műsor bizonyos részei nem lesznek rögzítve.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Mit szeretne rögzíteni?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Milyen hosszan szeretné folytatni a rögzítést?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Már be van ütemezve"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Ugyanennek a műsornak a rögzítése már be van ütemezve a következő időpontban: <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Már készült róla felvétel"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Erről a műsorról már készült felvétel, amely a DVR könyvtárban található."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"A rögzített program nem található."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Kapcsolódó felvételek"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nincs programleírás)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d felvétel</item>
+ <item quantity="one">%1$d felvétel</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"A(z) <xliff:g id="PROGRAMNAME">%1$s</xliff:g> eltávolítva a rögzítési ütemezésből"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Csak részben lesz rögzítve tunerproblémák miatt."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Nem lesz rögzítve tunerpoblémák miatt."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Még nincs ütemezett rögzítés.\nEzeket a műsorfüzetben lehet beállítani."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d rögzítési ütközés</item>
+ <item quantity="one">%1$d rögzítési ütközés</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Sorozatbeállítások"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Sorozatrögzítés"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Rögzítés leállítása"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Leállítja a sorozat rögzítését?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"A rögzített részek továbbra is hozzáférhetők lesznek a DVR könyvtárban."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Leállítás"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nincs rendelkezésre álló epizód.\nAz epizódok a megjelenésüket követően lesznek rögzítve."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d perc)</item>
+ <item quantity="one">(%1$d perc) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Ma"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Holnap"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Tegnap"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Ma: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Holnap: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Pontszám"</string>
</resources>
diff --git a/res/values-hy-rAM/arrays.xml b/res/values-hy-rAM/arrays.xml
index 766c779e..5c6f0bfd 100644
--- a/res/values-hy-rAM/arrays.xml
+++ b/res/values-hy-rAM/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Լիցքավորված"</item>
<item msgid="8568284598210500589">"Խոշորացնել"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Բոլոր ալիքները"</item>
- <item msgid="6897460857821394118">"Ընտանիք/Երեխաներ"</item>
- <item msgid="551257741825778215">"Սպորտ"</item>
- <item msgid="452133796804325879">"Գնումներ"</item>
- <item msgid="3296058637230163031">"Ֆիլմեր"</item>
- <item msgid="1054540282883891201">"Կատակերգություն"</item>
- <item msgid="7900158429062595471">"Ճամփորդություն"</item>
- <item msgid="3768998587825611787">"Դրամա"</item>
- <item msgid="8340620094959282881">"Կրթություն"</item>
- <item msgid="7396447839483867269">"Վայրի բնություն"</item>
- <item msgid="4738043455148062673">"Նորություններ"</item>
- <item msgid="7405041316051047427">"Համակարգչային խաղեր"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Բոլոր ալիքները"</item>
- <item msgid="7909003973960375395">"Ընտանիք/Երեխաներ"</item>
- <item msgid="3185279732911635789">"Սպորտ"</item>
- <item msgid="4704858492065325964">"Գնումներ"</item>
- <item msgid="6083795019290250078">"Ֆիլմեր"</item>
- <item msgid="8302638329222449550">"Կատակերգություն"</item>
- <item msgid="3803709976021475052">"Ճամփորդություն"</item>
- <item msgid="8116747365234169059">"Դրամա"</item>
- <item msgid="7356447541595315913">"Կրթություն"</item>
- <item msgid="7511135485827589547">"Վայրի բնություն"</item>
- <item msgid="6961248112238009967">"Նորություններ"</item>
- <item msgid="6484685553679698447">"Համակարգչային խաղեր"</item>
- <item msgid="2737158328243183190">"Արվեստ"</item>
- <item msgid="6577176952650166615">"Ժամանց"</item>
- <item msgid="7886693831871777617">"Ապրելակերպ"</item>
- <item msgid="8145832312485577062">"Երաժշտություն"</item>
- <item msgid="1345789204804308580">"Պրեմիերա"</item>
- <item msgid="2736680312770771994">"Տեխնիկա/Գիտություն"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Բոլոր ալիքները"</item>
+ <item msgid="928298872841713530">"Ընտանիք/Երեխաներ"</item>
+ <item msgid="2751606947569857164">"Սպորտ"</item>
+ <item msgid="7345749789651321496">"Գնումներ"</item>
+ <item msgid="167201149441442173">"Ֆիլմեր"</item>
+ <item msgid="525966731464264290">"Կատակերգություն"</item>
+ <item msgid="6096710741527327836">"Ճամփորդություն"</item>
+ <item msgid="2851882187117833883">"Դրամա"</item>
+ <item msgid="78492781188719038">"Կրթություն"</item>
+ <item msgid="7221999662426308394">"Կենդ./Վայրի բնություն"</item>
+ <item msgid="375300513250925001">"Նորություններ"</item>
+ <item msgid="7746320336582330410">"Համակարգչային խաղեր"</item>
+ <item msgid="1255741860568329178">"Արվեստ"</item>
+ <item msgid="7603949681065702867">"Ժամանց"</item>
+ <item msgid="4453821994746804366">"Ապրելակերպ"</item>
+ <item msgid="3488534597567932843">"Երաժշտություն"</item>
+ <item msgid="7452153120614274095">"Նորույթներ"</item>
+ <item msgid="8215762047341133299">"Տեխնիկա/Գիտություն"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Ուղիղ եթեր"</item>
diff --git a/res/values-hy-rAM/rating_system_strings.xml b/res/values-hy-rAM/rating_system_strings.xml
index 7305b01f..8c69ca7e 100644
--- a/res/values-hy-rAM/rating_system_strings.xml
+++ b/res/values-hy-rAM/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-hy-rAM/strings.xml b/res/values-hy-rAM/strings.xml
index 412902ee..d10652e1 100644
--- a/res/values-hy-rAM/strings.xml
+++ b/res/values-hy-rAM/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Նախորդը"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Ծրագրի ուղեցույց"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Նոր ալիքներ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Հասանելի հղում չկա"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Բացել <xliff:g id="APP_NAME">%1$s</xliff:g>-ը"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Փակ խորագրեր"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Ցուցադրման ռեժիմ"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Ենթավարկանիշեր"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Այս ալիքը դիտելու համար մուտքագրեք PIN-ը"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Այս ծրագիրը դիտելու համա մուտքագրեք PIN-ը"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Այս ծրագիրն ունի տարիքային սահմանափակում՝ <xliff:g id="RATING">%1$s</xliff:g>: Այն դիտելու համար մուտքագրեք PIN կոդը"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Մուտքագրեք ձեր PIN-ը"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ծնողական վերահսկումը կարգավորելու համար PIN կոդ նախադրեք"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Մուտքագրեք նոր PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Բաց կոդով ծրագրակազմի արտոնագրեր"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Բաց կոդով ծրագրաշարի լիցենզիաներ"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Տարբերակ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Օգնել բարելավել «Ուղիղ եթերը»"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google-ին ուղարկեք օգտագործման և ախտորոշման անանուն տվյալներ, որոնք մենք կօգնեն կատարելագործել Live TV-ը և կանխել դրա հետ կապված խնդիրները, օրինակ՝ աշխատանքի խափանումը և սառեցումը:"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Այս կապուղին դիտելու համար սեղմեք Աջ և մուտքագրեք ձեր PIN-ը"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Այս ծրագիրը դիտելու համար սեղմեք Աջ և մուտքագրեք ձեր PIN-ը"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Այս ծրագրի վարկանիշը <xliff:g id="RATING">%1$s</xliff:g> է:\nԱյն դիտելու համար սեղմեք Աջ և մուտքագրեք PIN կոդը:"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Միայն ձայն"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Թույլ ազդանշան"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Համացանցի կապակցում չկա"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">This channel can\'t be played until <xliff:g id="END_TIME_1">%1$s</xliff:g> because other channels are being recorded. \n\nPress Right to adjust recording schedule.</item>
+ <item quantity="other">Այս ալիքը հնարավոր չէ ցուցադրել մինչև <xliff:g id="END_TIME_1">%1$s</xliff:g>-ը, քանի որ ներկայումս տեսագրվում են այլ ալիքներ: \n\nՏեսագրման ժամանակացույցը կարգավորելու համար սեղմեք Աջ կոճակը:</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Անվերնագիր"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Ալիքն արգելափակված է"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Նոր"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ալիքներ չկան"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Նոր"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Կարգավորված չէ"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Ավելացնել այլ աղբյուրներ"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Որոնեք ուղիղ եթեր առաջարկող հավելվածներ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Ավելացնել այլ աղբյուրներ"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Որոնեք ուղիղ եթեր առաջարկող հավելվածներ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Հասանելի են ալիքների նոր աղբյուրներ"</string>
<string name="new_sources_description" msgid="749649005588426813">"Ալիքների նոր աղբյուրները պարունակում են նոր ալիքներ:\nԿարգավորեք դրանք հիմա կամ ավելի ուշ՝ ալիքների աղբյուրների կարգավորումների միջոցով:"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Կարգավորել հիմա"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Բոլոր ալիքները թաքնված են:\nԸնտրեք առնվազն մեկ ալիք:"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Անսպասելի սխալ առաջացավ տեսանյութի ցուցադրման ժամանակ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"«Հետ» կոճակը միացված սարքի համար է: Դուս գալու համար սեղմեք «Գլխավոր» կոճակը:"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Ուղիղ եթերը չի աջակցվում Android Lollipop համակարգով սարքի վրա:"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Հեռուստատեսային ծրագրերը կարդալու համար ուղիղ եթերին թույլտվություն է անհրաժեշտ:"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Կարգավորեք աղբյուրները"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Ուղիղ եթերը համատեղում է ավանդական հեռուստաալիքները և հավելվածների կողմից հոսքային եղանակով հեռարձակվող ալիքները: \n\nՍկսեք արդեն իսկ տեղադրված ալիքների աղբյուրները կարգավորելուց կամ Google Play Խանութում որոնեք ուղիղ եթեր առաջարկող այլ հավելվածներ:"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Տեսագրում և ժամանակացույցեր"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 րոպե"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 րոպե"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ժամ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ժամ"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Վերջինները"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ծրագրավորված"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Սերիալներ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Այլ"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Հնարավոր չէ տեսագրել այս հեռուստաալիքը:"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Հնարավոր չէ տեսագրել այս ծրագիրը:"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ծրագրի տեսագրումը ծրագրավորվեց"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ծրագրի տեսագրում այս պահից մինչև <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Ամբողջական ժամանակացույց"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Next %1$d days</item>
+ <item quantity="other">%1$d օր</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minutes</item>
+ <item quantity="other">%1$d րոպե</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d new recordings</item>
+ <item quantity="other">%1$d նոր տեսագրություն</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d recordings</item>
+ <item quantity="other">%1$d տեսագրություն</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d recordings scheduled</item>
+ <item quantity="other">Ծրագրավորվել է %1$d տեսագրություն</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Դիտել"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Նվագարկել սկզբից"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Վերսկսել նվագարկումը"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Ջնջել"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Ջնջել տեսագրությունները"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Շարունակել"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Եթերաշրջան <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ժամանակացույց"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Կարդալ ավելին"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Ջնջել տեսագրումները"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Ընտրեք դրվագները, որոնք ցանկանում եք ջնջել: Ջնջելուց հետո դրանք այլևս հնարավոր չի լինի տեսագրել:"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Ջնջելու համար տեսագրումներ չկան"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Նշել դիտված դրվագները"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Նշել բոլոր դրվագները"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Ապանշել բոլոր դրվագները"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> րոպեից դիտվել է <xliff:g id="WATCHED">%1$d</xliff:g>-ը"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> վայրկյանից դիտվել է <xliff:g id="WATCHED">%1$d</xliff:g>-ը"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Երբեք չդիտված"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d of %2$d episodes are deleted</item>
+ <item quantity="other">%2$d դրվագներից %1$d-ը ջնջվել է</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Առաջնահերթություն"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Ամենաբարձր"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Ամենացածր"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Ոչ: <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Հեռուստաալիքներ"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Ցանկացած"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Ընտրեք առաջնահերթությունը"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Եթե միաժամանակ ծրագրավորված է չափազանց շատ ծրագրերի տեսագրում, ապա կտեսագրվեն միայն բարձր առաջնահերթություն ունեցող ծրագրերը:"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Պահել"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Միանգամյա տեսագրումն ունի ամենաբարձր առաջնահերթությունը"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Չեղարկել"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Չեղարկել"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Մոռանալ"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Դադար"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Դիտել տեսագրման ժամանակացույցը"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Միայն այս ծրագիրը"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"այժմ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Ամբողջ սերիալը…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Ծրագրավորել"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Փոխարենը տեսագրել այս ծրագիրը"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Չեղարկել այս տեսագրումը"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Դիտել հիմա"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Հնարավոր է տեսագրել"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Տեսագրումը ծրագրավորված է"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Տեսագրման հակասություն"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Տեսագրում"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Չհաջողվեց տեսագրել"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Ծրագրերի ընթերցում՝ տեսագրության ժամանակացույցեր ստեղծելու համար"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Ծրագրերի ընթերցում"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR-ին ավելի շատ հիշողություն է անհրաժեշտ"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Դուք կկարողանաք տեսագրել ծրագրեր DVR-ի օգնությամբ: Սակայն այս պահին ձեր սարքում DVR-ի աշխատանքի համար անհրաժեշտ բավականաչափ հիշողություն չկա: Միացեք առնվազն <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>ԳԲ հիշողություն ունեցող արտաքին սարք և հետևեք ցուցումներին՝ այն որպես սարքի հիշողություն ձևաչափելու համար:"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Հիշողությունն անհասանելի է"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR-ի կողմից օգտագործվող հիշողության մի մասն անհասանելի է: DVR-ը կրկին ակտիվացնելու համար միացրեք նախկինում օգտագործված արտաքին սարքը: Կարող եք նաև մոռանալ հիշողությունը, եթե այն այևս հասանելի չէ:"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Մոռանա՞լ հիշողությունը:"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Ձեր տեսագրած ամբողջ բովանդակությունը և ժամանակացույցները չեն պահվի:"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Դադարեցնե՞լ տեսագրումը:"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Տեսագրված բովանդակությունը կպահվի:"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Տեսագրումը ծրագրավորվեց, սակայն այն հակասություններ ունի"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Տեսագրումը սկսվել է, սակայն որոշ հակասություններ ունի"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ծրագիրը կտեսագրվի:"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> ալիքը տեսագրվում է:"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ծրագրի որոշ հատվածներ չեն տեսագրվի:"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> և <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ծրագրերի որոշ հատվածներ չեն տեսագրվի:"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ու ևս մեկ ծրագրի որոշ հատվածներ չեն տեսագրվի:"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Some parts of <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> and %3$d more schedules will not be recorded.</item>
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ու ևս %3$d ծրագրի որոշ հատվածներ չեն տեսագրվի:</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ի՞նչ եք ցանկանում տեսագրել:"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Նշեք տեսագրելու տևողությունը"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Արդեն ծրագրավորվել է"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Միևնույն ծրագրի տեսագրումն արդեն ծրագրավորվել է <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>-ին:"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Արդեն տեսագրվել է"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Այս ծրագիրն արդեն տեսագրվել է: Այն հասանելի է DVR դարանում:"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Տեսագրված ծրագիրը չի գտնվել:"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Առնչվող տեսագրություններ"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ծրագիրը նկարագրություն չունի)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d recordings</item>
+ <item quantity="other">%1$d տեսագրություն</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ծրագիրը հեռացվել է տեսագրման ժամանակացույցից"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Ընդունիչների հակասությունների պատճառով կտեսագրվի մասամբ:"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ընդունիչների հակասությունների պատճառով չի տեսագրվի:"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Ծրագրավորված տեսագրումներ դեռ չկան:\nՏեսագրումը կարող եք ծրագրավորել հեռուստահաղորդումների ցանկից:"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d recording conflicts</item>
+ <item quantity="other">Տեսագրման %1$d հակասություն</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Սերիալների կարգավորումներ"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Սկսել սերիալի տեսագրումը"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Դադարեցնել սերիալի տեսագրումը"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Դադարեցնե՞լ սերիալի տեսագրումը:"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Տեսագրված դրվագները հասանելի կմնան միայն DVR դարանում:"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Դադար"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Հասանելի դրվագներ չկան:\nԴրանք կտեսագրվեն հասանելի դառնալուց հետո:"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minutes)</item>
+ <item quantity="other">(%1$d րոպե)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Այսօր"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Վաղը"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Երեկ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Այսօր, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Վաղը, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Գնահատական"</string>
</resources>
diff --git a/res/values-in/arrays.xml b/res/values-in/arrays.xml
index e6d34476..1248c942 100644
--- a/res/values-in/arrays.xml
+++ b/res/values-in/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Penuh"</item>
<item msgid="8568284598210500589">"Perbesar/Perkecil"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Semua saluran"</item>
- <item msgid="6897460857821394118">"Keluarga/Anak-anak"</item>
- <item msgid="551257741825778215">"Olahraga"</item>
- <item msgid="452133796804325879">"Belanja"</item>
- <item msgid="3296058637230163031">"Film"</item>
- <item msgid="1054540282883891201">"Komedi"</item>
- <item msgid="7900158429062595471">"Wisata"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Pendidikan"</item>
- <item msgid="7396447839483867269">"Satwa/Alam Liar"</item>
- <item msgid="4738043455148062673">"Berita"</item>
- <item msgid="7405041316051047427">"Game"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Semua saluran"</item>
- <item msgid="7909003973960375395">"Keluarga/Anak-anak"</item>
- <item msgid="3185279732911635789">"Olahraga"</item>
- <item msgid="4704858492065325964">"Belanja"</item>
- <item msgid="6083795019290250078">"Film"</item>
- <item msgid="8302638329222449550">"Komedi"</item>
- <item msgid="3803709976021475052">"Wisata"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Pendidikan"</item>
- <item msgid="7511135485827589547">"Satwa/Alam Liar"</item>
- <item msgid="6961248112238009967">"Berita"</item>
- <item msgid="6484685553679698447">"Game"</item>
- <item msgid="2737158328243183190">"Seni"</item>
- <item msgid="6577176952650166615">"Hiburan"</item>
- <item msgid="7886693831871777617">"Gaya Hidup"</item>
- <item msgid="8145832312485577062">"Musik"</item>
- <item msgid="1345789204804308580">"Tayang Perdana"</item>
- <item msgid="2736680312770771994">"Teknologi/Sains"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Semua saluran"</item>
+ <item msgid="928298872841713530">"Keluarga/Anak-anak"</item>
+ <item msgid="2751606947569857164">"Olahraga"</item>
+ <item msgid="7345749789651321496">"Belanja"</item>
+ <item msgid="167201149441442173">"Film"</item>
+ <item msgid="525966731464264290">"Komedi"</item>
+ <item msgid="6096710741527327836">"Perjalanan"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Pendidikan"</item>
+ <item msgid="7221999662426308394">"Satwa/Alam Liar"</item>
+ <item msgid="375300513250925001">"Berita"</item>
+ <item msgid="7746320336582330410">"Game"</item>
+ <item msgid="1255741860568329178">"Seni"</item>
+ <item msgid="7603949681065702867">"Hiburan"</item>
+ <item msgid="4453821994746804366">"Gaya Hidup"</item>
+ <item msgid="3488534597567932843">"Musik"</item>
+ <item msgid="7452153120614274095">"Tayang Perdana"</item>
+ <item msgid="8215762047341133299">"Teknologi/Sains"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Saluran TV Langsung"</item>
diff --git a/res/values-in/rating_system_strings.xml b/res/values-in/rating_system_strings.xml
index b4023172..2dfcb39b 100644
--- a/res/values-in/rating_system_strings.xml
+++ b/res/values-in/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 6be2f7d6..662cfc89 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Sebelumnya"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Panduan program"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Tersedia saluran baru"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Tidak ada tautan yang tersedia"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Buka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Teks"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mode tayang"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subperingkat"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Masukkan PIN untuk menonton saluran ini"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Masukkan PIN untuk menonton program ini"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Program ini memiliki rating <xliff:g id="RATING">%1$s</xliff:g>. Masukkan PIN untuk menonton program ini"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Masukkan PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Untuk menyetel kontrol induk, buat PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Masukkan PIN baru"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Lisensi sumber terbuka"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Lisensi sumber terbuka"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versi"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Bantu meningkatkan Saluran Siaran Langsung"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Bagikan data penggunaan dan diagnostik anonim kepada Google agar kami dapat membuat Saluran TV Langsung jadi lebih baik, serta mencegah masalah seperti aplikasi mogok dan berhenti tiba-tiba."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Untuk menonton saluran ini, tekan Kanan dan masukkan PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Untuk menonton program ini, tekan Kanan dan masukkan PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Program ini diberi rating <xliff:g id="RATING">%1$s</xliff:g>.\nUntuk menonton program ini, tekan Panah Kanan dan masukkan PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio saja"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Sinyal lemah"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Tidak ada sambungan internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Saluran ini tidak dapat diputar sampai <xliff:g id="END_TIME_1">%1$s</xliff:g> karena saluran lain sedang direkam. \n\nTekan Kanan untuk menyesuaikan jadwal perekaman.</item>
+ <item quantity="one">Saluran ini tidak dapat diputar hingga <xliff:g id="END_TIME_0">%1$s</xliff:g> karena saluran lain sedang direkam. \n\nTekan Kanan untuk menyesuaikan jadwal perekaman.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Tanpa judul"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Saluran diblokir"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Baru"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Tidak ada saluran yang tersedia"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Baru"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Belum disiapkan"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Dapatkan sumber lainnya"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Jelajahi aplikasi yang menawarkan saluran TV langsung"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Dapatkan sumber lainnya"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Jelajahi aplikasi yang menawarkan saluran TV langsung"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Sumber saluran baru tersedia"</string>
<string name="new_sources_description" msgid="749649005588426813">"Sumber saluran baru menawarkan saluran.\nSiapkan sekarang atau nanti di setelan sumber saluran."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Siapkan sekarang"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Semua saluran asal disembunyikan.\nPilih setidaknya satu saluran untuk ditonton."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video tiba-tiba tidak tersedia"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Tombol KEMBALI adalah untuk perangkat yang tersambung. Tekan tombol UTAMA untuk keluar."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Saluran Langsung tidak didukung pada perangkat dengan Android Lollipop ini."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Saluran Langsung membutuhkan izin untuk membaca cantuman TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Siapkan sumber Anda"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Saluran TV langsung menggabungkan pengalaman saluran TV tradisional dengan saluran streaming yang disediakan aplikasi. \n\nMulailah dengan menyiapkan sumber saluran yang telah terpasang. Atau jelajahi Google Play Store untuk menemukan aplikasi lain yang menawarkan saluran TV langsung."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Jadwal &amp; rekaman"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 menit"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 menit"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 jam"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 jam"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Baru-baru ini"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Terjadwal"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serial"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Lainnya"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Saluran ini tidak dapat direkam."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Program ini tidak dapat direkam."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> telah dijadwalkan untuk direkam"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Merekam <xliff:g id="PROGRAMNAME">%1$s</xliff:g> dari saat ini hingga <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Jadwal lengkap"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d hari berikutnya</item>
+ <item quantity="one">%1$d hari berikutnya</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d menit</item>
+ <item quantity="one">%1$d menit</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d rekaman baru</item>
+ <item quantity="one">%1$d rekaman baru</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d rekaman</item>
+ <item quantity="one">%1$d rekaman</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d jadwal rekaman</item>
+ <item quantity="one">%1$d jadwal rekaman</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Tonton"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Putar dari awal"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Lanjutkan pemutaran"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Hapus"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Hapus rekaman"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Lanjutkan"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Season <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Lihat jadwal"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Baca selengkapnya"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Hapus data"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Pilih episode yang ingin dihapus. Episode tidak dapat dipulihkan setelah dihapus."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Tidak ada data untuk dihapus."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Pilih episode yang ditonton"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Pilih semua episode"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Hapus semua episode"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> dari <xliff:g id="DURATION">%2$d</xliff:g> menit yang sudah ditonton"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> dari <xliff:g id="DURATION">%2$d</xliff:g> detik yang sudah ditonton"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Tidak pernah ditonton"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d dari %2$d episode telah dihapus</item>
+ <item quantity="one">%1$d dari %2$d episode telah dihapus</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritas"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Tertinggi"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Terendah"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Tidak. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Saluran"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Apa saja"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Pilih prioritas"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Jika terlalu banyak program yang akan direkam secara bersamaan, hanya program dengan prioritas lebih tinggi yang akan direkam."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Simpan"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Perekaman satu kali memiliki prioritas tertinggi"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Batal"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Batal"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Lupakan"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Berhenti"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Lihat jadwal rekaman"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Program tunggal ini"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"sekarang - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Semua serial…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Tetap jadwalkan"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Rekam yang ini saja"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Batalkan rekaman ini"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Tonton sekarang"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Dapat direkam"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Perekaman dijadwalkan"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Perekaman bentrok"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Merekam"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Rekaman gagal"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Membaca program untuk membuat jadwal rekaman"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Membaca program"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR memerlukan penyimpanan ekstra"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Anda akan dapat merekam program dengan DVR. Namun, saat ini penyimpanan pada perangkat tidak cukup untuk menjalankan DVR. Hubungkan drive eksternal berukuran <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB atau lebih besar dan ikuti langkah untuk memformat drive tersebut sebagai perangkat penyimpanan."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Penyimpanan tidak ada"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Beberapa penyimpanan yang digunakan oleh DVR tidak ada. Hubungkan drive eksternal yang sebelumnya digunakan untuk kembali mengaktifkan DVR. Atau, Anda dapat memilih untuk melupakan penyimpanan jika sudah tidak tersedia."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Lupakan penyimpanan?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Semua konten dan jadwal yang direkam akan hilang."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Berhenti merekam?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Konten yang direkam akan disimpan."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Rekaman telah dijadwalkan, tapi jadwalnya bentrok"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Rekaman telah dimulai, namun jadwalnya bentrok"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> akan direkam."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> sedang direkam."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Beberapa bagian dari <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> tidak akan direkam."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Beberapa bagian dari <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> dan <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> tidak akan direkam."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Beberapa bagian dari <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> dan satu jadwal lainnya tidak akan direkam."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Beberapa bagian dari <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>, dan %3$d jadwal lainnya tidak akan direkam.</item>
+ <item quantity="one">Beberapa bagian dari <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>, dan %3$d jadwal lainnya tidak akan direkam.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Apa yang ingin direkam?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Berapa lama Anda ingin merekam?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Sudah dijadwalkan"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Program yang sama telah dijadwalkan untuk direkam pukul <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Sudah direkam"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Program ini telah direkam. Rekaman ada di pustaka DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Tidak ditemukan program yang direkam."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Rekaman terkait"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Tidak ada deskripsi program)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d rekaman</item>
+ <item quantity="one">%1$d rekaman</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> dihapus dari jadwal perekaman"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Akan direkam sebagian karena tuner bermasalah."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Tidak akan direkam karena tuner bermasalah."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Belum ada rekaman yang dijadwalkan.\nAnda dapat menjadwalkan rekaman dari panduan program."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d rekaman bentrok</item>
+ <item quantity="one">%1$d rekaman bentrok</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Setelan seri"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Mulai rekaman seri"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Hentikan rekaman seri"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Hentikan rekaman seri?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Episode yang direkam akan tetap tersedia di pustaka DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Hentikan"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Tidak ada episode yang tersedia.\nEpisode akan direkam setelah tersedia."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d menit)</item>
+ <item quantity="one">(%1$d menit) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hari ini"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Besok"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Kemarin"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> hari ini"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> besok"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Skor"</string>
</resources>
diff --git a/res/values-is-rIS/arrays.xml b/res/values-is-rIS/arrays.xml
index 08200b56..27cb8655 100644
--- a/res/values-is-rIS/arrays.xml
+++ b/res/values-is-rIS/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Allur skjárinn"</item>
<item msgid="8568284598210500589">"Aðdráttur"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Allar rásir"</item>
- <item msgid="6897460857821394118">"Fjölskylduefni/barnaefni"</item>
- <item msgid="551257741825778215">"Íþróttir"</item>
- <item msgid="452133796804325879">"Verslun"</item>
- <item msgid="3296058637230163031">"Kvikmyndir"</item>
- <item msgid="1054540282883891201">"Grín"</item>
- <item msgid="7900158429062595471">"Ferðalög"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Fræðsla"</item>
- <item msgid="7396447839483867269">"Dýr/dýralíf"</item>
- <item msgid="4738043455148062673">"Fréttir"</item>
- <item msgid="7405041316051047427">"Leikir"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Allar rásir"</item>
- <item msgid="7909003973960375395">"Fjölskylduefni/barnaefni"</item>
- <item msgid="3185279732911635789">"Íþróttir"</item>
- <item msgid="4704858492065325964">"Verslun"</item>
- <item msgid="6083795019290250078">"Kvikmyndir"</item>
- <item msgid="8302638329222449550">"Grín"</item>
- <item msgid="3803709976021475052">"Ferðalög"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Fræðsla"</item>
- <item msgid="7511135485827589547">"Dýr/dýralíf"</item>
- <item msgid="6961248112238009967">"Fréttir"</item>
- <item msgid="6484685553679698447">"Leikir"</item>
- <item msgid="2737158328243183190">"List"</item>
- <item msgid="6577176952650166615">"Afþreying"</item>
- <item msgid="7886693831871777617">"Lífsstíll"</item>
- <item msgid="8145832312485577062">"Tónlist"</item>
- <item msgid="1345789204804308580">"Úrvalsefni"</item>
- <item msgid="2736680312770771994">"Tækni og vísindi"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Allar rásir"</item>
+ <item msgid="928298872841713530">"Fjölskylduefni/barnaefni"</item>
+ <item msgid="2751606947569857164">"Íþróttir"</item>
+ <item msgid="7345749789651321496">"Verslun"</item>
+ <item msgid="167201149441442173">"Kvikmyndir"</item>
+ <item msgid="525966731464264290">"Grín"</item>
+ <item msgid="6096710741527327836">"Ferðalög"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Fræðsla"</item>
+ <item msgid="7221999662426308394">"Dýr/dýralíf"</item>
+ <item msgid="375300513250925001">"Fréttir"</item>
+ <item msgid="7746320336582330410">"Leikir"</item>
+ <item msgid="1255741860568329178">"List"</item>
+ <item msgid="7603949681065702867">"Afþreying"</item>
+ <item msgid="4453821994746804366">"Lífsstíll"</item>
+ <item msgid="3488534597567932843">"Tónlist"</item>
+ <item msgid="7452153120614274095">"Úrvalsefni"</item>
+ <item msgid="8215762047341133299">"Tækni og vísindi"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Beinar útsendingar"</item>
diff --git a/res/values-is-rIS/rating_system_strings.xml b/res/values-is-rIS/rating_system_strings.xml
index 7e3bfbb3..1725d040 100644
--- a/res/values-is-rIS/rating_system_strings.xml
+++ b/res/values-is-rIS/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-is-rIS/strings.xml b/res/values-is-rIS/strings.xml
index 1bfefeac..6111b578 100644
--- a/res/values-is-rIS/strings.xml
+++ b/res/values-is-rIS/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Til baka"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Dagskrárvísir"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nýjar rásir í boði"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Enginn tengill í boði"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Opna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Skjátextar"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Birtingarstill."</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Undirflokkar"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Sláðu inn PIN-númerið til að horfa á þessa rás"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Sláðu inn PIN-númerið til að horfa á þennan þátt"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Þessi þáttur er flokkaður sem <xliff:g id="RATING">%1$s</xliff:g>. Sláðu inn PIN-númerið til að horfa á þáttinn"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Sláðu inn PIN-númerið"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Til að stilla foreldraeftirlit skaltu búa til PIN-númer"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Sláðu inn nýtt PIN-númer"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Leyfi opins kóða"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Leyfi opins kóða"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Útgáfa"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Hjálpa til við að bæta rásir í beinni"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Deila nafnlausum gögnum um notkun og greiningu með Google til að við getum gert beinar útsendingar betri og komið í veg fyrir vandamál eins og hrun og að mynd frjósi."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Til að horfa á þessa rás skaltu ýta til hægri og slá inn PIN-númerið þitt"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Til að horfa á þennan þátt skaltu ýta til hægri og slá inn PIN-númerið þitt"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Þessi þáttur er flokkaður sem <xliff:g id="RATING">%1$s</xliff:g>.\nTil að horfa á þáttinn skaltu ýta til hægri og slá inn PIN-númerið þitt."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Aðeins hljóð"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Lítill sendistyrkur"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Engin nettenging"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Ekki er hægt að spila þessa rás fyrr en <xliff:g id="END_TIME_1">%1$s</xliff:g> þar sem verið er að taka upp aðrar rásir. \n\nÝttu á hægri takkann til að breyta upptökuáætluninni.</item>
+ <item quantity="other">Ekki er hægt að spila þessa rás fyrr en <xliff:g id="END_TIME_1">%1$s</xliff:g> þar sem verið er að taka upp aðrar rásir. \n\nÝttu á hægri takkann til að breyta upptökuáætluninni.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Ekkert heiti"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Rás læst"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Ný"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Engar rásir í boði"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nýtt"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Ekki uppsett"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Sækja fleiri veitur"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Skoða forrit sem bjóða upp á beinar útsendingar"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Sækja fleiri veitur"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Skoða forrit sem bjóða upp á beinar útsendingar"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nýjar sjónvarpsveitur í boði"</string>
<string name="new_sources_description" msgid="749649005588426813">"Nýjum sjónvarpsveitum fylgja nýjar sjónvarpsrásir.\nSettu þær upp núna eða gerðu það síðar í stillingunum fyrir inntak rása."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Setja upp núna"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Allar inntaksrásir eru faldar.\nVeldu minnst eina rás til að horfa á."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Myndskeiðið er óvænt ekki tiltækt"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Til baka-lykillinn er fyrir tengd tæki. Ýttu á heimahnappinn til að hætta."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Rásir í beinni eru ekki studdar í þessu tæki með Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Rásir í beinni þurfa heimild til að lesa sjónvarpsdagskrána."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Setja upp inntök rása"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Beinar útsendingar sameina þá upplifun að horfa á venjulegar sjónvarpsstöðvar og straumspila rásir í gegnum forrit. \n\nByrjaðu á því að setja upp þau inntök rása sem þegar hafa verið sótt eða farðu í Google Play Store til að skoða fleiri forrit sem bjóða upp á beinar útsendingar."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Upptökur og áætlanir"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 mínútur"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 mínútur"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 klukkustund"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 klukkustundir"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nýlegt"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Áætlað"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Þáttaröð"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Annað"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Ekki er hægt að taka upp rásina."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Ekki er hægt að taka upp dagskrárliðinn."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> var sett á upptökuáætlun"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Tekur upp <xliff:g id="PROGRAMNAME">%1$s</xliff:g> núna og þangað til <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Heildaráætlun"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Næsti %1$d dagur</item>
+ <item quantity="other">Næstu %1$d dagar</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d mínúta</item>
+ <item quantity="other">%1$d mínútur</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d ný upptaka</item>
+ <item quantity="other">%1$d nýjar upptökur</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d upptaka</item>
+ <item quantity="other">%1$d upptökur</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d upptaka á áætlun</item>
+ <item quantity="other">%1$d upptökur á áætlun</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Horfa"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Spila frá upphafi"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Halda spilun áfram"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Eyða"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Eyða upptökum"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Halda áfram"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Þáttaröð <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Skoða dagskrá"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Lesa meira"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Eyða upptökum"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Veldu þætti sem þú vilt eyða. Ekki er hægt að endurheimta þætti eftir að þeim hefur verið eytt."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Engar upptökur til að eyða"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Velja þætti sem horft var á"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Velja alla þætti"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Hætta við val á öllum þáttum"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Horft á <xliff:g id="WATCHED">%1$d</xliff:g> af <xliff:g id="DURATION">%2$d</xliff:g> mínútum"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Horft á <xliff:g id="WATCHED">%1$d</xliff:g> af <xliff:g id="DURATION">%2$d</xliff:g> sekúndum"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Aldrei horft á"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d af %2$d þætti er eytt</item>
+ <item quantity="other">%1$d af %2$d þáttum er eytt</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Forgangur"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Mestur"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Mjög lítill"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nei. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Stöðvar"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Hvað sem er"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Veldu forgang"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Þegar taka á upp of marga þætti á sama tíma eru aðeins þættir sem eru í forgangi teknir upp."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Vista"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Stakar upptökur hafa forgang"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Hætta við"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Hætta við"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Gleyma"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stöðva"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Skoða upptökuáætlun"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Bara þennan þátt"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"núna – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Alla þáttaröðina…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Setja samt á áætlun"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Taka þetta upp í staðinn"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Hætta við þessa upptöku"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Horfa núna"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Hægt að taka upp"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Upptaka sett á áætlun"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Skarast á við aðra upptöku"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Upptaka í gangi"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Upptaka mistókst"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Les dagskrár til að búa til upptökuáætlanir"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Les dagskrár"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR þarf meira geymslupláss"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Þú getur tekið upp þætti með stafræna upptökubúnaðinum (DVR). Hins vegar er ekki nóg geymslupláss til staðar á tækinu þínu sem stendur til að DVR virki. Tengdu utanáliggjandi disk við tækið sem er <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB eða stærri og fylgdu skrefunum til að setja það upp sem geymslupláss tækisins."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Geymslu vantar"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Hluta af geymslurýminu sem stafræni upptökubúnaðurinn notar vantar. Tengdu utanáliggjandi drif sem þú notaðir áður til að gera stafræna upptökubúnaðinn virkan á ný. Einnig geturðu valið að gleyma geymslunni ef hún er ekki lengur tiltæk."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Viltu gleyma geymslunni?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Allt efni sem þú hefur tekið upp og allar dagskrár glatast."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Stöðva upptöku?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Upptökur á efni verða vistaðar."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Upptaka á áætlun en skarast við aðra"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Upptaka er hafin en hún skarast við aðra"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> verður tekið upp."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Upptaka í gangi á <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Einhverjir hlutar af <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> verða ekki teknir upp."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Einhverjir hlutar af <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> og <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> verða ekki teknir upp."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Einhverjir hlutar af <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> og einu dagskráratriði í viðbót verða ekki teknir upp."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Einhverjir hlutar af <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> og %3$d í viðbót verða ekki teknir upp.</item>
+ <item quantity="other">Einhverjir hlutar af <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> og %3$d í viðbót verða ekki teknir upp.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Hvað viltu taka upp?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hversu lengi viltu taka upp?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Þegar áætlað"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Sami þáttur er þegar á upptökuáætlun kl. <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Þegar tekið upp"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Þessi þáttur hefur þegar verið tekinn upp. Hann er tiltækur í DVR-safninu."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Upptekinn þáttur fannst ekki."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Tengdar upptökur"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Engin þáttalýsing)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d upptaka</item>
+ <item quantity="other">%1$d upptökur</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> fjarlægt úr upptökuáætlun"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Verður tekið upp að hluta til vegna árekstra við stilli."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Verður ekki tekið upp vegna árekstra við stilli."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Engar upptökur eru á áætlun enn sem komið er.\nÞú getur bætt upptöku við áætlun í dagskrárvísinum."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d árekstur í upptöku</item>
+ <item quantity="other">%1$d árekstrar í upptöku</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Þáttaraðastillingar"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Hefja upptöku á þáttaröð"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Hætta upptöku á þáttaröð"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Hætta upptöku á þáttaröð?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Upptökur af þáttum verða áfram tiltækar í DVR-safninu."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stöðva"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Engir þættir eru tiltækir.\nÞeir verða teknir upp þegar þeir eru tiltækir."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d mínúta)</item>
+ <item quantity="other">(%1$d mínútur)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Í dag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Á morgun"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Í gær"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> í dag"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> á morgun"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Einkunn"</string>
</resources>
diff --git a/res/values-it/arrays.xml b/res/values-it/arrays.xml
index e445f6ab..8dd12954 100644
--- a/res/values-it/arrays.xml
+++ b/res/values-it/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Intera"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Tutti i canali"</item>
- <item msgid="6897460857821394118">"Famiglia/bambini"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Acquisti"</item>
- <item msgid="3296058637230163031">"Cinema"</item>
- <item msgid="1054540282883891201">"Commedie"</item>
- <item msgid="7900158429062595471">"Viaggi"</item>
- <item msgid="3768998587825611787">"Drammatici"</item>
- <item msgid="8340620094959282881">"Istruzione"</item>
- <item msgid="7396447839483867269">"Animali/fauna selvatica"</item>
- <item msgid="4738043455148062673">"Notizie"</item>
- <item msgid="7405041316051047427">"Giochi"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Tutti i canali"</item>
- <item msgid="7909003973960375395">"Famiglia/bambini"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Acquisti"</item>
- <item msgid="6083795019290250078">"Cinema"</item>
- <item msgid="8302638329222449550">"Commedie"</item>
- <item msgid="3803709976021475052">"Viaggi"</item>
- <item msgid="8116747365234169059">"Drammatici"</item>
- <item msgid="7356447541595315913">"Istruzione"</item>
- <item msgid="7511135485827589547">"Animali/fauna selvatica"</item>
- <item msgid="6961248112238009967">"Notizie"</item>
- <item msgid="6484685553679698447">"Giochi"</item>
- <item msgid="2737158328243183190">"Arte"</item>
- <item msgid="6577176952650166615">"Divertimento"</item>
- <item msgid="7886693831871777617">"Stile di vita"</item>
- <item msgid="8145832312485577062">"Musica"</item>
- <item msgid="1345789204804308580">"Il meglio"</item>
- <item msgid="2736680312770771994">"Scienza/tecnica"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Tutti i canali"</item>
+ <item msgid="928298872841713530">"Famiglia/bambini"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Film"</item>
+ <item msgid="525966731464264290">"Commedie"</item>
+ <item msgid="6096710741527327836">"Viaggi"</item>
+ <item msgid="2851882187117833883">"Drammatici"</item>
+ <item msgid="78492781188719038">"Istruzione"</item>
+ <item msgid="7221999662426308394">"Animali/fauna selvatica"</item>
+ <item msgid="375300513250925001">"Notizie"</item>
+ <item msgid="7746320336582330410">"Giochi"</item>
+ <item msgid="1255741860568329178">"Arte"</item>
+ <item msgid="7603949681065702867">"Svago"</item>
+ <item msgid="4453821994746804366">"Stile di vita"</item>
+ <item msgid="3488534597567932843">"Musica"</item>
+ <item msgid="7452153120614274095">"Il meglio"</item>
+ <item msgid="8215762047341133299">"Scienza/tecnica"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Dirette TV"</item>
diff --git a/res/values-it/rating_system_strings.xml b/res/values-it/rating_system_strings.xml
index 1bc1f6b2..7891e49b 100644
--- a/res/values-it/rating_system_strings.xml
+++ b/res/values-it/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 56717ba0..da0b48a6 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Indietro"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guida ai programmi"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nuovi canali disponibili"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nessun link disponibile"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Apri <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Sottotitoli"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Visualizzazione"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Classificazioni secondarie"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Inserisci il codice PIN per guardare questo canale"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Inserisci il codice PIN per guardare questo programma"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"La valutazione di questo programma è <xliff:g id="RATING">%1$s</xliff:g>. Inserisci il tuo PIN per guardare il programma"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Inserisci il codice PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Per impostare il filtro famiglia, crea un codice PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Inserisci il nuovo PIN"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licenze open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licenze open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versione"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Contribuisci a migliorare Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Condividi con Google dati anonimi sull\'utilizzo e sulla diagnostica per consentirci di migliorare l\'app Dirette TV ed di evitare problemi, quali arresti anomali e blocchi."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Per guardare questo canale, premi il pulsante destro e inserisci il PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Per guardare questo programma, premi il pulsante destro e inserisci il PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Questo programma è classificato come <xliff:g id="RATING">%1$s</xliff:g>.\nPer guardarlo, premi il tasto destro e inserisci il PIN."</string>
@@ -159,6 +157,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Solo audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Segnale debole"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nessuna connessione Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Il canale non può essere riprodotto fino alle ore <xliff:g id="END_TIME_1">%1$s</xliff:g> perché è in corso la registrazione di altri canali. \n\nPremi la freccia destra per regolare la pianificazione di registrazione.</item>
+ <item quantity="one">Il canale non può essere riprodotto fino alle ore <xliff:g id="END_TIME_0">%1$s</xliff:g> perché è in corso la registrazione di un altro canale. \n\nPremi la freccia destra per regolare la pianificazione di registrazione.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Senza titolo"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canale bloccato"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nuove"</string>
@@ -170,8 +172,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nessun canale disponibile"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Elementi nuovi"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Non configurato"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Trova altre fonti"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Trova app che offrono dirette TV"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Trova altre fonti"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Trova app che offrono dirette TV"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nuove fonti di canali disponibili"</string>
<string name="new_sources_description" msgid="749649005588426813">"Nuove fonti con canali disponibili.\nConfigurale ora o più tardi nell\'impostazione Fonti canali."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configura ora"</string>
@@ -189,8 +191,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Tutti i canali di origine sono nascosti.\nSeleziona almeno un canale da guardare."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Il video è improvvisamente non disponibile"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Il tasto INDIETRO è per il dispositivo connesso. Per uscire premi il pulsante HOME."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV non è supportato su questo dispositivo con Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV richiede l\'autorizzazione per leggere gli elenchi TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configura le tue fonti"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"L\'app Dirette TV combina i canali TV tradizionali ai canali in streaming forniti dalle app. \n\nInnanzitutto, configura le fonti di canali già installate. In alternativa, cerca altre app di dirette TV sul Google Play Store."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Registrazioni e programmazioni"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuti"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuti"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ore"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recenti"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programmate"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Altri"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Il canale non può essere registrato."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Il programma non può essere registrato."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"È stata programmata la registrazione di <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Registra <xliff:g id="PROGRAMNAME">%1$s</xliff:g> da adesso fino alle ore <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Pianificazione completa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">I prossimi %1$d giorni</item>
+ <item quantity="one">Il prossimo %1$d giorno</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minuti</item>
+ <item quantity="one">%1$d minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nuove registrazioni</item>
+ <item quantity="one">%1$d nuova registrazione</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d registrazioni</item>
+ <item quantity="one">%1$d registrazione</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d registrazioni programmate</item>
+ <item quantity="one">%1$d registrazione programmata</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Guarda"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Riproduci dall\'inizio"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Riprendi riproduz."</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Elimina"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Elimina registraz."</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Riprendi"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Stagione <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Pianificazione"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Leggi tutto"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Elimina registraz."</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Seleziona le puntate da eliminare. Una volta eliminate, le puntate non potranno essere ripristinate."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nessuna registrazione da eliminare."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Seleziona puntate guardate"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Seleziona tutte le puntate"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Deseleziona tutte le puntate"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> di <xliff:g id="DURATION">%2$d</xliff:g> minuti guardati"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> di <xliff:g id="DURATION">%2$d</xliff:g> secondi guardati"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Mai guardate"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d di %2$d puntate eliminate</item>
+ <item quantity="one">%1$d di %2$d puntata eliminata</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorità"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Massima"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Minima"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"N. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canali"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Qualsiasi"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Scegli la priorità"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Quando ci sono troppi programmi da registrare nello stesso momento, vengono registrati solo quelli con le priorità maggiori."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Salva"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Le registrazioni uniche hanno la massima priorità"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Annulla"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Annulla"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Elimina"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Interrompi"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Pianificazione registrazione"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Solo questo programma"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"adesso - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Intera serie…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programma comunque"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Registra questo"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Annulla la registrazione"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Guarda adesso"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Registrabile"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Registrazione programmata"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflitto di registrazione"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Registrazione in corso"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Registrazione non riuscita"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lettura dei programmi per la creazione delle pianificazioni di registrazione"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Lettura dei programmi…"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Il dispositivo DVR ha bisogno di più spazio di archiviazione"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Potrai registrare programmi con un dispositivo DVR. Tuttavia, al momento lo spazio di archiviazione non è sufficiente per consentire il funzionamento del DVR. Collega un\'unità esterna di almeno <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB e segui la procedura per formattarla come memoria dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Memoria mancante"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Manca parte della memoria utilizzata dal DVR. Collega l\'unità esterna utilizzata prima di riattivare il DVR. In alternativa, puoi scegliere di eliminare la memoria se non è più disponibile."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Eliminare la memoria?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tutti i contenuti registrati e le pianificazioni andranno persi."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Interrompere la registrazione?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"I contenuti registrati verranno salvati."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Registrazione programmata, ma ci sono conflitti"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"La registrazione è iniziata, ma ci sono conflitti"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Verrà registrato il programma <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Registrazione in corso di <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Alcune parti di <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> non verranno registrate."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Alcune parti di <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> e <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> non verranno registrate."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Alcune parti di <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> e di un\'altra pianificazione non verranno registrate."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Alcune parti di <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> e di altre %3$d pianificazioni non verranno registrate.</item>
+ <item quantity="one">Alcune parti di <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> e di %3$d altra pianificazione non verranno registrate.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Cosa vuoi registrare?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Per quanto tempo desideri registrare?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Già in programma"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"È già stata programmata la registrazione dello stesso programma alle <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Già registrato"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Questo programma è già stato registrato. È disponibile nella raccolta DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programma registrato non trovato."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Registrazioni correlate"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nessuna descrizione programma)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d registrazioni</item>
+ <item quantity="one">%1$d registrazione</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> rimosso dalla pianificazione di registrazione"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Registraz. parziale per conflitti con il sintonizzatore."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Impossibile registrare per conflitti con il sintonizzatore."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Non ci sono ancora registrazioni in programma.\nPuoi pianificare la registrazione dalla guida ai programmi."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d conflitti di registrazione</item>
+ <item quantity="one">%1$d conflitto di registrazione</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Impostazioni per la serie"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Avvia registrazione serie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Interrompi regis. serie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Interrompere la registrazione della serie?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Le puntate registrate resteranno disponibili nella raccolta DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Interrompi"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Non ci sono episodi a disposizione.\nVerranno registrati non appena saranno disponibili."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minuti)</item>
+ <item quantity="one">(%1$d minuto) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Oggi"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Domani"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ieri"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> di oggi"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> di domani"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Punteggio"</string>
</resources>
diff --git a/res/values-iw/arrays.xml b/res/values-iw/arrays.xml
index 7748ed68..17a73776 100644
--- a/res/values-iw/arrays.xml
+++ b/res/values-iw/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"מלאה"</item>
<item msgid="8568284598210500589">"שנה מרחק מתצוגה"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"כל הערוצים"</item>
- <item msgid="6897460857821394118">"משפחה/ילדים"</item>
- <item msgid="551257741825778215">"ספורט"</item>
- <item msgid="452133796804325879">"קניות"</item>
- <item msgid="3296058637230163031">"סרטים"</item>
- <item msgid="1054540282883891201">"קומדיה"</item>
- <item msgid="7900158429062595471">"טיולים"</item>
- <item msgid="3768998587825611787">"דרמה"</item>
- <item msgid="8340620094959282881">"חינוך"</item>
- <item msgid="7396447839483867269">"בעלי חיים/חיות בר"</item>
- <item msgid="4738043455148062673">"חדשות"</item>
- <item msgid="7405041316051047427">"משחקים"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"כל הערוצים"</item>
- <item msgid="7909003973960375395">"משפחה/ילדים"</item>
- <item msgid="3185279732911635789">"ספורט"</item>
- <item msgid="4704858492065325964">"קניות"</item>
- <item msgid="6083795019290250078">"סרטים"</item>
- <item msgid="8302638329222449550">"קומדיה"</item>
- <item msgid="3803709976021475052">"טיולים"</item>
- <item msgid="8116747365234169059">"דרמה"</item>
- <item msgid="7356447541595315913">"חינוך"</item>
- <item msgid="7511135485827589547">"בעלי חיים/חיות בר"</item>
- <item msgid="6961248112238009967">"חדשות"</item>
- <item msgid="6484685553679698447">"משחקים"</item>
- <item msgid="2737158328243183190">"אמנות"</item>
- <item msgid="6577176952650166615">"בידור"</item>
- <item msgid="7886693831871777617">"סגנון חיים"</item>
- <item msgid="8145832312485577062">"מוזיקה"</item>
- <item msgid="1345789204804308580">"עילית"</item>
- <item msgid="2736680312770771994">"טכנולוגיה/מדע"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"כל הערוצים"</item>
+ <item msgid="928298872841713530">"משפחה/ילדים"</item>
+ <item msgid="2751606947569857164">"ספורט"</item>
+ <item msgid="7345749789651321496">"קניות"</item>
+ <item msgid="167201149441442173">"סרטים"</item>
+ <item msgid="525966731464264290">"קומדיה"</item>
+ <item msgid="6096710741527327836">"טיולים"</item>
+ <item msgid="2851882187117833883">"דרמה"</item>
+ <item msgid="78492781188719038">"חינוך"</item>
+ <item msgid="7221999662426308394">"בעלי חיים/טבע"</item>
+ <item msgid="375300513250925001">"חדשות"</item>
+ <item msgid="7746320336582330410">"משחקים"</item>
+ <item msgid="1255741860568329178">"אמנויות"</item>
+ <item msgid="7603949681065702867">"בידור"</item>
+ <item msgid="4453821994746804366">"החיים הטובים"</item>
+ <item msgid="3488534597567932843">"מוזיקה"</item>
+ <item msgid="7452153120614274095">"עילית"</item>
+ <item msgid="8215762047341133299">"טכנולוגיה/מדע"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ערוצי שידורים חיים"</item>
diff --git a/res/values-iw/rating_system_strings.xml b/res/values-iw/rating_system_strings.xml
index e682d2f6..ecf86eb6 100644
--- a/res/values-iw/rating_system_strings.xml
+++ b/res/values-iw/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 354c837c..743b31fd 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"הקודם"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"מדריך תכניות"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"ערוצים חדשים זמינים"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"אין קישור זמין"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"פתח את <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"כתוביות"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"מצב תצוגה"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"סיווגי משנה"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"הזן את קוד האימות שלך כדי לצפות בערוץ זה"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"הזן את קוד האימות שלך כדי לצפות בתכנית זו"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"‏סיווג התוכנית הזו הוא <xliff:g id="RATING">%1$s</xliff:g>. הזן את ה-PIN שלך כדי לצפות בתוכנית זו"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"הזן את קוד האימות שלך"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"‏להגדרת בקרות הוריות, צור מספר PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"‏הזן את מספר ה-PIN החדש"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"רישיונות קוד פתוח"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"רישיונות קוד פתוח"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"גרסה"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"עוזרים לשפר את הערוצים בשידור חי"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"‏שתף נתוני שימוש ואבחון אנונימיים עם Google כדי שנוכל לשפר את ערוצי השידורים החיים ולמנוע בעיות כמו קריסות וקפיאת תמונה."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"‏כדי לצפות בערוץ הזה, לחץ על \'ימין\' והזן את מספר ה-PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"‏כדי לצפות בתכנית הזו, לחץ על \'ימין\' והזן את מספר ה-PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"‏סיווג התכנית הזו הוא <xliff:g id="RATING">%1$s</xliff:g>.\nכדי לצפות בתכנית, לחץ ימינה והזן את ה-PIN."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"אודיו בלבד"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"אות חלש"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"אין חיבור לאינטרנט"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="two">לא ניתן להפעיל את הערוץ הזה עד <xliff:g id="END_TIME_1">%1$s</xliff:g> כי ערוצים אחרים מוקלטים. \n\nלחץ על \'ימינה\' כדי לכוון את לוח הזמנים להקלטה.</item>
+ <item quantity="many">לא ניתן להפעיל את הערוץ הזה עד <xliff:g id="END_TIME_1">%1$s</xliff:g> כי ערוצים אחרים מוקלטים. \n\nלחץ על \'ימינה\' כדי לכוון את לוח הזמנים להקלטה.</item>
+ <item quantity="other">לא ניתן להפעיל את הערוץ הזה עד <xliff:g id="END_TIME_1">%1$s</xliff:g> כי ערוצים אחרים מוקלטים. \n\nלחץ על \'ימינה\' כדי לכוון את לוח הזמנים להקלטה.</item>
+ <item quantity="one">לא ניתן להפעיל את הערוץ הזה עד <xliff:g id="END_TIME_0">%1$s</xliff:g> כי ערוץ אחר מוקלט. \n\nלחץ על \'ימינה\' כדי לכוון את לוח הזמנים להקלטה.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ללא כותרת"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"הערוץ חסום"</string>
<string name="setup_category_new" msgid="2899355289563443627">"חדש"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"אין ערוצים זמינים"</string>
<string name="setup_input_new" msgid="3337725672277046798">"חדש"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"לא מוגדר"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"קבל מקורות נוספים"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"עיין באפליקציות שמציעות ערוצי שידורים חיים"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"קבלת מקורות נוספים"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"עיין באפליקציות שמציעות ערוצי שידורים חיים"</string>
<string name="new_sources_title" msgid="3878933676500061895">"יש מקורות ערוצים חדשים זמינים"</string>
<string name="new_sources_description" msgid="749649005588426813">"למקורות הערוצים החדשים יש הצעות לערוצים.\nהגדר אותם עכשיו, או עשה זאת מאוחר יותר בהגדרת מקורות הערוצים."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"הגדר עכשיו"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"כל ערוצי המקור מוסתרים.\nבחר ערוץ אחד לפחות לצפייה."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"מסיבה בלתי צפויה, הסרטון אינו זמין"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"מקש \'הקודם\' מיועד למכשירים מחוברים. לחץ על לחצן \'דף הבית\' כדי לצאת."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"‏Live TV אינו נתמך במכשיר זה עם Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"‏Live TV זקוק להרשאה כדי לקרוא את לוחות שידורי הטלוויזיה."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"הגדרת המקורות שלך"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"‏ערוצי שידורים חיים משלבים בין חוויית הצפייה בערוצי טלוויזיה מסורתיים לבין ערוצי סטרימינג שמספקות אפליקציות. \n\nהתחל על ידי הגדרת מקורות הערוצים שכבר מותקנים. או חפש בחנות Google Play אפליקציות נוספות המציעות ערוצי שידורים חיים."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"הקלטות ולוחות זמנים"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 דקות"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 דקות"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 שעה"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 שעות"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"אחרונות"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"מתוזמנות"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"סדרה"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"אחרות"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"לא ניתן להקליט את הערוץ."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"לא ניתן להקליט את התוכנית."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"התוכנית <xliff:g id="PROGRAMNAME">%1$s</xliff:g> תוזמנה להקלטה"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"מקליט את התוכנית <xliff:g id="PROGRAMNAME">%1$s</xliff:g> מעכשיו עד <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"לוח זמנים מלא"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="two">היומיים הבאים</item>
+ <item quantity="many">‏%1$d הימים הבאים</item>
+ <item quantity="other">‏%1$d הימים הבאים</item>
+ <item quantity="one">היום הבא</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <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="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <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="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <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="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <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="dvr_detail_watch" msgid="7085694764364338215">"צפה"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"הפעל מההתחלה"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"המשך את ההפעלה"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"מחק"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"מחק הקלטות"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"המשך"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"עונה <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"הצג לוח זמנים"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"קרא עוד"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"מחיקת הקלטות"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"בחר את הפרקים שברצונך למחוק. לא ניתן יהיה לשחזר אותם לאחר המחיקה."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"אין הקלטות למחיקה."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"בחר בפרקים שנצפו"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"בחר את כל הפרקים"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"בטל את בחירת כל הפרקים"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"נצפו <xliff:g id="WATCHED">%1$d</xliff:g> מתוך <xliff:g id="DURATION">%2$d</xliff:g> דקות"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"נצפו <xliff:g id="WATCHED">%1$d</xliff:g> מתוך <xliff:g id="DURATION">%2$d</xliff:g> שניות"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"לא נצפו אף פעם"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="two">‏נמחקו %1$d מתוך %2$d פרקים</item>
+ <item quantity="many">‏נמחקו %1$d מתוך %2$d פרקים</item>
+ <item quantity="other">‏נמחקו %1$d מתוך %2$d פרקים</item>
+ <item quantity="one">‏נמחק %1$d פרק מתוך %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"עדיפות"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"הגבוהה ביותר"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"הנמוכה ביותר"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"לא. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ערוצים"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"הכול"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"בחירת עדיפות"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"כשיש יותר מדי תוכניות להקליט בו-זמנית, רק תוכניות בעלות עדיפות גבוהה יותר יוקלטו."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"שמור"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"הקלטות חד-פעמיות הן בעלות העדיפות הגבוהה ביותר"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"בטל"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"בטל"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"שכח"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"עצור"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"הצג לוח זמנים להקלטה"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"את התוכנית הזו בלבד"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"עכשיו - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"את הסדרה כולה…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"קביעת תזמון בכל זאת"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"הקלטת תוכנית זו במקום זאת"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ביטול הקלטה זאת"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"לצפייה עכשיו"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ניתנת להקלטה"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ההקלטה מתוזמנת"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"התנגשות בין הקלטות"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"מקליט"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ההקלטה נכשלה"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"קורא תוכניות כדי ליצור לוחות זמנים להקלטות"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"קורא תוכניות"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"‏DVR זקוק לשטח אחסון נוסף"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"‏תוכל להקליט תוכניות עם DVR. אולם, אין מספיק מקום אחסון במכשיר שלך כרגע כדי ש-DVR יעבוד. התחבר לכונן חיצוני בגודל GB<xliff:g id="STORAGE_SIZE">%1$s</xliff:g> או יותר, ובצע את השלבים לביצוע פורמט כאחסון מכשיר."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"אחסון חסר"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"‏חלק מהאחסון שנעשה בו שימוש ב-DVR חסר. חבר את הכונן החיצוני שבו השתמשת בעבר כדי להפעיל מחדש את ה-DVR. לחלופין, תוכל לבחור לשכוח את האחסון אם הוא אינו זמין עוד."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"לשכוח את האחסון?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"כל התוכן ולוחות הזמנים שתיעדת יאבדו."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"האם להפסיק את ההקלטה?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"התוכן המוקלט יישמר."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ההקלטה מתוזמנת, אבל ישנן הקלטות מתנגשות."</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ההקלטה החלה, אבל ישנן הקלטות מתנגשות"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"התוכנית <xliff:g id="PROGRAMNAME">%1$s</xliff:g> תוקלט."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"ערוץ <xliff:g id="CHANNELNAME">%1$s</xliff:g> מוקלט עכשיו."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"חלקים מסוימים מהתוכנית <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> לא יוקלטו."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ו-<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> לא יוקלטו."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ותוכנית אחת נוספת לא יוקלטו."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="two">‏חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ו-%3$d נוספות שתוזמנו להקלטה לא יוקלטו.</item>
+ <item quantity="many">‏חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ו-%3$d נוספות שתוזמנו להקלטה לא יוקלטו.</item>
+ <item quantity="other">‏חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ו-%3$d נוספות שתוזמנו להקלטה לא יוקלטו.</item>
+ <item quantity="one">חלקים מסוימים מהתוכניות <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ואחת נוספת שתוזמנה להקלטה לא יוקלטו.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"מה אתה רוצה להקליט?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"כמה זמן אתה רוצה להקליט?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"כבר מתוזמן"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"אותה תוכנית כבר תוזמנה להקלטה ב-<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"כבר הוקלט"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"‏תוכנית זו כבר הוקלטה. היא זמינה לצפייה בספריית ה-DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"התוכנית המוקלטת לא נמצאה."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"הקלטות קשורות"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(אין תיאור לתוכנית)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <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="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"התוכנית <xliff:g id="PROGRAMNAME">%1$s</xliff:g> הוסרה מלוח הזמנים להקלטה"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ההקלטה תבוצע באופן חלקי עקב התנגשויות בטיונר."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ההקלטה לא תבוצע עקב התנגשויות בטיונר."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"עדיין אין הקלטות מתוזמנות.\nניתן לתזמן הקלטה מלוח השידורים."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="two">‏%1$d התנגשויות בין הקלטות</item>
+ <item quantity="many">‏%1$d התנגשויות בין הקלטות</item>
+ <item quantity="other">‏%1$d התנגשויות בין הקלטות</item>
+ <item quantity="one">‏%1$d התנגשות בין הקלטות</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"הגדרות סדרה"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"התחל הקלטת סדרה"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"הפסק הקלטת סדרה"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"האם להפסיק את הקלטת הסדרה?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"‏פרקים מוקלטים יישארו זמינים בספריית DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"הפסק"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"אין פרקים זמינים.\nהם יוקלטו כשיהיו זמינים."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="two">‏(%1$d דקות)</item>
+ <item quantity="many">‏(%1$d דקות)</item>
+ <item quantity="other">‏(%1$d דקות)</item>
+ <item quantity="one">‏(%1$d דקה) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"היום"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"מחר"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"אתמול"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> היום"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> מחר"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ניקוד"</string>
</resources>
diff --git a/res/values-ja/arrays.xml b/res/values-ja/arrays.xml
index 52ac8f55..12d3b91a 100644
--- a/res/values-ja/arrays.xml
+++ b/res/values-ja/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"フル"</item>
<item msgid="8568284598210500589">"ズーム"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"すべてのチャンネル"</item>
- <item msgid="6897460857821394118">"ファミリー / 子ども"</item>
- <item msgid="551257741825778215">"スポーツ"</item>
- <item msgid="452133796804325879">"ショッピング"</item>
- <item msgid="3296058637230163031">"映画"</item>
- <item msgid="1054540282883891201">"コメディー"</item>
- <item msgid="7900158429062595471">"旅行"</item>
- <item msgid="3768998587825611787">"ドラマ"</item>
- <item msgid="8340620094959282881">"教育"</item>
- <item msgid="7396447839483867269">"動物 / 野生生物"</item>
- <item msgid="4738043455148062673">"ニュース"</item>
- <item msgid="7405041316051047427">"ゲーム"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"すべてのチャンネル"</item>
- <item msgid="7909003973960375395">"ファミリー / 子ども"</item>
- <item msgid="3185279732911635789">"スポーツ"</item>
- <item msgid="4704858492065325964">"ショッピング"</item>
- <item msgid="6083795019290250078">"映画"</item>
- <item msgid="8302638329222449550">"コメディー"</item>
- <item msgid="3803709976021475052">"旅行"</item>
- <item msgid="8116747365234169059">"ドラマ"</item>
- <item msgid="7356447541595315913">"教育"</item>
- <item msgid="7511135485827589547">"動物 / 野生生物"</item>
- <item msgid="6961248112238009967">"ニュース"</item>
- <item msgid="6484685553679698447">"ゲーム"</item>
- <item msgid="2737158328243183190">"芸術"</item>
- <item msgid="6577176952650166615">"エンターテイメント"</item>
- <item msgid="7886693831871777617">"ライフスタイル"</item>
- <item msgid="8145832312485577062">"音楽"</item>
- <item msgid="1345789204804308580">"プレミア"</item>
- <item msgid="2736680312770771994">"科学、技術"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"すべてのチャンネル"</item>
+ <item msgid="928298872841713530">"ファミリー/子ども"</item>
+ <item msgid="2751606947569857164">"スポーツ"</item>
+ <item msgid="7345749789651321496">"ショッピング"</item>
+ <item msgid="167201149441442173">"映画"</item>
+ <item msgid="525966731464264290">"コメディー"</item>
+ <item msgid="6096710741527327836">"旅行"</item>
+ <item msgid="2851882187117833883">"ドラマ"</item>
+ <item msgid="78492781188719038">"教育"</item>
+ <item msgid="7221999662426308394">"動物/野生生物"</item>
+ <item msgid="375300513250925001">"ニュース"</item>
+ <item msgid="7746320336582330410">"ゲーム"</item>
+ <item msgid="1255741860568329178">"芸術"</item>
+ <item msgid="7603949681065702867">"エンターテインメント"</item>
+ <item msgid="4453821994746804366">"ライフスタイル"</item>
+ <item msgid="3488534597567932843">"音楽"</item>
+ <item msgid="7452153120614274095">"プレミア"</item>
+ <item msgid="8215762047341133299">"科学、技術"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ライブ チャンネル"</item>
diff --git a/res/values-ja/rating_system_strings.xml b/res/values-ja/rating_system_strings.xml
index 69a38849..1ef3323d 100644
--- a/res/values-ja/rating_system_strings.xml
+++ b/res/values-ja/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 62b0f253..9c526c21 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"前へ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"番組ガイド"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"利用できる新しいチャンネル"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"リンクはありません"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>を開く"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"字幕"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"表示モード"</string>
@@ -94,7 +93,7 @@
</plurals>
<string name="msg_no_channel_added" msgid="2882586037409921925">"追加されたチャンネルなし"</string>
<string name="input_selector_tuner_label" msgid="6631205039926880892">"チューナー"</string>
- <string name="menu_parental_controls" msgid="2474294054521345840">"ペアレンタルコントロール"</string>
+ <string name="menu_parental_controls" msgid="2474294054521345840">"保護者による使用制限"</string>
<string name="option_toggle_parental_controls_on" msgid="9122851821454622696">"ON"</string>
<string name="option_toggle_parental_controls_off" msgid="7797910199040440618">"OFF"</string>
<string name="option_channels_locked" msgid="5797855082297549907">"ブロック済み"</string>
@@ -124,8 +123,9 @@
<string name="option_subrating_header" msgid="4637961301549615855">"サブレーティング"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"PINを入力してこのチャンネルを視聴"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"PINを入力してこのプログラムを視聴"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"この番組は「<xliff:g id="RATING">%1$s</xliff:g>」レーティングです。この番組を視聴するには PIN を入力してください"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PINの入力"</string>
- <string name="pin_enter_create_pin" msgid="3385754356793309946">"ペアレンタルコントロールを設定するには、PINを作成してください"</string>
+ <string name="pin_enter_create_pin" msgid="3385754356793309946">"保護者による使用制限を設定するには、暗証番号を作成してください"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"新しいPINを入力"</string>
<string name="pin_enter_again" msgid="2618999754723090427">"PINの確認"</string>
<string name="pin_enter_old_pin" msgid="4588282612931041919">"現在のPINの入力"</string>
@@ -140,12 +140,10 @@
<string name="settings_channel_source_item_customize_channels_description" msgid="8966243790328235580">"番組ガイド用のチャンネルを選択します"</string>
<string name="settings_channel_source_item_setup" msgid="4566190088656419070">"チャンネル ソース"</string>
<string name="settings_channel_source_item_setup_new_inputs" msgid="4845822152617430787">"新しいチャンネルを利用できます"</string>
- <string name="settings_parental_controls" msgid="5449397921700749317">"ペアレンタル コントロール"</string>
+ <string name="settings_parental_controls" msgid="5449397921700749317">"保護者による使用制限"</string>
<string name="settings_menu_licenses" msgid="1257646083838406103">"オープンソース ライセンス"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"オープンソースライセンス"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"バージョン"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ライブチャンネルの改善に協力する"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"クラッシュやフリーズの問題を防止し、ライブチャンネルの向上に役立てるため、匿名の診断情報や使用状況データをGoogleと共有してください。"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"このチャンネルを視聴するには、右のボタンを押してPINを入力してください。"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"このプログラムを視聴するには、右のボタンを押してPINを入力してください。"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"このプログラムのレーティングは<xliff:g id="RATING">%1$s</xliff:g>です。\nこのプログラムを視聴するには、右のボタンを押してPINを入力してください。"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"音声のみ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"信号強度が弱くなっています"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"インターネットに接続されていません"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">他のチャンネルが録画されているため、このチャンネルの再生は <xliff:g id="END_TIME_1">%1$s</xliff:g> までできません。\n\n録画予約を調整するには右のボタンを押してください。</item>
+ <item quantity="one">他のチャンネルが録画されているため、このチャンネルの再生は <xliff:g id="END_TIME_0">%1$s</xliff:g> までできません。\n\n録画予約を調整するには右のボタンを押してください。</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"タイトルなし"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"チャンネルをブロック"</string>
<string name="setup_category_new" msgid="2899355289563443627">"新規"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"チャンネルはありません"</string>
<string name="setup_input_new" msgid="3337725672277046798">"新規"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"セットアップしていません"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"その他のソース"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"ライブ チャンネルを利用できるアプリを探します"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"その他のソース"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"ライブ チャンネルを利用できるアプリを探します"</string>
<string name="new_sources_title" msgid="3878933676500061895">"新しいチャンネル ソースを利用できます"</string>
<string name="new_sources_description" msgid="749649005588426813">"新しいチャンネル ソースに、利用できるチャンネルがあります。\n今すぐセットアップするか、後からチャンネル ソース設定でセットアップすることができます。"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"今すぐセットアップ"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ソースチャンネルはすべて非表示になっています。\n視聴するチャンネルを1つ以上選択してください。"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"動画を再生できなくなりました"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"戻るキーは接続されたデバイス用です。終了するにはホームボタンを押してください。"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"ライブチャンネルは、Android Lollipopを搭載するこの端末では利用できません。"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"ライブチャンネルには、TV番組表を読み取る権限が必要です。"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"ソースをセットアップ"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ライブ チャンネルを利用すると、アプリで提供されるストリーミング チャンネルを従来のテレビのチャンネルと同様に視聴できます。\n\n使ってみるには、既にインストールされているチャンネル ソースをセットアップします。また、ライブ チャンネルを提供するアプリを Google Play ストアで探してさらに追加することもできます。"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"録画予約"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10分"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30分"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1時間"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3時間"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"最近"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"予約済み"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"シリーズ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"その他"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"このチャンネルの録画はできません。"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"この番組の録画はできません。"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"「<xliff:g id="PROGRAMNAME">%1$s</xliff:g>」が録画予約されました"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"「<xliff:g id="PROGRAMNAME">%1$s</xliff:g>」を今から <xliff:g id="ENDTIME">%2$s</xliff:g> まで録画します"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"すべての予約"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">今後 %1$d 日間</item>
+ <item quantity="one">今後 %1$d 日間</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d分</item>
+ <item quantity="one">%1$d分</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d 件の新しい録画</item>
+ <item quantity="one">%1$d 件の新しい録画</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d 件の録画</item>
+ <item quantity="one">%1$d 件の録画</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d 件の録画予約</item>
+ <item quantity="one">%1$d 件の録画予約</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"再生"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"最初から再生"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"再生を再開"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"削除"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"録画を削除"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"再開"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"シーズン <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"予約を見る"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"続きを読む"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"録画の削除"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"削除するエピソードを選択してください。削除したエピソードは復元できませんのでご注意ください。"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"削除できる録画がありません。"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"再生済みのエピソードを選択"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"すべてのエピソードを選択"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"すべてのエピソードの選択を解除"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"再生済み(<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> 分)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"再生済み(<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> 秒)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"未再生"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d 件中 %1$d 件のエピソードを削除しました</item>
+ <item quantity="one">%2$d 件中 %1$d 件のエピソードを削除しました</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"優先度"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"最高"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"最低"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"<xliff:g id="RANK">%1$d</xliff:g> 番目"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"チャンネル"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"すべて"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"優先度の選択"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"同時に多数の番組を録画する場合は、優先度の高い番組だけが録画されます。"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"保存"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"1 回のみの録画を最優先"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"キャンセル"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"キャンセル"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"削除"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"停止"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"録画予約を見る"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"この番組のみ"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"現在~<xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"全シリーズ…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"このまま予約"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"この番組を代わりに録画"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"この録画をキャンセル"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"今すぐ見る"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"録画できます"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"録画を予約しました"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"録画予約が重複しています"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"録画"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"録画に失敗しました"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"録画予約を作成する番組情報を読み取っています"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"番組情報を読み取っています"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR のストレージ不足"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR を使用して番組を録画することはできますが、お使いの端末のストレージが十分ではないため、現在 DVR を使用できません。<xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB 以上の外部ストレージを接続し、手順に沿って端末のストレージと同じようにフォーマットしてください。"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"ストレージにアクセスできません"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR で使用しているストレージの一部にアクセスできません。DVR を再度有効にする前に、使用している外部ドライブを接続してください。アクセスできないストレージは削除することもできます。"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ストレージの削除"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"録画したコンテンツと録画予約がすべて失われます。"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"録音の停止"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"録画したコンテンツは保存されます。"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"録画を予約しましたが、他の予約と重なっています"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"録画を開始しましたが、他の予約と重なっています"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"「<xliff:g id="PROGRAMNAME">%1$s</xliff:g>」が録画されます。"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"「<xliff:g id="CHANNELNAME">%1$s</xliff:g>」を録画しています。"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"「<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>」は一部録画されません。"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"「<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>」、「<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>」は一部録画されません。"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"「<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>」、「<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>」、他 1 件の予約は一部録画されません。"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">「<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>」、「<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>」、他 %3$d 件の予約は一部録画されません。</item>
+ <item quantity="one">「<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>」、「<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>」、他 %3$d 件の予約は一部録画されません。</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"どの番組を録画しますか?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"録画時間の指定"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"予約済み"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"同じ番組が既に録画予約されています(<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>)。"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"録画済み"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"この番組は既に録画され、DVR ライブラリから利用できます。"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"録画された番組は見つかりませんでした。"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"関連の録画"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(番組の説明はありません)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d 件の録画</item>
+ <item quantity="one">%1$d 件の録画</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">"/"</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"「<xliff:g id="PROGRAMNAME">%1$s</xliff:g>」を録画予約から削除しました"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"チューナーが競合しているため、一部のみ録画されます。"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"チューナーが競合しているため、録画されません。"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"録画予約はまだありません。\n録画予約は番組ガイドから行えます。"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d 件の録画予約が競合しています</item>
+ <item quantity="one">%1$d 件の録画予約が競合しています</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"シリーズの設定"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"シリーズの録画を開始"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"シリーズの録画を停止"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"シリーズの録画を中止しますか?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"録画したエピソードは DVR ライブラリから利用できます。"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"停止"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"利用可能なエピソードはありません。\n利用可能になると録画されます。"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d分)</item>
+ <item quantity="one">(%1$d分)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"今日"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"明日"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"昨日"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"今日(<xliff:g id="TIME_RANGE">%1$s</xliff:g>)"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"明日(<xliff:g id="TIME_RANGE">%1$s</xliff:g>)"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"スコア"</string>
</resources>
diff --git a/res/values-ka-rGE/arrays.xml b/res/values-ka-rGE/arrays.xml
index 4c911685..1d6659a6 100644
--- a/res/values-ka-rGE/arrays.xml
+++ b/res/values-ka-rGE/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"სრული"</item>
<item msgid="8568284598210500589">"მასშტაბი"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ყველა არხი"</item>
- <item msgid="6897460857821394118">"ოჯახი/ბავშვები"</item>
- <item msgid="551257741825778215">"სპორტი"</item>
- <item msgid="452133796804325879">"საყიდლები"</item>
- <item msgid="3296058637230163031">"ფილმები"</item>
- <item msgid="1054540282883891201">"კომედია"</item>
- <item msgid="7900158429062595471">"მოგზაურობა"</item>
- <item msgid="3768998587825611787">"დრამა"</item>
- <item msgid="8340620094959282881">"განათლება"</item>
- <item msgid="7396447839483867269">"ცხოველები/ველური ბუნება"</item>
- <item msgid="4738043455148062673">"ახალი ამბები"</item>
- <item msgid="7405041316051047427">"თამაშები"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ყველა არხი"</item>
- <item msgid="7909003973960375395">"ოჯახი/ბავშვები"</item>
- <item msgid="3185279732911635789">"სპორტი"</item>
- <item msgid="4704858492065325964">"საყიდლები"</item>
- <item msgid="6083795019290250078">"ფილმები"</item>
- <item msgid="8302638329222449550">"კომედია"</item>
- <item msgid="3803709976021475052">"მოგზაურობა"</item>
- <item msgid="8116747365234169059">"დრამა"</item>
- <item msgid="7356447541595315913">"განათლება"</item>
- <item msgid="7511135485827589547">"ცხოველები/ველური ბუნება"</item>
- <item msgid="6961248112238009967">"ახალი ამბები"</item>
- <item msgid="6484685553679698447">"თამაშები"</item>
- <item msgid="2737158328243183190">"ხელოვნება"</item>
- <item msgid="6577176952650166615">"გართობა"</item>
- <item msgid="7886693831871777617">"ცხოვრების სტილი"</item>
- <item msgid="8145832312485577062">"მუსიკა"</item>
- <item msgid="1345789204804308580">"პრემიერა"</item>
- <item msgid="2736680312770771994">"ტექნოლოგიები/მეცნიერება"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"ყველა არხი"</item>
+ <item msgid="928298872841713530">"ოჯახი/ბავშვები"</item>
+ <item msgid="2751606947569857164">"სპორტი"</item>
+ <item msgid="7345749789651321496">"საყიდლები"</item>
+ <item msgid="167201149441442173">"ფილმები"</item>
+ <item msgid="525966731464264290">"კომედია"</item>
+ <item msgid="6096710741527327836">"მოგზაურობა"</item>
+ <item msgid="2851882187117833883">"დრამატული"</item>
+ <item msgid="78492781188719038">"განათლება"</item>
+ <item msgid="7221999662426308394">"ცხოველები/ველური ბუნება"</item>
+ <item msgid="375300513250925001">"ახალი ამბები"</item>
+ <item msgid="7746320336582330410">"თამაშები"</item>
+ <item msgid="1255741860568329178">"ხელოვნება"</item>
+ <item msgid="7603949681065702867">"გართობა"</item>
+ <item msgid="4453821994746804366">"ცხოვრების სტილი"</item>
+ <item msgid="3488534597567932843">"მუსიკა"</item>
+ <item msgid="7452153120614274095">"პრემიერა"</item>
+ <item msgid="8215762047341133299">"ტექნოლოგიები/მეცნიერება"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"პირდაპირი არხები"</item>
diff --git a/res/values-ka-rGE/rating_system_strings.xml b/res/values-ka-rGE/rating_system_strings.xml
index 249bb557..498d1d82 100644
--- a/res/values-ka-rGE/rating_system_strings.xml
+++ b/res/values-ka-rGE/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ka-rGE/strings.xml b/res/values-ka-rGE/strings.xml
index 831cdd05..72608bd4 100644
--- a/res/values-ka-rGE/strings.xml
+++ b/res/values-ka-rGE/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"წინა"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"პროგ. სახელმძღვანელო"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"წვდომაა ახალ არხებზე"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ხელმისაწ. ბმული არ არის"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის გახსნა"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"დახურ.წარწერები"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ჩვენების რეჟიმი"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ქვე-რეიტინგები"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"შეიყვანეთ თქვენი PIN ამ არხის საყურებლად"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"შეიყვანეთ თქვენი PIN ამ პროგრამის საყურებლად"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ამ პროგრამის ასაკობრივი შეზღუდვაა: <xliff:g id="RATING">%1$s</xliff:g>. მის საყურებლად, შეიყვანეთ PIN-კოდი"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"შეიყვანეთ თქვენი PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"მშობელთა კონტროლის დასაყენებლად შექმენით PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"შეიყვანეთ ახალი PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ღია კოდის ლიცენზიები"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ღია კოდის ლიცენზიები"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ვერსია"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"მსურს პირდაპირი არხების გაუმჯობესების ხელშეწყობა"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"პირდაპირი არხების გაუმჯობესების მიზნით და ავარიულად გათიშვებისა თუ გაჭედვების თავიდან ასაცილებლად, გამოყენების და დიაგნოსტიკური მონაცემების Google-თან გაზიარება."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ამ არხის საყურებლად დააჭირეთ „მარჯვენას“ და შეიყვანოთ თქვენი PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ამ პროგრამის საყურებლად დააჭირეთ „მარჯვენას“ და შეიყვანოთ თქვენი PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ამ პროგრამის რეიტინგია <xliff:g id="RATING">%1$s</xliff:g>.\nამ პროგრამის საყურებლად დააჭირეთ „მარჯვენას“ და შეიყვანოთ თქვენი PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"მხოლოდ აუდიო"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"სიგნალი სუსტია"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ინტერნეტთან კავშირი არ არის"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">ამ არხის დაკვრა <xliff:g id="END_TIME_1">%1$s</xliff:g>-მდე ვერ მოხერხდება, რადგან იწერება სხვა არხები. \n\nჩაწერის განრიგის კორექტირებისთვის, დააჭირეთ „მარჯვნივ“-ს.</item>
+ <item quantity="one">ამ არხის დაკვრა <xliff:g id="END_TIME_0">%1$s</xliff:g>-მდე ვერ მოხერხდება, რადგან იწერება სხვა არხი. \n\nჩაწერის განრიგის კორექტირებისთვის, დააჭირეთ „მარჯვნივ“-ს.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"უსათაურო"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"არხი დაბლოკილია"</string>
<string name="setup_category_new" msgid="2899355289563443627">"ახალი"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ხელმისაწვდომი არხები არ არის"</string>
<string name="setup_input_new" msgid="3337725672277046798">"ახალი"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"არ არის დაყენებული"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"მეტი წყაროს მიღება"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"დაათვალიერეთ აპები, რომლებიც პირდაპირ არხებს გთავაზობთ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"მეტი წყაროს მიღება"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"დაათვალიერეთ აპები, რომლებიც პირდაპირ არხებს გთავაზობთ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"ხელმისაწვდომია არხების ახალი წყაროები"</string>
<string name="new_sources_description" msgid="749649005588426813">"არხების ახალი წყაროები დამატებით არხებს გთავაზობთ.\nდააყენეთ ისინი ახლავე ან მოგვიანებით, არხების წყაროების პარამეტრებიდან."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ახლავე დაყენება"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"წყაროს ყველა არხი დამალულია.\nსაყურებლად აირჩიეთ მინიმუმ ერთი არხი."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ვიდეო მიუწვდომელი გახდა მოულოდნელად."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"ღილაკი „უკან“ დაკავშირებული მოწყობილობისთვისაა. გამოსასვლელად დააჭირეთ ღილაკს „მთავარი“."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"პირდაპირი არხები არ არის მხარდაჭერილი ამ მოწყობილობაზე Android Lollipop-ით."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"პირდაპირი არხები საჭიროებს ნებართვას ტელეპროგრამის წასაკითხად."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"დააყენეთ თქვენი წყაროები"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"პირდაპირი არხები ტრადიციულ სატელევიზიო არხებსა და აპების მიერ მოწოდებულ სტრიმინგის არხებს აერთიანებს. \n\nდასაწყებად, დააყენეთ არხების უკვე დაინსტალირებული წყაროები, ან დაათვალიერეთ Google Play Store და აღმოაჩინეთ მეტი აპი, რომლებიც პირდაპირ არხებს გთავაზობთ."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ჩანაწერები და განრიგები"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 წუთი"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 წუთი"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 საათი"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 საათი"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ბოლო"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"დაგეგმილი"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"სერიები"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"სხვა"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"არხის ჩაწერა ვერ მოხერხდება."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"პროგრამის ჩაწერა ვერ მოხერხდება."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> დაიგეგმა ჩასაწერად"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> იწერება ამ მომენტიდან <xliff:g id="ENDTIME">%2$s</xliff:g>-მდე"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"სრული განრიგი"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">შემდეგი %1$d დღე</item>
+ <item quantity="one">შემდეგი %1$d დღე</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d წუთი</item>
+ <item quantity="one">%1$d წუთი</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d ახალი ჩანაწერი</item>
+ <item quantity="one">%1$d ახალი ჩანაწერი</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d ჩანაწერი</item>
+ <item quantity="one">%1$d ჩანაწერი</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d ჩანაწერი დაიგეგმა</item>
+ <item quantity="one">%1$d ჩანაწერი დაიგეგმა</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ყურება"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"თავიდან დაკვრა"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"დაკვრის განახლება"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"წაშლა"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ჩანაწერების წაშლა"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"განახლება"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"სეზონი <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"განრიგის ნახვა"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"მეტის წაკითხვა"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ჩანაწერების წაშლა"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"აირჩიეთ ეპიზოდები, რომელთა წაშლაც გსურთ. წაშლის შემდეგ, მათი აღდგენა ვეღარ მოხერხდება."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"წასაშლელი ჩანაწერები არ არის."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"ნაყურები ეპიზოდების არჩევა"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"ყველა ეპიზოდის არჩევა"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ყველა მონიშვნის მოხსნა"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"ნაყურებია <xliff:g id="DURATION">%2$d</xliff:g>-დან <xliff:g id="WATCHED">%1$d</xliff:g> წუთი"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"ნაყურებია <xliff:g id="DURATION">%2$d</xliff:g>-დან <xliff:g id="WATCHED">%1$d</xliff:g> წამი"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"არასოდეს ნაყურები"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d-დან %1$d ეპიზოდი წაიშალა</item>
+ <item quantity="one">%2$d-დან %1$d ეპიზოდი წაიშალა</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"პრიორიტეტი"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"ყველაზე მაღალი"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ყველაზე დაბალი"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"№ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"არხები"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ნებისმიერი"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"აირჩიეთ პრიორიტეტი"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"თუ ჩასაწერად მეტისმეტად ბევრი პროგრამა დაიგეგმება, ჩაიწერება მხოლოდ მაღალი პრიორიტეტის მქონე პროგრამები."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"შენახვა"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ერთჯერად ჩანაწერებს მიენიჭოს მეტი პრიორიტეტი"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"გაუქმება"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"გაუქმება"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"დავიწყება"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"შეწყვეტა"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ჩაწერის განრიგის ნახვა"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"მხოლოდ ეს პროგრამა"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ახლა — <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"მთლიანი სერიალი…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"მაინც დაგეგმვა"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"სანაცვლოდ, ჩაიწეროს ეს"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ამ ჩანაწერის გაუქმება"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ახლავე ყურება"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"შესაძლებელია ჩაწერა"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ჩაწერა დაგეგმილია"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ჩაწერის კონფლიქტი"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"მიმდინარეობს ჩაწერა"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ჩაწერა ვერ მოხერხდა"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"მიმდინარეობს პროგრამების წაკითხვა ჩაწერის განრიგების შესაქმნელად"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"მიმდინარეობს პროგრამების წაკითხვა"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR მეტ მეხსიერებას საჭიროებს"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR-ის მეშვეობით პროგრამების ჩაწერა შესაძლებელია, თუმცა თქვენს მოწყობილობაზე ამჟამად ხელმისაწვდომი მეხსიერება DVR-ის მუშაობისთვის არასაკმარისია. გთხოვთ, დააკავშიროთ <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> გბაიტი ან მეტი მოცულობის დისკწამყვანი და მიჰყვეთ ინსტრუქციას, რომელიც დაგეხმარებათ, დააფორმატოთ ის მოწყობილობის მეხსიერების სახით."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"აკლია მეხსიერება"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR-ის მიერ გამოყენებული მეხსიერების ნაწილი ვერ მოიძებნა. DVR-ის ხელახლა ჩასართავად, გთხოვთ, დააკავშიროთ გარე დისკი, რომლითაც ადრე სარგებლობდით. თუ მეხსიერება ხელმისაწვდომი აღარ არის, შეგიძლიათ მეხსიერების დავიწყება აირჩიოთ."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"გსურთ მეხსიერების დავიწყება?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"მთელი თქვენი ჩაწერილი კონტენტი და ყველა განრიგი დაიკარგება."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"გსურთ ჩაწერის შეწყვეტა?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ჩაწერილი კონტენტი შეინახება."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ჩაწერა დაგეგმილია, თუმცა ის კონფლიქტშია"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ჩაწერა დაიწყო, თუმცა ის კონფლიქტშია"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ჩაიწერება."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> იწერება."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ნაწილობრივ არ ჩაიწერება."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> და <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ნაწილობრივ არ ჩაიწერება."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> და კიდევ ერთი განრიგი ნაწილობრივ არ ჩაიწერება."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> და კიდევ %3$d განრიგი ნაწილობრივ არ ჩაიწერება.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> და კიდევ %3$d განრიგი ნაწილობრივ არ ჩაიწერება.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"გსურთ ჩაწერა?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"რამდენი ხანი გსურთ, გაგრძელდეს ჩაწერა?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"უკვე დაგეგმილია"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"იგივე პროგრამა უკვე დაიგეგმა ჩასაწერად <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>-ზე."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"უკვე ჩაწერილია"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ეს პროგრამა უკვე ჩაწერილია და DVR ბიბლიოთეკაშია ხელმისაწვდომი."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ჩაწერილი პროგრამა ვერ მოიძებნა."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"დაკავშირებული ჩანაწერები"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(პროგრამის აღწერა არ არის)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d ჩანაწერი</item>
+ <item quantity="one">%1$d ჩანაწერი</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ამოიშალა ჩაწერის განრიგიდან"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ჩაიწერება ნაწილობრივ ტუნერის კონფლიქტების გამო."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"არ ჩაიწერება ტუნერის კონფლიქტების გამო."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ჩაწერა ჯერ დაგეგმილი არ არის.\nჩაწერის დაგეგმვა პროგრამების მეგზურიდან შეგიძლიათ."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d ჩაწერის კონფლიქტი</item>
+ <item quantity="one">%1$d ჩაწერის კონფლიქტი</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"სერიალის პარამეტრები"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"სერიალის ჩაწერის დაწყება"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"სერიალის ჩაწერის შეწყვეტა"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"გსურთ სერიალის ჩაწერის შეწყვეტა?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ჩაწერილი ეპიზოდები DVR ბიბლიოთეკაში კვლავ იქნება ხელმისაწვდომი."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"შეწყვეტა"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ეპიზოდები მიუწვდომელია.\nმათი ჩაწერა მოხდება მაშინ, როცა ისინი ხელმისაწვდომი გახდება."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d წუთი)</item>
+ <item quantity="one">(%1$d წუთი) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"დღეს"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"ხვალ"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"გუშინ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"დღეს, <xliff:g id="TIME_RANGE">%1$s</xliff:g>-ზე"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"ხვალ, <xliff:g id="TIME_RANGE">%1$s</xliff:g>-ზე"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"შეფასება"</string>
</resources>
diff --git a/res/values-kk-rKZ/arrays.xml b/res/values-kk-rKZ/arrays.xml
index 16324735..bbb0282c 100644
--- a/res/values-kk-rKZ/arrays.xml
+++ b/res/values-kk-rKZ/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Толық"</item>
<item msgid="8568284598210500589">"Масштабтау"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Барлық арналар"</item>
- <item msgid="6897460857821394118">"Отбасы/балалар"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Сатып алулар"</item>
- <item msgid="3296058637230163031">"Фильмдер"</item>
- <item msgid="1054540282883891201">"Комедия"</item>
- <item msgid="7900158429062595471">"Саяхат"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Білім"</item>
- <item msgid="7396447839483867269">"Жануарлар/жабайы табиғат"</item>
- <item msgid="4738043455148062673">"Жаңалықтар"</item>
- <item msgid="7405041316051047427">"Ойындар"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Барлық арналар"</item>
- <item msgid="7909003973960375395">"Отбасы/балалар"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Сатып алулар"</item>
- <item msgid="6083795019290250078">"Фильмдер"</item>
- <item msgid="8302638329222449550">"Комедия"</item>
- <item msgid="3803709976021475052">"Саяхат"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Білім"</item>
- <item msgid="7511135485827589547">"Жануарлар/жабайы табиғат"</item>
- <item msgid="6961248112238009967">"Жаңалықтар"</item>
- <item msgid="6484685553679698447">"Ойындар"</item>
- <item msgid="2737158328243183190">"Өнер"</item>
- <item msgid="6577176952650166615">"Ойын-сауық"</item>
- <item msgid="7886693831871777617">"Өмір салты"</item>
- <item msgid="8145832312485577062">"Музыка"</item>
- <item msgid="1345789204804308580">"Премьера"</item>
- <item msgid="2736680312770771994">"Технология/ғылым"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Барлық арналар"</item>
+ <item msgid="928298872841713530">"Отбасы/балалар"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Сатып алулар"</item>
+ <item msgid="167201149441442173">"Фильмдер"</item>
+ <item msgid="525966731464264290">"Комедия"</item>
+ <item msgid="6096710741527327836">"Саяхат"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Білім"</item>
+ <item msgid="7221999662426308394">"Жануарлар/жабайы табиғат"</item>
+ <item msgid="375300513250925001">"Жаңалықтар"</item>
+ <item msgid="7746320336582330410">"Ойындар"</item>
+ <item msgid="1255741860568329178">"Өнер"</item>
+ <item msgid="7603949681065702867">"Ойын-сауық"</item>
+ <item msgid="4453821994746804366">"Өмір салты"</item>
+ <item msgid="3488534597567932843">"Mузыка"</item>
+ <item msgid="7452153120614274095">"Премьера"</item>
+ <item msgid="8215762047341133299">"Технология/ғылым"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live арналары"</item>
diff --git a/res/values-kk-rKZ/rating_system_strings.xml b/res/values-kk-rKZ/rating_system_strings.xml
index 20e66344..efeb4715 100644
--- a/res/values-kk-rKZ/rating_system_strings.xml
+++ b/res/values-kk-rKZ/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-kk-rKZ/strings.xml b/res/values-kk-rKZ/strings.xml
index 56e72d5f..2a47972c 100644
--- a/res/values-kk-rKZ/strings.xml
+++ b/res/values-kk-rKZ/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Алдыңғы"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Бағдарламалар нұс-ғы"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Жаңа арналар қол жетім."</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Сілтеме қолжетімді емес"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын ашу"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Жасырын титрлер"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Дисплей режимі"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Ішкі бағалар"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Бұл арнаны көру үшін PIN кодын енгізіңіз"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Бұл бағдарламаны көру үшін PIN кодын енгізіңіз"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Бұл бағдарламаға <xliff:g id="RATING">%1$s</xliff:g> бағасы берілген. Оны көру үшін PIN кодын енгізіңіз"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN кодын енгізіңіз"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ата-аналық бақылауды орнату үшін PIN кодын жасаңыз"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Жаңа PIN кодын енгізіңіз"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Ашық бастапқы код лицензиялары"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Ашық бастапқы код лицензиялары"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Нұсқа"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Live TV қолданбасын жақсартуға көмектесу"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Анонимді пайдалану және диагностика деректерін Google жүйесімен бөлісіңіз, сонда Live TV қолданбасын жақсартып, жаңылыс не қатып қалу сияқты ақаулардың алдын аласыз."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Бұл арнаны көру үшін оңға түймесін басып, PIN кодын енгізіңіз"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Бұл бағдарламаны көру үшін оңға түймесін басып, PIN кодын енгізіңіз"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Бұл бағдарламаға <xliff:g id="RATING">%1$s</xliff:g> бағасы қойылған.\nБұл бағдарламаны көру үшін \"Оңға\" түймесін басып, PIN кодын енгізіңіз."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Тек аудио"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Cигнал әлсіз"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Интернетпен байланыс жоқ"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Басқа арналар жазылып жатқандықтан, бұл арна <xliff:g id="END_TIME_1">%1$s</xliff:g> дейін ойнатылмайды. \n\nЖазып алу кестесін реттеу үшін \"Оң жақ\" түймесін басыңыз.</item>
+ <item quantity="one">Басқа арна жазылып жатқандықтан, бұл арна <xliff:g id="END_TIME_0">%1$s</xliff:g> дейін ойнатылмайды. \n\nЖазып алу кестесін реттеу үшін \"Оң жақ\" түймесін басыңыз.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Тақырыпсыз"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Арна бөгелген"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Жаңа"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Қолжетімді арна жоқ"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Жаңа"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Реттелмеген"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Қосымша дереккөздерді алу"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Тікелей эфир арналарын ұсынатын қолданбаларды шолу"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Қосымша дереккөздерді алу"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Тікелей эфир арналарын ұсынатын қолданбаларды шолу"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Жаңа арна көздері қолжетімді"</string>
<string name="new_sources_description" msgid="749649005588426813">"Жаңа арна көздерінде ұсынатын арналар бар.\nОларды қазір орнатыңыз немесе арна көздері параметрінде кейінірек орындаңыз."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Қазір орнату"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Барлық көз арналар жасырылған.\nКөру үшін кемінде бір арнаны таңдаңыз."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Бейне белгісіз себеппен қолжетімсіз болып тұр"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"КЕРІ пернесі қосылған құрылғыға арналған. Шығу үшін НЕГІЗГІ пернесін басыңыз."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop жүйесі орнатылған құрылғыларда Live TV қолданбасына қолдау көрсетілмейді."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV үшін ТД тізімдерін оқу рұқсаты қажет."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Дерек көздерін орнату"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Live арналары қолданбалардағы ағынды арналармен қатар дәстүрлі теледидар арналарын да ұсынады. \n\nІсті бұрын орнатылған арна көздерін реттеуден бастаңыз. Тікелей эфир арналарын ұсынатын басқа қолданбаларды Google Play Store дүкенінен алуға болады."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Жазбалар және кестелер"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 минут"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 минут"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 сағат"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 сағат"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Жақындағы"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Жоспарланған"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Сериялар"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Басқалар"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Арнаны жазу мүмкін емес."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Бағдарламаны жазу мүмкін емес."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> бағдарламасын жазып алу жоспарланды"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> бағдарламасын қазірден бастап <xliff:g id="ENDTIME">%2$s</xliff:g> дейін жазу"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Толық кесте"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Келесі %1$d күн бойы</item>
+ <item quantity="one">Келесі %1$d күн бойы</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d минут</item>
+ <item quantity="one">%1$d минут</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d жаңа жазба</item>
+ <item quantity="one">%1$d жаңа жазба</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d жазба</item>
+ <item quantity="one">%1$d жазба</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d жазба жоспарланды</item>
+ <item quantity="one">%1$d жазба жоспарланды</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Сағат"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Басынан бастап ойнату"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Ойнатуды жалғастыру"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Жою"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Жазбаларды жою"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Жалғастыру"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-маусым"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Кестені көру"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Толығырақ оқу"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Жазбаларды жою"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Жойғыңыз келетін серияларды таңдаңыз. Олар біржола жойылады және қалпына келтірілмейді."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Жоюға болатын жазбалар жоқ."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Көрген серияларды таңдау"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Барлық серияларды таңдау"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Барлық серияларды таңдаудан алып тастау"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> минут көрілді (жалпы ұзақтығы: <xliff:g id="DURATION">%2$d</xliff:g>)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> секунд көрілді (жалпы ұзақтығы: <xliff:g id="DURATION">%2$d</xliff:g>)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Ешқашан көрмеген жазбалар"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d серия жойылды (жалпы саны: %2$d)</item>
+ <item quantity="one">%1$d серия жойылды (жалпы саны: %2$d)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Маңыздылық"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Ең жоғары"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Ең төмен"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"№ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Арналар"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Кез келген"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Маңыздылық деңгейін таңдау"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Бір мезгілде тым көп бағдарламаны жазып алу қажет болса, тек маңыздылығы жоғарылары ғана жазылады."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Сақтау"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Бір жолғы жазбалар ең маңызды болып табылады"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Бас тарту"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Бас тарту"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Жою"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Тоқтату"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Жазу кестесін көру"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Тек осы бағдарлама"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"қазір - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Барлық сериялар..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Бәрібір жазып алу"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Орнына мына бағдарламаны жазу"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Бұл жазып алу кестесінен бас тарту"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Қазір көру"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Жазып алуға болады"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Жазып алынады"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Жазу кестесінде қайшылық бар"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Жазылуда"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Жазу сәтсіз аяқталды"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Жазу кестелерін жасауға арналған оқу бағдарламалары"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Бағдарлама ақпараты оқылуда"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR көбірек бос орынды қажет етеді"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Бағдарламаларды DVR арқылы жазып алуға болады. Алайда DVR жұмысы үшін құрылғыда бос орын жеткіліксіз. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> ГБ не одан үлкен сыртқы дискіні жалғап, оны құрылғы жады ретінде форматтау қадамдарын орындаңыз."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Жад жоқ"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR пайдаланатын жадтың бір бөлігі жоқ. DVR құрылғысын қайта іске қосу үшін бұрын пайдаланған сыртқы дискіні жалғаңыз. Сондай-ақ егер жад бұдан әрі қолжетімді болмаса, оны жоюыңызға болады."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Жад жойылсын ба?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Барлық жазылған мазмұндар мен кестелер жойылады."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Жазу тоқтатылсын ба?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Жазылған мазмұн сақталады."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Жоспарланған, бірақ қайшылықтары бар"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Жазу басталды, бірақ қайшылықтары бар"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> жазылады."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> жазылуда."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> бағдарламасының кейбір бөліктері жазылмайды."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> және <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> бағдарламасының кейбір бөліктері жазылмайды."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> бағдарламаларының және тағы бір жоспарланған бағдарламаның кейбір бөліктері жазылмайды."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> бағдарламалары мен тағы %3$d бағдарламаның кейбір бөліктері жазылмайды.</item>
+ <item quantity="one"> <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> бағдарламалары мен жоспарланған тағы %3$d бағдарламаның кейбір бөліктері жазылмайды.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Нені жазып алғыңыз келеді?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Қаншалықты ұзақ жазасыз?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Әлдеқашан жоспарланған"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Бұл бағдарламаны жазып алу басқа уақытқа (<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>) әлдеқашан жоспарланған."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Бұрын жазылған"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Бұл бағдарлама бұрын жазылған және DVR кітапханасында бар."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Жазылған бағдарлама табылмады."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Қатысты жазбалар"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Бағдарлама сипаттамасы жоқ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d жазба</item>
+ <item quantity="one">%1$d жазба</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" /  "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> бағдарламасы жазып алу кестесінен өшірілді"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Тюнер қайшылықтарына байланысты толық жазылмайды."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Тюнер қайшылықтарына байланысты жазылмайды."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Кестеде ешқандай жазып алу белгіленбеген.\nМұны бағдарлама нұсқаулығынан жоспарлауға болады."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d жазу қайшылығы</item>
+ <item quantity="one">%1$d жазу қайшылығы</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Сериялар параметрлері"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Серияларды жазуды бастау"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Серияларды жазуды тоқтату"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Серияларды жазу тоқтатылсын ба?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Жазылған серияларды DVR кітапханасынан алуға болады."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Тоқтату"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Ешқандай серия қолжетімді емес.\nОларды қолжетімді болған кезде ғана жазып алуға болады."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d минут)</item>
+ <item quantity="one">(%1$d минут) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Бүгін"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Ертең"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Кеше"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Бүгін <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Ертең <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Ұпай саны"</string>
</resources>
diff --git a/res/values-km-rKH/arrays.xml b/res/values-km-rKH/arrays.xml
index 0762e6ed..e46312b4 100644
--- a/res/values-km-rKH/arrays.xml
+++ b/res/values-km-rKH/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"ពេញ"</item>
<item msgid="8568284598210500589">"ពង្រីក"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"គ្រប់ប៉ុស្តិ៍"</item>
- <item msgid="6897460857821394118">"គ្រួសារ/កុមារ"</item>
- <item msgid="551257741825778215">"កីឡា"</item>
- <item msgid="452133796804325879">"ទិញ​ទំនិញ"</item>
- <item msgid="3296058637230163031">"ភាពយន្ត"</item>
- <item msgid="1054540282883891201">"រឿង​កំប្លែង"</item>
- <item msgid="7900158429062595471">"ធ្វើដំណើរ"</item>
- <item msgid="3768998587825611787">"ល្ខោន"</item>
- <item msgid="8340620094959282881">"ការអប់រំ"</item>
- <item msgid="7396447839483867269">"សត្វ​ពាហនៈ/សត្វព្រៃ"</item>
- <item msgid="4738043455148062673">"ព័ត៌មាន"</item>
- <item msgid="7405041316051047427">"ការលេងហ្គេម"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"គ្រប់ប៉ុស្តិ៍"</item>
- <item msgid="7909003973960375395">"គ្រួសារ/កុមារ"</item>
- <item msgid="3185279732911635789">"កីឡា"</item>
- <item msgid="4704858492065325964">"ទិញ​ទំនិញ"</item>
- <item msgid="6083795019290250078">"ភាពយន្ត"</item>
- <item msgid="8302638329222449550">"រឿង​កំប្លែង"</item>
- <item msgid="3803709976021475052">"ធ្វើដំណើរ"</item>
- <item msgid="8116747365234169059">"ល្ខោន"</item>
- <item msgid="7356447541595315913">"ការអប់រំ"</item>
- <item msgid="7511135485827589547">"សត្វ​ពាហនៈ/សត្វព្រៃ"</item>
- <item msgid="6961248112238009967">"ព័ត៌មាន"</item>
- <item msgid="6484685553679698447">"ការលេងហ្គេម"</item>
- <item msgid="2737158328243183190">"សិល្បៈ"</item>
- <item msgid="6577176952650166615">"កម្សាន្ត"</item>
- <item msgid="7886693831871777617">"របៀបរស់នៅ"</item>
- <item msgid="8145832312485577062">"តន្ត្រី"</item>
- <item msgid="1345789204804308580">"បង្ហាញជូនលើដំបូង"</item>
- <item msgid="2736680312770771994">"បច្ចេក/វិទ្យាសាស្ត្រ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"គ្រប់​ឆានែល"</item>
+ <item msgid="928298872841713530">"គ្រួសារ/កុមារ"</item>
+ <item msgid="2751606947569857164">"កីឡា"</item>
+ <item msgid="7345749789651321496">"ទិញ​ទំនិញ"</item>
+ <item msgid="167201149441442173">"ភាពយន្ត"</item>
+ <item msgid="525966731464264290">"រឿង​កំប្លែង"</item>
+ <item msgid="6096710741527327836">"ធ្វើដំណើរ"</item>
+ <item msgid="2851882187117833883">"ល្ខោន"</item>
+ <item msgid="78492781188719038">"ការអប់រំ"</item>
+ <item msgid="7221999662426308394">"សត្វ​ពាហនៈ/សត្វព្រៃ"</item>
+ <item msgid="375300513250925001">"ព័ត៌មាន"</item>
+ <item msgid="7746320336582330410">"លេង​ហ្គេម​"</item>
+ <item msgid="1255741860568329178">"សិល្បៈ"</item>
+ <item msgid="7603949681065702867">"ការ​កម្សាន្ត"</item>
+ <item msgid="4453821994746804366">"របៀបរស់នៅ"</item>
+ <item msgid="3488534597567932843">"តន្ត្រី"</item>
+ <item msgid="7452153120614274095">"បង្ហាញជូនលើដំបូង"</item>
+ <item msgid="8215762047341133299">"បច្ចេក/វិទ្យាសាស្ត្រ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ប៉ុស្តិ៍ផ្សាយផ្ទាល់"</item>
diff --git a/res/values-km-rKH/rating_system_strings.xml b/res/values-km-rKH/rating_system_strings.xml
index bf188cb5..8f5df6b3 100644
--- a/res/values-km-rKH/rating_system_strings.xml
+++ b/res/values-km-rKH/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-km-rKH/strings.xml b/res/values-km-rKH/strings.xml
index 77f4edbd..98fa13f5 100644
--- a/res/values-km-rKH/strings.xml
+++ b/res/values-km-rKH/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"មុន"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"ការ​ណែនាំ​កម្មវិធី"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"មានប៉ុស្តិ៍ថ្មី"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"មិនមានតំណទេ"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"បើក <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"ចំណងជើង​បិទ"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"របៀប​បង្ហាញ"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ការ​វាយ​តម្លៃ​រង"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"បញ្ចូល​កូដ PIN របស់​អ្នក​ដើម្បី​មើល​​ឆានែល​នេះ"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"បញ្ចូល​កូដ PIN របស់​អ្នក​ដើម្បី​មើល​កម្មវិធី​នេះ"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"កម្មវិធីនេះត្រូវបានវាយតម្លៃ <xliff:g id="RATING">%1$s</xliff:g>។ បញ្ចូលកូដ PIN របស់អ្នកដើម្បីមើលកម្មវិធីនេះ"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"បញ្ចូល​កូដ PIN របស់​អ្នក"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"ដើម្បី​កំណត់​ការ​ពិនិត្យ​របស់​ឪពុកម្ដាយ អ្នក​ត្រូវ​បង្កើត​កូដ PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"បញ្ចូល​កូដ PIN ថ្មី"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"អាជ្ញាប័ណ្ណប្រភពកូដបើកចំហ"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"អាជ្ញាប័ណ្ណប្រភពកូដចំហ"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"កំណែ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ជួយធ្វើឲ្យប៉ុស្តិ៍ផ្សាយផ្ទាល់ប្រសើងជាងមុន"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"ចែករំលែកទិន្នន័យវិនិច្ឆ័យ និងទិន្នន័យប្រើប្រាស់អនាមិកជាមួយ Google នោះយើងនឹងអាចធ្វើឲ្យប៉ុស្តិ៍ផ្សាយបន្តផ្ទាល់ប្រសើរឡើង និងទប់ស្កាត់បញ្ហាដូចជា៖ ការគាំង និងការមិនដំណើរការជាដើម។"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ដើម្បី​មើល​ឆានែល​នេះ អ្នក​ត្រូវ​ចុច​កណ្ដុរស្ដាំ រួច​បញ្ចូល​កូដ PIN របស់​អ្នក"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ដើម្បី​មើល​កម្មវិធី​នេះ អ្នក​ត្រូវ​ចុច​កណ្ដុរស្ដាំ រួច​បញ្ចូល​កូដ PIN របស់​អ្នក"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"កម្មវិធីនេះត្រូវបានវាយតម្លៃ <xliff:g id="RATING">%1$s</xliff:g>។\n ដើម្បីមើលកម្មវិធីនេះ សូមចុច ស្តាំ រួចបញ្ចូលកូដ PIN របស់អ្នក។"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"តែ​អូឌីយ៉ូ​ប៉ុណ្ណោះ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"សញ្ញា​ខ្សោយ"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"គ្មានការតភ្ជាប់អ៊ីនធឺណិតទេ"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">ប៉ុស្តិ៍នេះមិនអាចចាក់បានទេរហូតដល់ម៉ោង <xliff:g id="END_TIME_1">%1$s</xliff:g> ដោយសារតែប៉ុស្តិ៍ផ្សេងទៀតកំពុងត្រូវបានថត។ \n\nចុច ស្តាំ ដើម្បីកែសម្រួលកាលវិភាគថត។</item>
+ <item quantity="one">ប៉ុស្តិ៍នេះមិនអាចចាក់បានទេរហូតដល់ម៉ោង <xliff:g id="END_TIME_0">%1$s</xliff:g> ដោយសារតែប៉ុស្តិ៍ផ្សេងទៀតកំពុងត្រូវបានថត។ \n\nចុច ស្តាំ ដើម្បីកែសម្រួលកាលវិភាគថត។</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"គ្មាន​ចំណងជើង"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"បាន​ទប់​ស្កាត់​ឆានែល"</string>
<string name="setup_category_new" msgid="2899355289563443627">"ថ្មី"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"មិនមានប៉ុស្តិ៍ទេ"</string>
<string name="setup_input_new" msgid="3337725672277046798">"ថ្មី"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"មិន​បាន​កំណត់"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"ទទួលយកប្រភពច្រើនទៀត"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"រុករកកម្មវិធីដែលមានផ្តល់ជូនប៉ុស្តិ៍ផ្សាយផ្ទាល់"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"ទទួលយកប្រភពច្រើនទៀត"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"រុករកកម្មវិធីដែលមានផ្តល់ជូនប៉ុស្តិ៍ផ្សាយផ្ទាល់"</string>
<string name="new_sources_title" msgid="3878933676500061895">"មានផ្តល់ជូនប្រភពប៉ុស្តិ៍ថ្មី"</string>
<string name="new_sources_description" msgid="749649005588426813">"ប្រភពប៉ុស្តិ៍ថ្មីមានប៉ុស្តិ៍ដែលត្រូវផ្តល់ជូន។\nដំឡើងប៉ុស្តិ៍ទាំងនោះឥឡូវនេះ ឬដំឡើងពេលក្រោយនៅក្នុងការកំណត់ប្រភពប៉ុស្តិ៍។"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ដំឡើងឥឡូវនេះ"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"រាល់​​ឆានែល​ប្រភព​គឺ​​លាក់​។ \n ជ្រើស​ឆា​នែ​ល​យ៉ាង​ហោច​ណាស់​មួយ​​ដើម្បី​​មើល​។"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"មិនបានរំពឹងថាមិនមានវីដេអូនេះទេ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"ប៊ូតុង​ថយក្រោយ​សម្រាប់​ឧបករណ៍​ដែល​បាន​ភ្ជាប់។ ចុច​ប៊ូតុង​ដើម ដើម្បី​ចាកចេញ។"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"ប៉ុស្តិ៍ផ្សាយផ្ទាល់មិនត្រូវបានគាំទ្រលើឧបករណ៍ដែលដំណើរការដោយ Android Lollipop នេះទេ។"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"ប៉ុស្តិ៍ផ្សាយផ្ទាល់ត្រូវការសិទ្ធិអនុញ្ញាតដើម្បីអានបញ្ជីទូរទស្សន៍។"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"កំណត់ប្រភពរបស់អ្នក"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ប៉ុស្តិ៍ផ្សាយផ្ទាល់ផ្សាភ្ជាប់បទពិសោធន៍ប្រើប្រាស់ប៉ុស្តិ៍ទូរទស្សន៍លក្ខណៈបុរាណជាមួយប៉ុស្តិ៍ស្រ្ទីមដែលផ្តល់ដោយកម្មវិធី។ \n\nចាប់ផ្តើមដោយកំណត់ប្រភពប៉ុស្តិ៍ដែលបានដំឡើងរួចហើយ។ ឬរុករកក្នុងហាង Google Play ដើម្បីរកកម្មវិធីច្រើនទៀតដែលផ្តល់ជូនប៉ុស្តិ៍ផ្សាយផ្ទាល់។"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ការថត និងកាលវិភាក"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 នាទី"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 នាទី"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ម៉ោង"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ម៉ោង"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ថ្មីៗ"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"បាន​កំណត់​ពេល"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"ស៊េរី"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"ផ្សេងៗ"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"មិនអាចថតប៉ុស្តិ៍នេះបានទេ"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"មិនអាចថតកម្មវិធីនេះបានទេ"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ត្រូវបានកំណត់ពេលដើម្បីថត"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ការថត <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ពីឥឡូវនេះដល់ <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"កាលវិភាគពេញហើយ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d ថ្ងៃបន្ទាប់</item>
+ <item quantity="one">%1$d ថ្ងៃបន្ទាប់</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d នាទី</item>
+ <item quantity="one">%1$d នាទី</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">ការថតថ្មី %1$d</item>
+ <item quantity="one">ការថតថ្មី %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">ការថត %1$d</item>
+ <item quantity="one">ការថត %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">ការថតដែលបានកំណត់ពេល %1$d</item>
+ <item quantity="one">ការថតដែលបានកំណត់ពេល %1$d</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ទស្សនា"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"ចាក់ពីដំបូង"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ចាក់​បន្ត"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"លុប"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"លុបការថត"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"បន្ត"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"វគ្គ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"មើលកាលវិភាគ"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"អាន​បន្ថែម"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"លុបការថត"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ជ្រើសភាគដែលអ្នកចង់លុប។ ពួកវាមិនអាចស្តារឡើវិញបានទេបន្ទាប់ពីលុបរួចហើយ។"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"មិនមានការថតដែលត្រូវលុបទេ"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"ជ្រើសភាគដែលបានមើល"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"ជ្រើសភាគទាំងអស់"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ដោះការជ្រើសភាគទាំងអស់"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"បានមើល <xliff:g id="WATCHED">%1$d</xliff:g> នៅនាទីទី <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"បានមើល <xliff:g id="WATCHED">%1$d</xliff:g> នៅវិនាទីទី <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"មិនដែលមើល"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">ភាគចំនួន %1$d ក្នុងចំណោម %2$d ត្រូវបានលុប</item>
+ <item quantity="one">ភាគចំនួន %1$d ក្នុងចំណោម %2$d ត្រូវបានលុប</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"អាទិភាព"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"ខ្ពស់បំផុត"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ទាបបំផុត"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"លេខ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ប៉ុស្តិ៍"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"មួយណាក៏បាន"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ជ្រើសអាទិភាព"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"នៅពេលដែលមានកម្មវិធីដែលត្រូវថតច្រើនពេកក្នុងពេលតែមួយ នោះមានតែកម្មវិធីដែលមានអាទិភាពខ្ពស់ជាងប៉ុណ្ណោះដែលនឹងត្រូវថត។"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"រក្សាទុក"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ការថតមួយដងមានអាទិភាពខ្ពស់បំផុត"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"បោះបង់"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"បោះបង់"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"បំភ្លេច"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"បញ្ឈប់"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"មើលកាលវិភាគថត"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"កម្មវិធីមួយនេះ"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ឥឡូវនេះ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"វគ្គទាំងមូល…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"កាលវិភាគទោះយ៉ាងណាក៏ដោយ"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"ថតកម្មវិធីនេះជំនួសវិញ"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"បោះបង់ការថតនេះ"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"មើលឥឡូវនេះ"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"អាចថតបាន"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"បានកំណត់ពេលការថត"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ការថតជាន់ម៉ោងគ្នា"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ការថត"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"បានបរាជ័យក្នុងការថត"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"កំពុងអានកម្មវិធីដើម្បីបង្កើតកាលវិភាគថត"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"កំពុងអានកម្មវិធី"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR ត្រូវការទំហំផ្ទុកបន្ថែមទៀត"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"អ្នកនឹងអាចថតកម្មវិធីដោយប្រើ DVR។ ទោះបីជាយ៉ាងណាក៏ដោយ ឥឡូវនេះមិនមានទំហំផ្ទុកគ្រប់គ្រាន់នៅលើឧបករណ៍របស់អ្នកដើម្បីអនុញ្ញាតឲ្យ DVR ដំណើរការនោះទេ។ សូមភ្ជាប់ទៅឧបករណ៍ផ្ទុកខាងក្រៅដែលមានទំហំផ្ទុក <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB ឬធំជាងនេះ បន្ទាប់មកអនុវត្តតាមជំហានទាំងនេះដើម្បីសម្អាតវាក្នុងនាមជាឧបករណ៍ផ្ទុក។"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"ឧបករណ៍ផ្ទុកដែលបានបាត់"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"ឧបករណ៍ផ្ទុកមួយចំនួនដែលប្រើដោយ DVR បានបាត់បង់។ សូមភ្ជាប់ថាសផ្ទុកផ្នែកខាងក្រៅដែលអ្នកបានប្រើពីមុន ដើម្បីបើកដំណើរការ DVR ឡើងវិញ ឬអ្នកអាចជ្រើសរើសធ្វើការបំភ្លេចឧបករណ៍ផ្ទុកនេះ ប្រសិនបើវាមិនអាចប្រើបានតទៅទៀត។"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"បំភ្លេចឧបករណ៍ផ្ទុកឬ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"មាតិកា និងកាលវិភាគដែលបានថតទុករបស់អ្នកទាំងអស់នឹងបាត់បង់។"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"បញ្ឈប់ការថតឬ?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"មាតិកាដែលបានថតនឹងត្រូវបានរក្សាទុក"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ការថតបានកំណត់ពេលហើយ ប៉ុន្តែមានម៉ោងជាន់គ្នា"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ការថតបានចាប់ផ្តើមប៉ុន្តែវាជាន់គ្នា"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> នឹងត្រូវបានថត។"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> កំពុងត្រូវបានថត។"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"ផ្នែកមួយចំនួននៃ <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> នឹងមិនត្រូវបានថតទេ។"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"ផ្នែកមួយចំនួននៃ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> និង <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> នឹងមិនត្រូវបានថតទេ។"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"ផ្នែកមួយចំនួននៃ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> និងកាលវិភាគមួយទៀតនឹងមិនត្រូវបានថតទេ។"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">ផ្នែកមួយចំនួននៃ <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> និងកាលវិភាគ %3$d ទៀតនឹងមិនត្រូវបានថតទេ។</item>
+ <item quantity="one">ផ្នែកមួយចំនួននៃ <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> និងកាលវិភាគ %3$d ទៀតនឹងមិនត្រូវបានថតទេ។</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"តើអ្នកចង់ថតដែរទេ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"តើអ្នកចង់ថតរយៈពេលប៉ុន្មានដែរ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"បានកំណត់ពេលរួចហើយ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"កម្មវិធីដូចគ្នានេះត្រូវបានកំណត់ពេលថតរួចហើយនៅម៉ោង <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"បានថតរួចហើយ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"កម្មវិធីនេះត្រូវបានថតរួចហើយ។ វាអាចប្រើបាននៅក្នុងបណ្ណាល័យ DVR ។"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"រកមិនឃើញកម្មវិធីដែលបានថតទេ"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ការថតដែលពាក់ព័ន្ធ"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(គ្មានការពិពណ៌នាអំពីកម្មវិធីទេ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">ការថត %1$d</item>
+ <item quantity="one">ការថត %1$d</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ត្រូវបានលុបចេញពីកាលវិភាគថត"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"នឹងមិនត្រូវបានថតពេញលេញនោះទេដោយសារតែអង្គរាវប៉ុស្តិ៍ជាន់គ្នា។"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"នឹងមិនត្រូវបានថតនោះទេដោយសារតែអង្គរាវប៉ុស្តិ៍ជាន់គ្នា។"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"មិនទាន់មានការថតនៅក្នុងកាលវិភាគនៅឡើយទេ។\nអ្នកអាចកំណត់ពេលថតចេញពីការណែនាំកម្មវិធីនេះ។"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">ការជាន់ម៉ោងថត %1$d</item>
+ <item quantity="one">ការជាន់ម៉ោងថត %1$d</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"ការកំណត់វគ្គ"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"ចាប់ផ្តើមថតវគ្គ"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"ឈប់ថតវគ្គ"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"បញ្ឈប់ការថតវគ្គឬ?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ភាគដែលបានថតនឹងនៅតែមាននៅក្នុងបណ្ណាល័យ DVR ។"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"បញ្ឈប់"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"មិនមានផ្តល់ជូនភាគណាមួយទេ។\nពួកវានឹងត្រូវបានថតបន្ទាប់ពីមានផ្តល់ជូន។"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d នាទី)</item>
+ <item quantity="one">(%1$d នាទី) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ថ្ងៃនេះ"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"ថ្ងៃស្អែក"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ម្សិលមិញ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ថ្ងៃនេះ"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ថ្ងៃស្អែក"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ពិន្ទុ"</string>
</resources>
diff --git a/res/values-kn-rIN/arrays.xml b/res/values-kn-rIN/arrays.xml
index eb376e7b..e6d19c9f 100644
--- a/res/values-kn-rIN/arrays.xml
+++ b/res/values-kn-rIN/arrays.xml
@@ -20,41 +20,27 @@
<string-array name="display_mode_labels">
<item msgid="2259828487212953611">"ಸಾಮಾನ್ಯ"</item>
<item msgid="2533030282864800794">"ಸಂಪೂರ್ಣ"</item>
- <item msgid="8568284598210500589">"ಜೂಮ್"</item>
+ <item msgid="8568284598210500589">"ಝೂಮ್"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ಎಲ್ಲಾ ಚಾನಲ್‌ಗಳು"</item>
- <item msgid="6897460857821394118">"ಕುಟುಂಬ/ಮಕ್ಕಳು"</item>
- <item msgid="551257741825778215">"ಕ್ರೀಡೆಗಳು"</item>
- <item msgid="452133796804325879">"ಶಾಪಿಂಗ್"</item>
- <item msgid="3296058637230163031">"ಚಲನಚಿತ್ರಗಳು"</item>
- <item msgid="1054540282883891201">"ಹಾಸ್ಯ ಪ್ರಧಾನ"</item>
- <item msgid="7900158429062595471">"ಪ್ರವಾಸ"</item>
- <item msgid="3768998587825611787">"ನಾಟಕ"</item>
- <item msgid="8340620094959282881">"ಶಿಕ್ಷಣ"</item>
- <item msgid="7396447839483867269">"ಪ್ರಾಣಿ/ವನ್ಯಜೀವಿ"</item>
- <item msgid="4738043455148062673">"ಸುದ್ದಿ"</item>
- <item msgid="7405041316051047427">"ಗೇಮಿಂಗ್"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ಎಲ್ಲಾ ಚಾನಲ್‌ಗಳು"</item>
- <item msgid="7909003973960375395">"ಕುಟುಂಬ/ಮಕ್ಕಳು"</item>
- <item msgid="3185279732911635789">"ಕ್ರೀಡೆಗಳು"</item>
- <item msgid="4704858492065325964">"ಶಾಪಿಂಗ್"</item>
- <item msgid="6083795019290250078">"ಚಲನಚಿತ್ರಗಳು"</item>
- <item msgid="8302638329222449550">"ಹಾಸ್ಯ ಪ್ರಧಾನ"</item>
- <item msgid="3803709976021475052">"ಪ್ರವಾಸ"</item>
- <item msgid="8116747365234169059">"ನಾಟಕ"</item>
- <item msgid="7356447541595315913">"ಶಿಕ್ಷಣ"</item>
- <item msgid="7511135485827589547">"ಪ್ರಾಣಿ/ವನ್ಯಜೀವಿ"</item>
- <item msgid="6961248112238009967">"ಸುದ್ದಿ"</item>
- <item msgid="6484685553679698447">"ಗೇಮಿಂಗ್"</item>
- <item msgid="2737158328243183190">"ಕಲೆ"</item>
- <item msgid="6577176952650166615">"ಮನರಂಜನೆ"</item>
- <item msgid="7886693831871777617">"ಜೀವನಶೈಲಿ"</item>
- <item msgid="8145832312485577062">"ಸಂಗೀತ"</item>
- <item msgid="1345789204804308580">"ಪ್ರೀಮಿಯರ್"</item>
- <item msgid="2736680312770771994">"ತಂತ್ರಜ್ಞಾನ/ವಿಜ್ಞಾನ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"ಎಲ್ಲಾ ಚಾನಲ್‌ಗಳು"</item>
+ <item msgid="928298872841713530">"ಕುಟುಂಬ/ಮಕ್ಕಳು"</item>
+ <item msgid="2751606947569857164">"ಕ್ರೀಡೆಗಳು"</item>
+ <item msgid="7345749789651321496">"ಶಾಪಿಂಗ್"</item>
+ <item msgid="167201149441442173">"ಚಲನಚಿತ್ರಗಳು"</item>
+ <item msgid="525966731464264290">"ಹಾಸ್ಯ ಪ್ರಧಾನ"</item>
+ <item msgid="6096710741527327836">"ಪ್ರಯಾಣ"</item>
+ <item msgid="2851882187117833883">"ನಾಟಕ"</item>
+ <item msgid="78492781188719038">"ವಿದ್ಯಾಭ್ಯಾಸ"</item>
+ <item msgid="7221999662426308394">"ಪ್ರಾಣಿ/ವನ್ಯಜೀವಿ"</item>
+ <item msgid="375300513250925001">"ಸುದ್ದಿ"</item>
+ <item msgid="7746320336582330410">"ಗೇಮಿಂಗ್"</item>
+ <item msgid="1255741860568329178">"ಕಲೆ"</item>
+ <item msgid="7603949681065702867">"ಮನರಂಜನೆ"</item>
+ <item msgid="4453821994746804366">"ಲೈಫ್‌ಸ್ಟೈಲ್‌‌"</item>
+ <item msgid="3488534597567932843">"ಸಂಗೀತ"</item>
+ <item msgid="7452153120614274095">"ಪ್ರೀಮಿಯರ್"</item>
+ <item msgid="8215762047341133299">"ತಂತ್ರಜ್ಞಾನ/ವಿಜ್ಞಾನ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ಲೈವ್‌ ಚಾನಲ್‌ಗಳು"</item>
diff --git a/res/values-kn-rIN/rating_system_strings.xml b/res/values-kn-rIN/rating_system_strings.xml
index 7f3c869a..4d878099 100644
--- a/res/values-kn-rIN/rating_system_strings.xml
+++ b/res/values-kn-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-kn-rIN/strings.xml b/res/values-kn-rIN/strings.xml
index e9e0127c..adc99656 100644
--- a/res/values-kn-rIN/strings.xml
+++ b/res/values-kn-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"ಹಿಂದೆ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"ಕಾರ್ಯಕ್ರಮ ಮಾರ್ಗಸೂಚಿ"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"ಹೊಸ ಚಾನಲ್‌ಗಳು ಲಭ್ಯವಿವೆ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ಯಾವುದೇ ಲಿಂಕ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ತೆರೆಯಿರಿ"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"ಮುಚ್ಚಿದ ಶೀರ್ಷಿಕೆಗಳು"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ಪ್ರದರ್ಶನ ಮೋಡ್"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ಉಪ-ರೇಟಿಂಗ್‌ಗಳು"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ಈ ಚಾನಲ್‌ ವೀಕ್ಷಿಸಲು ನಿಮ್ಮ PIN ನಮೂದಿಸಿ"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ಈ ಕಾರ್ಯಕ್ರಮ ವೀಕ್ಷಿಸಲು ನಿಮ್ಮ PIN ನಮೂದಿಸಿ"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು <xliff:g id="RATING">%1$s</xliff:g> ರೇಟ್ ಮಾಡಲಾಗಿದೆ. ಈ ಕಾರ್ಯಕ್ರಮ ವೀಕ್ಷಿಸಲು ನಿಮ್ಮ ಪಿನ್‌ ನಮೂದಿಸಿ"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"ನಿಮ್ಮ PIN ಅನ್ನು ನಮೂದಿಸಿ"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"ಪೋಷಕ ನಿಯಂತ್ರಣಗಳನ್ನು ಹೊಂದಿಸಲು, PIN ರಚಿಸಿ"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"ಹೊಸ PIN ನಮೂದಿಸಿ"</string>
@@ -144,19 +144,21 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ಮುಕ್ತ ಮೂಲ ಪರವಾನಗಿಗಳು"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ಮುಕ್ತ ಮೂಲ ಪರವಾನಗಿಗಳು"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ಆವೃತ್ತಿ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ಲೈವ್ ಚಾನಲ್‌ಗಳನ್ನು ಸುಧಾರಿಸಲು ಸಹಾಯ ಮಾಡಿ"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"ಅನಾಮಧೇಯ ಬಳಕೆ ಮತ್ತು ಡಯಾಗ್ನೋಸ್ಟಿಕ್ಸ್ ಡೇಟಾವನ್ನು Google ಜೊತೆಗೆ ಹಂಚಿಕೊಳ್ಳಿ, ಈ ಮೂಲಕ ನಮಗೆ ಲೈವ್ ಚಾನಲ್‌ಗಳನ್ನು ಉತ್ತಮಗೊಳಿಸಲು ಹಾಗೂ ಕ್ರ್ಯಾಶಿಂಗ್ ಮತ್ತು ಫ್ರೀಜಿಂಗ್‌ನಂತಹ ಸಮಸ್ಯೆಗಳನ್ನು ತಡೆಯಲು ಸಾಧ್ಯವಾಗುತ್ತದೆ."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ಈ ಚಾನಲ್ ಅನ್ನು ವೀಕ್ಷಿಸಲು, ಬಲಕ್ಕೆ ಒತ್ತಿ ಮತ್ತು ನಿಮ್ಮ PIN ಅನ್ನು ನಮೂದಿಸಿ"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಬಲಕ್ಕೆ ಒತ್ತಿ ಮತ್ತು ನಿಮ್ಮ PIN ಅನ್ನು ನಮೂದಿಸಿ"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು <xliff:g id="RATING">%1$s</xliff:g> ರೇಟ್ ಮಾಡಲಾಗಿದೆ.\nಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಬಲಕ್ಕೆ ಒತ್ತಿ ಮತ್ತು ನಿಮ್ಮ ಪಿನ್ ನಮೂದಿಸಿ."</string>
- <string name="tvview_channel_locked_no_permission" msgid="677653135227590620">"ಈ ಚಾನಲ್ ವೀಕ್ಷಿಸಲು, ಡೀಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
- <string name="tvview_content_locked_no_permission" msgid="2279126235895507764">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಡೀಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
- <string name="tvview_content_locked_format_no_permission" msgid="5690794624572767106">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು <xliff:g id="RATING">%1$s</xliff:g> ರೇಟ್ ಮಾಡಲಾಗಿದೆ.\nಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಡೀಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
+ <string name="tvview_channel_locked_no_permission" msgid="677653135227590620">"ಈ ಚಾನಲ್ ವೀಕ್ಷಿಸಲು, ಡಿಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
+ <string name="tvview_content_locked_no_permission" msgid="2279126235895507764">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಡಿಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
+ <string name="tvview_content_locked_format_no_permission" msgid="5690794624572767106">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು <xliff:g id="RATING">%1$s</xliff:g> ರೇಟ್ ಮಾಡಲಾಗಿದೆ.\nಈ ಕಾರ್ಯಕ್ರಮವನ್ನು ವೀಕ್ಷಿಸಲು, ಡಿಫಾಲ್ಟ್ ಲೈವ್ ಟಿವಿ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಿ."</string>
<string name="shrunken_tvview_content_locked" msgid="7686397981042364446">"ಕಾರ್ಯಕ್ರಮವನ್ನು ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="shrunken_tvview_content_locked_format" msgid="3720284198877900916">"ಈ ಕಾರ್ಯಕ್ರಮವನ್ನು <xliff:g id="RATING">%1$s</xliff:g> ಎಂದು ರೇಟ್‌ ಮಾಡಲಾಗಿದೆ."</string>
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ಆಡಿಯೊ ಮಾತ್ರ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"ದುರ್ಬಲ ಸಿಗ್ನಲ್"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ಇಂಟರ್ನೆಟ್ ಸಂಪರ್ಕವಿಲ್ಲ"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">ಇತರ ಚಾನಲ್‌ಗಳು ರೆಕಾರ್ಡ್ ಆಗುತ್ತಿರುವ ಕಾರಣ <xliff:g id="END_TIME_1">%1$s</xliff:g> ವರೆಗೂ ಈ ಚಾನಲ್‌ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. \n\nರೆಕಾರ್ಡ್ ಮಾಡುವ ವೇಳಾಪಟ್ಟಿಯನ್ನು ಸರಿಹೊಂದಿಸಲು ಬಲಕ್ಕೆ ಒತ್ತಿರಿ.</item>
+ <item quantity="other">ಇತರ ಚಾನಲ್‌ಗಳು ರೆಕಾರ್ಡ್ ಆಗುತ್ತಿರುವ ಕಾರಣ <xliff:g id="END_TIME_1">%1$s</xliff:g> ವರೆಗೂ ಈ ಚಾನಲ್‌ ಪ್ಲೇ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ. \n\nರೆಕಾರ್ಡ್ ಮಾಡುವ ವೇಳಾಪಟ್ಟಿಯನ್ನು ಸರಿಹೊಂದಿಸಲು ಬಲಕ್ಕೆ ಒತ್ತಿರಿ.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ಯಾವುದೇ ಶೀರ್ಷಿಕೆಯಿಲ್ಲ"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"ಚಾನಲ್ ನಿರ್ಬಂಧಿಸಲಾಗಿದೆ"</string>
<string name="setup_category_new" msgid="2899355289563443627">"ಹೊಸತು"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ಯಾವುದೇ ಚಾನಲ್‌ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="setup_input_new" msgid="3337725672277046798">"ಹೊಸತು"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"ಇನ್ನೂ ಹೊಂದಿಸಿಲ್ಲ"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"ಹೆಚ್ಚು ಮೂಲಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"ಲೈವ್ ಚಾನಲ್‌ಗಳನ್ನು ಒದಗಿಸುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"ಹೆಚ್ಚು ಮೂಲಗಳನ್ನು ಪಡೆದುಕೊಳ್ಳಿ"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"ಲೈವ್ ಚಾನಲ್‌ಗಳನ್ನು ಒದಗಿಸುವಂತಹ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಬ್ರೌಸ್ ಮಾಡಿ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"ಹೊಸ ಚಾನಲ್ ಮೂಲಗಳು ಲಭ್ಯವಿದೆ"</string>
<string name="new_sources_description" msgid="749649005588426813">"ಹೊಸ ಚಾನಲ್ ಮೂಲಗಳು ಆಫರ್ ಮಾಡಲು ಚಾನಲ್‌ಗಳನ್ನು ಹೊಂದಿವೆ.\n ಈಗ ಅವುಗಳನ್ನು ಹೊಂದಿಸಿ, ಅಥವಾ ಇದನ್ನು ಚಾನಲ್ ಮೂಲಗಳ ಸೆಟ್ಟಿಂಗ್‌ನಲ್ಲಿ ನಂತರ ಮಾಡಿ."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ಇದೀಗ ಹೊಂದಿಸಿ"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ಎಲ್ಲ ಮೂಲ ಚಾನಲ್‌ಗಳನ್ನು ಮರೆಮಾಡಲಾಗಿದೆ.\nವೀಕ್ಷಿಸಲು ಕನಿಷ್ಠ ಒಂದು ಚಾನಲ್‌‌ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ವೀಡಿಯೊ ಅನಿರೀಕ್ಷಿತವಾಗಿ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"ಸಂಪರ್ಕಪಡಿಸಲಾದ ಸಾಧನಕ್ಕಾಗಿ ಹಿಂದೆ ಕೀ. ನಿರ್ಗಮಿಸಲು ಮುಖಪುಟ ಬಟನ್ ಒತ್ತಿರಿ."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop ಹೊಂದಿರುವ ಈ ಸಾಧನದಲ್ಲಿ ಲೈವ್ ಚಾನಲ್‌ಗಳು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"ಟಿವಿ ಪಟ್ಟಿಗಳನ್ನು ರೀಡ್ ಮಾಡಲು ಲೈವ್ ಚಾನಲ್‌ಗಳಿಗೆ ಅನುಮತಿ ಅಗತ್ಯವಿದೆ."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"ನಿಮ್ಮ ಮೂಲಗಳನ್ನು ಹೊಂದಿಸಿ"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ಲೈವ್‌ ಚಾನಲ್‌ಗಳು, ಅಪ್ಲಿಕೇಶನ್‌ ಮೂಲಕ ಒದಗಿಸಲಾದ ಸ್ಟ್ರೀಮಿಂಗ್ ಚಾನಲ್‌ಗಳ ಜೊತೆಗೆ ಸಾಂಪ್ರದಾಯಿಕ ಟಿವಿ ಅನುಭವವನ್ನು ಒಳಗೊಂಡಿರುತ್ತದೆ. \n\nಈಗಾಗಲೇ ಸ್ಥಾಪಿಸಲಾದ ಚಾನಲ್‌‌ ಮೂಲಗಳನ್ನು ಹೊಂದಿಸುವ ಮೂಲಕ ಪ್ರಾರಂಭಿಸಿ. ಅಥವಾ ಲೈವ್‌ ಚಾನಲ್‌ಗಳನ್ನು ಆಫರ್‌ ಮಾಡುವಂತಹ ಇನ್ನಷ್ಟು ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ Google Play ಸ್ಟೋರ್‌ನಲ್ಲಿ ಬ್ರೌಸ್‌ ಮಾಡಿ."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು ಮತ್ತು ವೇಳಾಪಟ್ಟಿಗಳು"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 ನಿಮಿಷಗಳು"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 ನಿಮಿಷಗಳು"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ಗಂಟೆ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ಗಂಟೆಗಳು"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ಇತ್ತೀಚಿನದು"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"ನಿಗದಿಪಡಿಸಲಾಗಿದ್ದು"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"ಸರಣಿ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"ಇತರರು"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ಚಾನಲ್ ರೆಕಾರ್ಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"ಪ್ರೋಗ್ರಾಂ ರೆಕಾರ್ಡ್ ಮಾಡಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ಅನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ನಿಗದಿಪಡಿಸಲಾಗಿದೆ"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ಈಗಿನಿಂದ <xliff:g id="ENDTIME">%2$s</xliff:g> ವರೆಗೆ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"ಪೂರ್ಣ ವೇಳಾಪಟ್ಟಿ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">ಮುಂದಿನ %1$d ದಿನಗಳು</item>
+ <item quantity="other">ಮುಂದಿನ %1$d ದಿನಗಳು</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d ನಿಮಿಷಗಳು</item>
+ <item quantity="other">%1$d ನಿಮಿಷಗಳು</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d ಹೊಸ ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ <item quantity="other">%1$d ಹೊಸ ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ <item quantity="other">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳ ವೇಳಾಪಟ್ಟಿ</item>
+ <item quantity="other">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳ ವೇಳಾಪಟ್ಟಿ</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ವಾಚ್"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"ಪ್ರಾರಂಭದಿಂದ ಪ್ಲೇ ಮಾಡು"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ಪ್ಲೇ ಮುಂದುವರಿಸು"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"ಅಳಿಸಿ"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ರೆಕಾರ್ಡಿಂಗ್‌‌ಗಳನ್ನು ಅಳಿಸು"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"ಮುಂದುವರಿಸು"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"ಸೀಸನ್ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"ವೇಳಾಪ. ವೀಕ್ಷಿಸಿ"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"ಇನ್ನಷ್ಟು ಓದಿ"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ರೆಕಾರ್ಡಿಂಗ್‌ ಅಳಿಸಿ"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ನೀವು ಅಳಿಸಲು ಬಯಸುವಂತಹ ಸಂಚಿಕೆಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ. ಅವುಗಳನ್ನು ಒಮ್ಮೆ ಅಳಿಸಿದರೆ ಹಿಂಪಡೆಯಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ಅಳಿಸಲು ಯಾವುದೇ ರೆಕಾರ್ಡಿಂಗ್‌ಗಳಿಲ್ಲ."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"ವೀಕ್ಷಿಸಿದ ಸಂಚಿಕೆ ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"ಎಲ್ಲಾ ಸಂಚಿಕೆಗಳನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ಎಲ್ಲಾ ಸಂಚಿಕೆಗಳನ್ನು ಅಳಿಸಿ"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="WATCHED">%1$d</xliff:g> ನಿಮಿಷಗಳ ಕಾಲ ವೀಕ್ಷಿಸಲಾಗಿದೆ"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> ರಲ್ಲಿ <xliff:g id="WATCHED">%1$d</xliff:g> ಸೆಕೆಂಡುಗಳ ಕಾಲ ವೀಕ್ಷಿಸಲಾಗಿದೆ"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"ಎಂದಿಗೂ ವೀಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%2$d ರಲ್ಲಿ %1$d ಸಂಚಿಕೆಗಳನ್ನು ಅಳಿಸಲಾಗಿದೆ</item>
+ <item quantity="other">%2$d ರಲ್ಲಿ %1$d ಸಂಚಿಕೆಗಳನ್ನು ಅಳಿಸಲಾಗಿದೆ</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ಆದ್ಯತೆ"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"ಹೆಚ್ಚು"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ಅತಿ ಕಡಿಮೆ"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"ಸಂ. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ಚಾನಲ್‌ಗಳು"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ಯಾವುದಾದರೂ"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ಆದ್ಯತೆಯನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"ಏಕ ಕಾಲದಲ್ಲಿ ರೆಕಾರ್ಡ್‌ ಮಾಡಲು ಸಾಕಷ್ಟು ಕಾರ್ಯಕ್ರಮಗಳು ಇದ್ದ ಸಂದರ್ಭದಲ್ಲಿ, ಹೆಚ್ಚಿನ ಆದ್ಯತೆ ಇರುವುದನ್ನು ಮಾತ್ರ ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"ಉಳಿಸು"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ಒಂದು ಬಾರಿ ಮಾಡಿದ ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು ಹೆಚ್ಚಿನ ಆದ್ಯತೆ ಹೊಂದಿರುತ್ತದೆ"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"ರದ್ದುಮಾಡು"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"ರದ್ದುಮಾಡಿ"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"ಮರೆತುಬಿಡು"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"ನಿಲ್ಲಿಸು"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ರೆಕಾರ್ಡಿಂಗ್ ವೇಳಾಪಟ್ಟಿ ವೀಕ್ಷಿಸಿ"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ಈ ಏಕೈಕ ಪ್ರೋಗ್ರಾಂ"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ಈಗ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"ಸಂಪೂರ್ಣ ಸರಣಿ…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"ಹೇಗಾದರೂ ನಿಗದಿಪಡಿಸಿ"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"ಬದಲಿಗೆ ಇದನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಿ"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ಈ ರೆಕಾರ್ಡಿಂಗ್ ರದ್ದುಗೊಳಿಸಿ"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ಈಗ ವೀಕ್ಷಿಸಿ"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ರೆಕಾರ್ಡ್ ಮಾಡಬಹುದಾದ"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ರೆಕಾರ್ಡಿಂಗ್ ನಿಗದಿಪಡಿಸಲಾಗಿದೆ"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ರೆಕಾರ್ಡಿಂಗ್ ಸಂಘರ್ಷ"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ರೆಕಾರ್ಡ್ ಆಗುತ್ತಿದೆ"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ರೆಕಾರ್ಡಿಂಗ್ ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"ರೆಕಾರ್ಡಿಂಗ್ ವೇಳಾಪಟ್ಟಿಗಳನ್ನು ರಚಿಸಲು ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ರೀಡ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ರೀಡ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR ಗೆ ಹೆಚ್ಚಿನ ಸಂಗ್ರಹಣೆಯ ಅಗತ್ಯವಿದೆ"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR ಮೂಲಕ ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ನಿಮಗೆ ಸಾಧ್ಯವಾಗುತ್ತದೆ. ಅದಾಗ್ಯೂ DVR ಗೆ ಕೆಲಸ ಮಾಡಲು ಇದೀಗ ನಿಮ್ಮ ಸಾಧನದಲ್ಲಿ ಸಾಕಷ್ಟು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ. ದಯವಿಟ್ಟು <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB ಅಥವಾ ಅದಕ್ಕಿಂತ ಹೆಚ್ಚಿನ ಬಾಹ್ಯ ಡ್ರೈವ್‌ಗೆ ಸಂಪರ್ಕಪಡಿಸಿ ಮತ್ತು ಸಾಧನ ಸಂಗ್ರಹಣೆಯಂತೆ ಫಾರ್ಮ್ಯಾಟ್‌ ಮಾಡಲು ಹಂತಗಳನ್ನು ಅನುಸರಿಸಿ."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"ಸಂಗ್ರಹಣೆ ಕಾಣೆಯಾಗಿದೆ"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR ಮೂಲಕ ಬಳಸಲಾದ ಕೆಲವು ಸಂಗ್ರಹಣೆಯು ಕಾಣೆಯಾಗಿದೆ. ನೀವು DVR ಮರು-ಸಕ್ರಿಯಗೊಳಿಸುವ ಮೊದಲು ಬಳಸಲಾದ ಬಾಹ್ಯ ಡ್ರೈವ್ ಅನ್ನು ಸಂಪರ್ಕಪಡಿಸಿ. ಪರ್ಯಾಯವಾಗಿ, ಇನ್ನೂ ಮುಂದೆ ಲಭ್ಯವಿಲ್ಲದಿದ್ದರೆ ಸಂಗ್ರಹಣೆಯನ್ನು ಮರೆಯಲು ನೀವು ಆಯ್ಕೆಮಾಡಬಹುದು."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ಸಂಗ್ರಹಣೆಯನ್ನು ಮರೆತಿರುವಿರಾ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"ನಿಮ್ಮ ಎಲ್ಲಾ ರೆಕಾರ್ಡ್ ಮಾಡಲಾದ ವಿಷಯ ಮತ್ತು ವೇಳಾಪಟ್ಟಿಗಳು ಕಳೆದುಹೋಗುತ್ತವೆ."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸುವುದೇ?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾದ ವಿಷಯವನ್ನು ಉಳಿಸಲಾಗುತ್ತದೆ."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ರೆಕಾರ್ಡಿಂಗ್ ನಿಗದಿಪಡಿಸಲಾಗಿದೆ ಆದರೆ ಸಂಘರ್ಷಣೆಗಳನ್ನು ಹೊಂದಿದೆ"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭಿಸಲಾಗಿದೆ ಆದರೆ ಸಂಘರ್ಷಣೆಗಳನ್ನು ಹೊಂದಿದೆ"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ಅನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ನ ಕೆಲವು ಭಾಗಗಳನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ನ ಕೆಲವು ಭಾಗಗಳನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ಮತ್ತು ಇನ್ನೊಂದು ವೇಳಾಪಟ್ಟಿಯನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುವುದಿಲ್ಲ."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one"> <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ಮತ್ತು %3$d ಕ್ಕಿಂತ ಹೆಚ್ಚಿನ ಕೆಲವು ಭಾಗಗಳ ವೇಳಾಪಟ್ಟಿಗಳನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</item>
+ <item quantity="other"> <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ಮತ್ತು %3$d ಕ್ಕಿಂತ ಹೆಚ್ಚಿನ ಕೆಲವು ಭಾಗಗಳ ವೇಳಾಪಟ್ಟಿಗಳನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುವುದಿಲ್ಲ.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"ನೀವು ಏನನ್ನು ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸುತ್ತೀರಿ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"ನೀವು ಎಷ್ಟು ಸಮಯ ರೆಕಾರ್ಡ್ ಮಾಡಲು ಬಯಸುವಿರಿ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ಈಗಾಗಲೇ ನಿಗದಿಪಡಿಸಲಾಗಿದೆ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"ಅದೇ ಕಾರ್ಯಕ್ರಮವನ್ನು ಈಗಾಗಲೇ <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> ಸಮಯಕ್ಕೆ ರೆಕಾರ್ಡ್ ಮಾಡಲು ನಿಗದಿಪಡಿಸಲಾಗಿದೆ."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ಈಗಾಗಲೇ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗಿದೆ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ಈ ಪ್ರೋಗ್ರಾಂ ಅನ್ನು ಈಗಾಗಲೇ ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗಿದೆ. ಇದು DVR ಲೈಬ್ರರಿಯಲ್ಲಿ ಲಭ್ಯವಿದೆ."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾದ ಕಾರ್ಯಕ್ರಮ ಕಂಡುಬಂದಿಲ್ಲ."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ಸಂಬಂಧಿಸಿದ ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ಯಾವುದೇ ಪ್ರೋಗ್ರಾಂ ವಿವರಣೆಯಿಲ್ಲ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ <item quantity="other">%1$d ರೆಕಾರ್ಡಿಂಗ್‌ಗಳು</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"ರೆಕಾರ್ಡ್‌ ಮಾಡುವಿಕೆ ವೇಳಾಪಟ್ಟಿಯಿಂದ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ಟ್ಯೂನರ್ ಸಂಘರ್ಷಗಳ ಕಾರಣದಿಂದಾಗಿ ಭಾಗಶಃ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ಟ್ಯೂನರ್ ಸಂಘರ್ಷಗಳ ಕಾರಣದಿಂದಾಗಿ ರೆಕಾರ್ಡ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ಯಾವುದೇ ರೆಕಾರ್ಡಿಂಗ್ ಇನ್ನೂ ನಿಗದಿಪಡಿಸಿಲ್ಲ.\n ನೀವು ಪ್ರೋಗ್ರಾಂ ಮಾರ್ಗಸೂಚಿ ಮೂಲಕ ರೆಕಾರ್ಡಿಂಗ್ ಅನ್ನು ನಿಗದಿಪಡಿಸಬಹುದು."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d ರೆಕಾರ್ಡಿಂಗ್ ಸಂಘರ್ಷಗಳು</item>
+ <item quantity="other">%1$d ರೆಕಾರ್ಡಿಂಗ್ ಸಂಘರ್ಷಗಳು</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"ಸರಣಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"ಸರಣಿ ರೆಕಾರ್ಡಿಂಗ್ ಪ್ರಾರಂಭ"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"ಸರಣಿ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸು"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"ಸರಣಿ ರೆಕಾರ್ಡಿಂಗ್ ನಿಲ್ಲಿಸುವುದೇ?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾದ ಭಾಗಗಳು DVR ಲೈಬ್ರರಿಯಲ್ಲಿ ಲಭ್ಯವಿರುತ್ತವೆ."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"ನಿಲ್ಲಿಸಿ"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ಯಾವುದೇ ಸಂಚಿಕೆಗಳು ಲಭ್ಯವಿಲ್ಲ.\nಅವುಗಳು ಒಮ್ಮೆ ಲಭ್ಯವಾದಾಗ ಅವುಗಳನ್ನು ರೆಕಾರ್ಡ್‌ ಮಾಡಲಾಗುತ್ತದೆ."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d ನಿಮಿಷಗಳು)</item>
+ <item quantity="other">(%1$d ನಿಮಿಷಗಳು)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ಇಂದು"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"ನಾಳೆ"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ನಿನ್ನೆ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ಇಂದು"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ನಾಳೆ"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ಸ್ಕೋರ್"</string>
</resources>
diff --git a/res/values-ko/arrays.xml b/res/values-ko/arrays.xml
index cdf412c8..da945d72 100644
--- a/res/values-ko/arrays.xml
+++ b/res/values-ko/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"전체"</item>
<item msgid="8568284598210500589">"확대/축소"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"모든 채널"</item>
- <item msgid="6897460857821394118">"가족/어린이"</item>
- <item msgid="551257741825778215">"스포츠"</item>
- <item msgid="452133796804325879">"쇼핑"</item>
- <item msgid="3296058637230163031">"영화"</item>
- <item msgid="1054540282883891201">"코미디"</item>
- <item msgid="7900158429062595471">"여행"</item>
- <item msgid="3768998587825611787">"드라마"</item>
- <item msgid="8340620094959282881">"교육"</item>
- <item msgid="7396447839483867269">"동물/야생 생물"</item>
- <item msgid="4738043455148062673">"뉴스"</item>
- <item msgid="7405041316051047427">"게임"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"모든 채널"</item>
- <item msgid="7909003973960375395">"가족/어린이"</item>
- <item msgid="3185279732911635789">"스포츠"</item>
- <item msgid="4704858492065325964">"쇼핑"</item>
- <item msgid="6083795019290250078">"영화"</item>
- <item msgid="8302638329222449550">"코미디"</item>
- <item msgid="3803709976021475052">"여행"</item>
- <item msgid="8116747365234169059">"드라마"</item>
- <item msgid="7356447541595315913">"교육"</item>
- <item msgid="7511135485827589547">"동물/야생 생물"</item>
- <item msgid="6961248112238009967">"뉴스"</item>
- <item msgid="6484685553679698447">"게임"</item>
- <item msgid="2737158328243183190">"예술"</item>
- <item msgid="6577176952650166615">"예능"</item>
- <item msgid="7886693831871777617">"라이프스타일"</item>
- <item msgid="8145832312485577062">"음악"</item>
- <item msgid="1345789204804308580">"프리미엄"</item>
- <item msgid="2736680312770771994">"기술/과학"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"모든 채널"</item>
+ <item msgid="928298872841713530">"가족/어린이"</item>
+ <item msgid="2751606947569857164">"스포츠"</item>
+ <item msgid="7345749789651321496">"쇼핑"</item>
+ <item msgid="167201149441442173">"영화"</item>
+ <item msgid="525966731464264290">"코미디"</item>
+ <item msgid="6096710741527327836">"여행"</item>
+ <item msgid="2851882187117833883">"드라마"</item>
+ <item msgid="78492781188719038">"교육"</item>
+ <item msgid="7221999662426308394">"동물/야생 생물"</item>
+ <item msgid="375300513250925001">"뉴스"</item>
+ <item msgid="7746320336582330410">"게임"</item>
+ <item msgid="1255741860568329178">"예술"</item>
+ <item msgid="7603949681065702867">"예능"</item>
+ <item msgid="4453821994746804366">"라이프스타일"</item>
+ <item msgid="3488534597567932843">"음악"</item>
+ <item msgid="7452153120614274095">"프리미엄"</item>
+ <item msgid="8215762047341133299">"기술/과학"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"실시간 채널"</item>
diff --git a/res/values-ko/rating_system_strings.xml b/res/values-ko/rating_system_strings.xml
index 8ce3d58c..80045c8e 100644
--- a/res/values-ko/rating_system_strings.xml
+++ b/res/values-ko/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index aa2a124a..4e9fa6a6 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"이전"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"프로그램 가이드"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"새 채널 사용 가능"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"사용 가능한 링크 없음"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> 열기"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"자막"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"표시 모드"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"하위 등급"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"PIN을 입력하여 이 채널 시청"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"PIN을 입력하여 이 프로그램 시청"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"이 프로그램의 등급은 <xliff:g id="RATING">%1$s</xliff:g>입니다. 이 프로그램을 감상하려면 PIN을 입력하세요."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN 입력"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"PIN을 생성하여 자녀 보호 기능 설정"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"새 PIN 입력"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"오픈소스 라이선스"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"오픈소스 라이선스"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"버전"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"실시간 채널 개선에 도움 주기"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google에서 실시간 채널을 향상하고 다운과 정지 등의 문제를 방지할 수 있도록 익명의 사용 및 진단 데이터를 공유합니다."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"이 채널을 보려면 오른쪽을 누르고 PIN을 입력하세요."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"이 프로그램을 보려면 오른쪽을 누르고 PIN을 입력하세요."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"이 프로그램의 시청 등급은 <xliff:g id="RATING">%1$s</xliff:g>입니다.\n이 프로그램을 보려면 오른쪽을 누르고 PIN을 입력하세요."</string>
@@ -159,6 +157,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"오디오 전용"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"신호 약함"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"인터넷에 연결되지 않았습니다."</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">다른 채널을 녹화 중이므로 <xliff:g id="END_TIME_1">%1$s</xliff:g>까지 이 채널을 재생할 수 없습니다. \n\n녹화 일정을 조정하려면 오른쪽을 누르세요.</item>
+ <item quantity="one">다른 채널을 녹화 중이므로 <xliff:g id="END_TIME_0">%1$s</xliff:g>까지 이 채널을 재생할 수 없습니다. \n\n녹화 일정을 조정하려면 오른쪽을 누르세요.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"제목 없음"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"차단된 채널"</string>
<string name="setup_category_new" msgid="2899355289563443627">"새 소스"</string>
@@ -170,8 +172,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"이용할 수 있는 채널이 없습니다."</string>
<string name="setup_input_new" msgid="3337725672277046798">"새 입력"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"설정되지 않음"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"더 많은 소스 다운로드"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"실시간 채널을 제공하는 앱 탐색"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"더 많은 소스 다운로드"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"실시간 채널을 제공하는 앱 탐색"</string>
<string name="new_sources_title" msgid="3878933676500061895">"새로운 채널 소스 이용 가능"</string>
<string name="new_sources_description" msgid="749649005588426813">"새로운 채널 소스에서 제공되는 채널이 있습니다.\n지금 채널 소스를 설정하거나 채널 소스 설정에서 나중에 할 수도 있습니다."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"지금 설정"</string>
@@ -189,8 +191,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"모든 소스 채널이 숨겨져 있습니다.\n시청할 채널을 하나 이상 선택하세요."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"예기치 않게 동영상을 사용할 수 없습니다."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"뒤로 키는 연결된 기기에 사용됩니다. 종료하려면 홈 버튼을 누르세요."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"실시간 채널은 이 Android Lollipop 기기에서 지원되지 않습니다."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"TV 목록을 읽으려면 실시간 채널에 권한이 필요합니다."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"소스 설정"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"실시간 채널은 기존 TV 채널 환경과 앱에서 제공하는 스트리밍 채널을 결합합니다. \n\n이미 설치된 채널 소스를 설정하여 시작하거나 Google Play 스토어에서 실시간 채널을 제공하는 더 많은 앱을 찾아보세요."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"녹화 및 일정"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10분"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30분"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1시간"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3시간"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"최근"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"예약"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"시리즈"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"기타"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"현재 채널을 녹화할 수 없습니다."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"현재 프로그램을 녹화할 수 없습니다."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>이(가) 녹화 예약되었습니다."</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"지금부터 <xliff:g id="ENDTIME">%2$s</xliff:g>까지 <xliff:g id="PROGRAMNAME">%1$s</xliff:g> 녹화"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"전체 일정"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">다음 %1$d일</item>
+ <item quantity="one">다음 %1$d일</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d분</item>
+ <item quantity="one">%1$d분</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">새로운 녹화 %1$d개</item>
+ <item quantity="one">새로운 녹화 %1$d개</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">녹화 %1$d개</item>
+ <item quantity="one">녹화 %1$d개</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">예약된 녹화 %1$d개</item>
+ <item quantity="one">예약된 녹화 %1$d개</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"시계"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"처음부터 재생"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"이어서 보기"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"삭제"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"녹화된 프로그램 삭제"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"재개"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"시즌 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"일정 보기"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"자세히 알아보기"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"녹화 삭제"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"삭제하려는 에피소드를 선택하세요. 삭제 후에는 복구할 수 없습니다."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"삭제할 녹화가 없습니다."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"시청한 에피소드 선택"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"모든 에피소드 선택"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"모든 에피소드 선택 취소"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g>분 시청함"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g>초 시청함"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"시청하지 않은 녹화"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">에피소드 %1$d/%2$d개 삭제됨</item>
+ <item quantity="one">에피소드 %1$d/%2$d개 삭제됨</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"우선순위"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"가장 높음"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"가장 낮음"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"아니요. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"채널"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"임의"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"우선순위 선택"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"동시에 녹화해야 하는 프로그램이 너무 많은 경우 우선순위가 높은 프로그램만 녹화됩니다."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"저장"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"일회 녹화의 우선순위가 가장 높음"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"취소"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"취소"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"삭제"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"중지"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"녹화 일정 보기"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"이 프로그램만"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"지금 - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"전체 시리즈…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"일정 예약하기"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"대신 이 항목을 녹화하기"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"이 녹화 취소하기"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"지금 보기"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"녹화 가능"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"녹화 예약됨"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"녹화 예약 충돌"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"녹화 중"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"녹화 실패"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"프로그램을 확인하고 녹화 일정을 만듭니다."</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"프로그램 정보 읽는 중"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR에 저장용량이 더 필요합니다."</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR을 사용하여 프로그램을 녹화할 수 있습니다. 그러나 DVR을 사용하기에는 기기에 남아있는 저장용량이 충분하지 않습니다. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB 이상의 외부 드라이브를 연결하고 외부 드라이브를 기기 저장소로 포맷하기 위한 단계를 따르세요."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"저장소 없음"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR에 사용되던 일부 저장소가 없습니다. 사용하던 외부 드라이브를 연결한 다음 DVR을 다시 사용 설정하시기 바랍니다. 또는 저장소를 더 이상 사용할 수 없는 경우 삭제할 수 있습니다."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"저장소를 삭제하시겠습니까?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"기록된 모든 콘텐츠 및 일정이 삭제됩니다."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"녹화를 중지하시겠습니까?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"녹화된 콘텐츠가 저장됩니다."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"녹화가 예약되었으나 충돌이 있음"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"녹화가 시작되었으나 충돌이 있음"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>이(가) 녹화됩니다."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g>이(가) 녹화 중입니다."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>의 일부는 녹화되지 않습니다."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>의 일부 및 <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>은(는) 녹화되지 않습니다."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>의 일부, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> 외 1개 일정이 녹화되지 않습니다."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>의 일부, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> 외 %3$d개 일정이 녹화되지 않습니다.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>의 일부, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> 외 %3$d개 일정이 녹화되지 않습니다.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"무엇을 녹화하시겠습니까?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"얼마 동안 녹화하시겠습니까?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"이미 예약됨"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"동일한 프로그램이 이미 <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>에 녹화 예약되었습니다."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"이미 녹화됨"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"이 프로그램이 이미 녹화되었습니다. DVR 라이브러리에서 사용할 수 있습니다."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"녹화된 프로그램을 찾을 수 없습니다."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"관련 녹화"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(프로그램 설명 없음)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">녹화 %1$d개</item>
+ <item quantity="one">녹화 %1$d개</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>을(를) 녹화 일정에서 삭제했습니다."</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"튜너의 충돌로 인해 일부만 녹화됩니다."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"튜너의 충돌로 인해 녹화되지 않습니다."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"아직 예약된 녹화가 없습니다.\n프로그램 가이드에서 녹화를 예약할 수 있습니다."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">녹화 충돌 %1$d개</item>
+ <item quantity="one">녹화 충돌 %1$d개</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"시리즈 설정"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"시리즈 녹화 시작"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"시리즈 녹화 중지"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"시리즈 녹화를 중지하시겠습니까?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"녹화된 에피소드는 DVR 라이브러리에서 계속 사용할 수 있습니다."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"중지"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"사용할 수 있는 에피소드가 없습니다.\n사용 가능한 에피소드가 생기면 녹화됩니다."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d분)</item>
+ <item quantity="one">(%1$d분) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"오늘"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"내일"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"어제"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"오늘 <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"내일 <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"점수"</string>
</resources>
diff --git a/res/values-ky-rKG/arrays.xml b/res/values-ky-rKG/arrays.xml
index 36bb78d4..835274e6 100644
--- a/res/values-ky-rKG/arrays.xml
+++ b/res/values-ky-rKG/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Толук"</item>
<item msgid="8568284598210500589">"Ченөлчөм"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Бардык каналдар"</item>
- <item msgid="6897460857821394118">"Үй-бүлө/Балдар"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Соода-сатык"</item>
- <item msgid="3296058637230163031">"Тасмалар"</item>
- <item msgid="1054540282883891201">"Комедия"</item>
- <item msgid="7900158429062595471">"Саякат"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Билим алуу"</item>
- <item msgid="7396447839483867269">"Жаныбарлар дүйнөсү"</item>
- <item msgid="4738043455148062673">"Жаңылыктар"</item>
- <item msgid="7405041316051047427">"Оюн-зоок"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Бардык каналдар"</item>
- <item msgid="7909003973960375395">"Үй-бүлө/Балдар"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Соода-сатык"</item>
- <item msgid="6083795019290250078">"Тасмалар"</item>
- <item msgid="8302638329222449550">"Комедия"</item>
- <item msgid="3803709976021475052">"Саякат"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Билим алуу"</item>
- <item msgid="7511135485827589547">"Жаныбарлар дүйнөсү"</item>
- <item msgid="6961248112238009967">"Жаңылыктар"</item>
- <item msgid="6484685553679698447">"Оюн-зоок"</item>
- <item msgid="2737158328243183190">"Көркөм өнөрчүлүк"</item>
- <item msgid="6577176952650166615">"Көңүл ачуу"</item>
- <item msgid="7886693831871777617">"Жашоо мүнөзү"</item>
- <item msgid="8145832312485577062">"Музыка"</item>
- <item msgid="1345789204804308580">"Бет ачар"</item>
- <item msgid="2736680312770771994">"Техника/Илим"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Бардык каналдар"</item>
+ <item msgid="928298872841713530">"Үй-бүлө/Балдар"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Соода-сатык"</item>
+ <item msgid="167201149441442173">"Тасмалар"</item>
+ <item msgid="525966731464264290">"Комедия"</item>
+ <item msgid="6096710741527327836">"Саякат"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Билим алуу"</item>
+ <item msgid="7221999662426308394">"Жаныбарлар дүйнөсү"</item>
+ <item msgid="375300513250925001">"Жаңылыктар"</item>
+ <item msgid="7746320336582330410">"Оюндар"</item>
+ <item msgid="1255741860568329178">"Көркөм өнөрчүлүк"</item>
+ <item msgid="7603949681065702867">"Көңүл ачуу"</item>
+ <item msgid="4453821994746804366">"Жашоо мүнөзү"</item>
+ <item msgid="3488534597567932843">"Музыка"</item>
+ <item msgid="7452153120614274095">"Бет ачар"</item>
+ <item msgid="8215762047341133299">"Тех/Илим"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Түз ободогу каналдар"</item>
diff --git a/res/values-ky-rKG/rating_system_strings.xml b/res/values-ky-rKG/rating_system_strings.xml
index 98672b74..1d422a0c 100644
--- a/res/values-ky-rKG/rating_system_strings.xml
+++ b/res/values-ky-rKG/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ky-rKG/strings.xml b/res/values-ky-rKG/strings.xml
index 6526178b..2b9d37ab 100644
--- a/res/values-ky-rKG/strings.xml
+++ b/res/values-ky-rKG/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Мурунку"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Программа көрсөтмөсү"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Жаңы каналдар бар"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Шилтеме жеткиликсиз"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ачуу"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Жабык субттрлр"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Көрсөтүү режими"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Көмөкчү рейтинг"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Бул каналды көрүү үчүн PIN\'иңизди киргизиңиз"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Бул программаны көрүү үчүн PIN\'иңизди киргизиңиз"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Бул программанын рейтинги <xliff:g id="RATING">%1$s</xliff:g>. Бул программаны көрүү үчүн PIN\'ди киргизиңиз"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN\'иңизди киргизиңиз"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ата-энелер көзөмөлүн коюу үчүн, PIN код түзүңүз"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Жаңы PIN киргизиңиз"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Ачык программа уруксаттамалары"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Ачык программа уруксаттамалары"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Версиясы"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Түз ободогу каналдарды жакшыртууга жардам бериңиз"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Түз обо каналдарын жакшыртып, бузулуу жана тоңдуруу сыяктуу маселелердин алдын алышыбыз үчүн, колдонуу жана дарт аныктоо дайындарын Google менен жашыруун бөлүшүңүз."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Бул каналды көрүү үчүн, Оңго басып, PIN-иңизди киргизиңиз"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Бул программаны көрүү үчүн, Оңго басып, PIN-иңизди киргизиңиз"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Бул программанын рейтинги <xliff:g id="RATING">%1$s</xliff:g> \n Бул программаны көрүү үчүн, Оң баскычын басып, PIN\'иңизди киргизиңиз"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Аудио гана"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Начар сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Интернет туташуусу жок"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Бул каналды саат <xliff:g id="END_TIME_1">%1$s</xliff:g> чейин ойнотууга болбойт, себеби башка каналдар жаздырылууда. \n\nЖаздыруунун графигин өзгөртүү үчүн \"Оңго\" деген жебени басыңыз.</item>
+ <item quantity="one">Бул каналды саат <xliff:g id="END_TIME_0">%1$s</xliff:g> чейин ойнотууга болбойт, себеби башка канал жаздырылууда. \n\nЖаздыруунун графигин өзгөртүү үчүн \"Оңго\" деген жебени басыңыз.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Аталышы жок"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Канал бөгөттөлдү"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Жаңы"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Жеткиликтүү каналдар жок"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Жаңы"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Орнотулган жок"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Дагы булактарды алуу"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Түз ободогу каналдарды сунуштаган колдонмолорду серептөө"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Дагы булактарды алуу"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Түз ободогу каналдарды сунуштаган колдонмолорду серептөө"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Жаңы канал булактары бар"</string>
<string name="new_sources_description" msgid="749649005588426813">"Жаңы канал булактарында сунуштай турган каналдар бар.\nАларды азыр жөндөңүз же кийинчерээк канал булактарынын жөндөөсүнөн аткарыңыз."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Азыр жөндөө"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Бардык булак каналдары жашырылган.\nКөрүү үчүн кеминде бир канал тандаңыз."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Видео күтүүсүздөн жеткиликсиз болуп калды."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"АРТКА баскычы – туташкан түзмөккө. Чыгуу үчүн БАШКЫ баскычты басыңыз."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Бул Android Lollipop орнотулган түзмөктө Түз ободогу каналдар колдоого алынбайт."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Сыналгы тизмелерин оруу үчүн Түз ободогу каналдарга уруксат керек."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Булактарыңызды жөндөңүз"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Түз ободогу каналдарда - кадимки сыналгы каналдары менен орнотулган колдонмолор аркылуу көрсөтүлүүчү видеоканалдар камтылган. \n\nМурунтан эле орнотулган канал булактарын жөндөөдөн баштаңыз же Google Play Store\'дон башка медиа колдонмолорду карап көрүңүз."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Жаздыруулар жана графиги"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 мүнөт"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 мүнөт"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 саат"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 саат"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Акыркы"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ыраатталды"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Топтомдор"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Башкалар"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Каналды жаздыруу мүмкүн эмес."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Программаны жаздыруу мүмкүн эмес."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> программасы жаздыруу графигине кошулду"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> программасын азыркы убактан <xliff:g id="ENDTIME">%2$s</xliff:g> чейин жаздыруу"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Толук графиги"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Кийинки %1$d күн</item>
+ <item quantity="one">Кийинки %1$d күн</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d мүнөт</item>
+ <item quantity="one">%1$d мүнөт</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">жаңы %1$d жаздыруу</item>
+ <item quantity="one">жаңы %1$d жаздыруу</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d жаздыруу</item>
+ <item quantity="one">%1$d жаздыруу</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d жаздыруу ыраатталган</item>
+ <item quantity="one">%1$d жаздыруу ыраатталган</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Саат"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Башынан баштап ойнотуу"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Ойнотууну улантуу"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Жок кылуу"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Жаздырылган нерселерди жок кылуу"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Улантуу"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-сезон"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Графикти көрүү"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Көбүрөөк окуу"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Жаздырылган нерселерди жок кылуу"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Жок кылгыңыз келген серияларды тандаңыз. Алар жок кылынгандан кийин кайра калыбына келтирилбейт."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Жок кылына турган жаздыруулар жок."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Көргөн серияларды тандоо"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Бардык серияларды тандоо"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Бардык серияларды тандоодон чыгаруу"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> мүнөттөн <xliff:g id="WATCHED">%1$d</xliff:g> мүнөт көрүлгөн"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> секундадан <xliff:g id="WATCHED">%1$d</xliff:g> секунда көрүлгөн"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Эч качан көрүлгөн эмес"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d сериядан %1$d серия жок кылынды</item>
+ <item quantity="one">%2$d сериядан %1$d серия жок кылынды</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Артыкчылыктуу"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Эң жогорку"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Эң төмөн"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Жок. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Каналдар"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Баары"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Артыкчылыкты тандоо"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Бир эле убакта жаздыра турган программалардын саны өтө көп болгон учурда, эң жогорку артыкчылыгы барлары гана жаздырылат."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Сактоо"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Бир жолку жаздыруулар жогорку артыкчылыкка ээ болот"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Баш тартуу"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Жокко чыгаруу"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Унутуу"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Токтотуу"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Жаздыруу графигин көрүү"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Жалгыз ушул программа"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"азыр - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Бардык чыгарылыштары..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Баары бир графикке киргизилсин"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Анын ордуна бул жаздырылсын"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Бул жаздыруу жокко чыгарылсын"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Азыр көрүңүз"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Жаздырууга болот"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Пландаштырылган жаздыруу"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Жаздырууда дал келбестик бар"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Жаздырууда"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Жаздырылбай калды"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Ырааттамаларды жаздырууну түзүү үчүн программаларды окуу"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Программалар окулууда"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR көбүрөөк орунду талап кылат"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Сиз DVR менен программаларды жаздыра аласыз. Бирок, DVR\'ды иштетүү үчүн түзмөгүңүздө бош орун калбай калды. Көлөмү <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>Гб же андан ашык болгон тышкы драйверге туташыңыз да, аны түзмөктүн сактагычы катары жөндөп алыңыз."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Сактагыч жок болуп жатат"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR колдонгон сактагычтын айрым бөлүмдөрү жок болуп жатат. DVR\'ды кайра иштетүү үчүн колдонулган тышкы драйверди туташтырыңыз. Же болбосо, жеткиликсиз сактагыч унутулсун дегенди тандасаңыз болот."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Сактагыч унутулсунбу?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Бардык жаздырылган мазмун жана графиктериңиз жоголот."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Жаздыруу токтотулсунбу?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Тартылган мазмун сакталып калат."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Пландаштырылган жаздыруу, бирок бир убакытка коюлуп калган"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Жаздыруу башталды, бирок башка программа менен дал келип калган"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> жаздырылат."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> жаздырылууда."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> программасынын кээ бир бөлүктөрү жаздырылбайт."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> жана <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> программаларынын кээ бир бөлүктөрү жаздырылбайт."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> программаларынын кээ бир бөлүктөрү жана графиктеги дагы бирөө жаздырылбайт."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g><xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> программаларынын кээ бир бөлүктөрү жана графиктеги %3$d жаздырылбайт.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g><xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> программаларынын кээ бир бөлүктөрү жана графиктеги %3$d жаздырылбайт.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Эмнени жаздырууну каалайсыз?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Канча убакыт жаздырууну каалайсыз?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Буга чейин графикке киргизилген"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Ушул эле программа буга чейин <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> жаздыруу графигине кошулган."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Буга чейин жаздырылган"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Бул программа буга чейин жазылган. Ал DVR китепканасында жеткиликтүү."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Жаздырылган программа табылган жок."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Окшош жаздыруулар"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Программанын сүрөттөлүшү жок)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d жаздыруу</item>
+ <item quantity="one">%1$d жаздыруу</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> жаздыруу графигинен алынып салынган"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Күүлөгүчтөгү дал келбестиктерге байланыштуу жарым-жартылай жаздырылат."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Күүлөгүчтөгү дал келбестиктерге байланыштуу жаздырылбайт."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Графикке жаздыруу киргизиле элек.\nПрограмма жетегинен жаздыруу графигин түзсөңүз болот."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">Жаздырууда %1$d дал келбестик бар</item>
+ <item quantity="one">Жаздырууда %1$d дал келбестик бар</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Сериал жөндөөлөрү"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Сериал тартып баштоо"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Сериал тартууну токтотуу"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Сериал тартуу токтотулсунбу?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Тартылган сериялар DVR китепканасында сакталып калат."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Токтотуу"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Учурда бир да эпизод жок.\nАлар жеткиликтүү болоору менен жаздырылат."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d мүнөт)</item>
+ <item quantity="one">(%1$d мүнөт) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Бүгүн"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Эртең"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Кечээ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Бүгүн саат <xliff:g id="TIME_RANGE">%1$s</xliff:g> чейин"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Эртең саат <xliff:g id="TIME_RANGE">%1$s</xliff:g> чейин"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Упай"</string>
</resources>
diff --git a/res/values-lo-rLA/arrays.xml b/res/values-lo-rLA/arrays.xml
index 71d977b4..5e1c1e0c 100644
--- a/res/values-lo-rLA/arrays.xml
+++ b/res/values-lo-rLA/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"ເຕັມ"</item>
<item msgid="8568284598210500589">"ຊູມ"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ທຸກຊ່ອງ"</item>
- <item msgid="6897460857821394118">"ຄອບຄົວ/ເດັກນ້ອຍ"</item>
- <item msgid="551257741825778215">"ກິລາ"</item>
- <item msgid="452133796804325879">"ຊັອບປິ້ງ"</item>
- <item msgid="3296058637230163031">"ຮູບເງົາ"</item>
- <item msgid="1054540282883891201">"ຕະຫລົກ"</item>
- <item msgid="7900158429062595471">"ການເດີນທາງ"</item>
- <item msgid="3768998587825611787">"ດຣາມ່າ"</item>
- <item msgid="8340620094959282881">"ການສຶກສາ"</item>
- <item msgid="7396447839483867269">"ສັດ"</item>
- <item msgid="4738043455148062673">"ຂ່າວ"</item>
- <item msgid="7405041316051047427">"ເກມ"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ທຸກຊ່ອງ"</item>
- <item msgid="7909003973960375395">"ຄອບຄົວ/ເດັກນ້ອຍ"</item>
- <item msgid="3185279732911635789">"ກິລາ"</item>
- <item msgid="4704858492065325964">"ຊັອບປິ້ງ"</item>
- <item msgid="6083795019290250078">"ຮູບເງົາ"</item>
- <item msgid="8302638329222449550">"ຕະຫລົກ"</item>
- <item msgid="3803709976021475052">"ການເດີນທາງ"</item>
- <item msgid="8116747365234169059">"ດຣາມ່າ"</item>
- <item msgid="7356447541595315913">"ການສຶກສາ"</item>
- <item msgid="7511135485827589547">"ສັດ"</item>
- <item msgid="6961248112238009967">"ຂ່າວ"</item>
- <item msgid="6484685553679698447">"ເກມ"</item>
- <item msgid="2737158328243183190">"ສິລະປະ"</item>
- <item msgid="6577176952650166615">"ບັນເທີງ"</item>
- <item msgid="7886693831871777617">"ການດຳລົງຊີວິດ"</item>
- <item msgid="8145832312485577062">"ດົນຕີ"</item>
- <item msgid="1345789204804308580">"ການສະແດງ"</item>
- <item msgid="2736680312770771994">"ເຕັກໂນໂລຊີ/ວິທະຍາສາດ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"​ທຸກ​ຊ່ອງ"</item>
+ <item msgid="928298872841713530">"ຄອບ​ຄົວ/ເດັກ​ນ້ອຍ"</item>
+ <item msgid="2751606947569857164">"ກິລາ"</item>
+ <item msgid="7345749789651321496">"ຊັອບປິງ"</item>
+ <item msgid="167201149441442173">"ຮູບເງົາ"</item>
+ <item msgid="525966731464264290">"ຄອມເມດີ"</item>
+ <item msgid="6096710741527327836">"ການເດີນທາງ"</item>
+ <item msgid="2851882187117833883">"ດຣາມ່າ"</item>
+ <item msgid="78492781188719038">"ການສຶກສາ"</item>
+ <item msgid="7221999662426308394">"ສັດ"</item>
+ <item msgid="375300513250925001">"​ຂ່າວ"</item>
+ <item msgid="7746320336582330410">"ເກມ"</item>
+ <item msgid="1255741860568329178">"ສິ​ລະ​ປະ"</item>
+ <item msgid="7603949681065702867">"ບັນເທີງ"</item>
+ <item msgid="4453821994746804366">"ການດຳລົງຊີວິດ"</item>
+ <item msgid="3488534597567932843">"ເພງ"</item>
+ <item msgid="7452153120614274095">"ການ​ສະ​ແດງ"</item>
+ <item msgid="8215762047341133299">"ເຕັກ​ໂນ​ໂລ​ຊີ/ວິ​ທະ​ຍາ​ສາດ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ຊ່ອງ​ອອກອາກາດສົດ"</item>
diff --git a/res/values-lo-rLA/rating_system_strings.xml b/res/values-lo-rLA/rating_system_strings.xml
index 99d82728..534b6a89 100644
--- a/res/values-lo-rLA/rating_system_strings.xml
+++ b/res/values-lo-rLA/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-lo-rLA/strings.xml b/res/values-lo-rLA/strings.xml
index 0f833d0a..05aba1ce 100644
--- a/res/values-lo-rLA/strings.xml
+++ b/res/values-lo-rLA/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"ກ່ອນໜ້າ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"ຄຳ​ແນະນຳ​ລາຍການ"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"ມີ​ຊ່ອງ​ໃໝ່​ໃຫ້​ຢູ່"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ບໍ່​ມີ​ລິ້ງ​ຢູ່"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"ເປີດ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"ຄຳ​ບັນຍາຍ​ແບບ​ປິດ"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ໂໝດ​ການ​ສະແດງຜົນ"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ປະເພດຍ່ອຍ"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ປ້ອນ​ລະ​ຫັດ​ PIN ຂອງ​ທ່ານ​ເພື່ອ​ເບິ່ງ​ຊ່ອງ​ນີ້"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"​ປ້ອນ​ລະ​ຫັດ PIN ຂອງ​ທ່ານ​ເພື່ອ​ເບິ່ງ​ລາຍ​ການ​ນີ້"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ລາຍການນີ້ຖືກຈັດປະເພດເປັນ <xliff:g id="RATING">%1$s</xliff:g>. ກະລຸນາໃສ່ລະຫັດ PIN ຂອງທ່ານເພື່ອເບິ່ງລາຍການນີ້"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"​ປ້ອນ​ລະ​ຫັດ PIN ຂອງ​ທ່ານ"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"ເພື່ອ​ຕັ້ງ​ຄ່າ​ຄວບ​ຄຸມ​ຂອງ​ຜູ່​ປົກ​ຄອງ, ກະລຸ​ນາຕັ້ງ​ລະ​ຫັດ PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"ໃສ່ລະຫັດ PIN ໂຕໃຫມ່"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"​ໃບ​ອະ​ນຸ​ຍາດ​ Open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"​ໃບ​ອະ​ນຸ​ຍາດ​ແຫຼ່ງ​ເປີດ"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ເວີຊັນ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ຊ່ວຍ​ປັບ​ປຸງ​ຊ່ອງ​ສົດ"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"ສະ​ແດງ​ການ​ໃຊ້​ນິ​ລະ​ນາມ ແລະ ຂໍ້​ມູນ​ວິ​ນິ​ໄສ​ກັບ Google ເພື່ອ​ທີ່​ພວກ​ເຮົາ​ຈະ​ສາ​ມາດ​ເຮັດ​ໃຫ້ຊ່ອງ​ສົດດີ​ຂຶ້ນ ແລະ ປ້ອງ​ກັນ​ບັນ​ຫາ​ຕ່າງໆ​ເຊັ່ນ: ການ​ຂັດ​ຂ້ອງ ແລະ ການ​ຈຶ້ງ​ໄວ້."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"​ເພື່ອ​ເບິ່ງ​ຊ່ອງ​ນີ້, ກົດ​ປຸ່ມ ຂວາ ແລະ ປ້ອນ​ລະ​ຫັດ PIN ຂອງ​ທ່ານ"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"​ເພື່ອ​ເບິ່ງ​ລາຍ​ການ​ນີ້, ໃຫ້ກົດ​ປຸ່ມ ຂວາ ແລະ ປ້ອນ​ລະ​ຫັດ PIN ຂອງ​ທ່ານ"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"​ລາຍ​ການ​ນີ້​ຖືກ​ຈັດ​ປະ​ເພດ​ <xliff:g id="RATING">%1$s</xliff:g>.\n​ເພື່ອ​ເບິ່ງ​ລາຍ​ການ​ນີ້, ໃຫ້ກົດ​ປຸ່ມ ຂວາ ແລະ ປ້ອນ​ລະ​ຫັດ PIN ຂອງ​ທ່ານ"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ສຽງເທົ່ານັ້ນ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"ສັນຍານອ່ອນ"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ບໍ່ມີການເຊື່ອມຕໍ່ອິນເຕີເນັດ"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">ບໍ່ສາມາດຫຼິ້ນຊ່ອງນີ້ໄດ້ຈົນກວ່າຈະຮອດ <xliff:g id="END_TIME_1">%1$s</xliff:g> ເນື່ອງຈາກກຳລັງບັນທຶກຊ່ອງອື່ນຢູ່. \n\nກົດຂວາເພື່ອປັບແຕ່ງເວລາການບັນທຶກ.</item>
+ <item quantity="one">ບໍ່ສາມາດຫຼິ້ນຊ່ອງນີ້ໄດ້ຈົນກວ່າຈະຮອດ <xliff:g id="END_TIME_0">%1$s</xliff:g> ເນື່ອງຈາກກຳລັງບັນທຶກຊ່ອງອື່ນຢູ່. \n\nກົດຂວາເພື່ອປັບແຕ່ງເວລາການບັນທຶກ.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ບໍ່ມີຫົວຂໍ້"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"​ຊ່ອງ​ຖືກບລັອກ"</string>
<string name="setup_category_new" msgid="2899355289563443627">"ໃໝ່"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ບໍ່​ມີ​ຊ່ອງ​ພ້ອມ​ໃຊ້​ງານ​ໄດ້​ຢູ່"</string>
<string name="setup_input_new" msgid="3337725672277046798">"ໃໝ່"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"ບໍ່ໄດ້​ຕິດ​ຕັ້ງ"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"ເອົາແຫຼ່ງທີ່ມາຂອງຊ່ອງເພີ່ມເຕີມ"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"ທ່ອງເບິ່ງແອັບທີ່ໃຫ້ຊ່ອງຖ່າຍທອດສົດ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"ເບິ່ງແຫຼ່ງທີ່ມາຂອງຊ່ອງເພີ່ມເຕີມ"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"ທ່ອງເບິ່ງແອັບທີ່ໃຫ້ຊ່ອງຖ່າຍທອດສົດ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"ມີແຫຼ່ງ​ຊ່ອງ​ໃໝ່"</string>
<string name="new_sources_description" msgid="749649005588426813">"ແຫຼ່ງຊ່ອງໃໝ່ມີຊ່ອງຕ່າງໆໄວ້ໃຫ້ບໍລິການ.\nຕັ້ງພວກມັນດຽວນີ້, ຫຼືເຮັດສິ່ງນີ້ໃນພາຍຫຼັງໃນການຕັ້ງຄ່າແຫຼ່ງຊ່ອງ."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ຕັ້ງດຽວນີ້"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ຊ່ອງ​ແຫລ່ງ​ຂໍ້​ມູນ​ທັງ​ໝົດ​ຖືກ​ເຊື່ອງ​ໄວ້​ແລ້ວ.\nກະ​ລຸ​ນາ​ເລືອກ​ຢ່າງ​ໜ້ອຍ​ນຶ່ງ​ຊ່ອງ​ເພື່ອ​ເບິ່ງ."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ວິ​ດີ​ໂອບໍ່​ສາ​ມາດ​ເບິ່ງ​ໄດ້​ໂດຍບໍ່​ຄາດ​ຄິດ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"ປຸ່ມ Back ແມ່ນ​ສຳ​ລັບ​ອຸ​ປະ​ກອນ​ທີ່​ເຊື່ອມ​ຕໍ່​ແລ້ວ. ໃຫ້​ກົດ​ປຸ່ມ Home ເພື່ອອອກ."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"ຊ່ອງ​ສົດ​ບໍ່​ຖືກ​ຮອງ​ຮັບ​ຢູ່​ໃນ​ອຸ​ປະ​ກອນ​ນີ້​ດ້ວຍ Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"ຊ່ອງ​ສົດ​ຕ້ອງ​ມີ​ການ​ອະ​ນຸ​ຍາດ​ເພື່ອ​ອ່ານ​ການ​ຈັດ​ລາຍ​ການ TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"ຕັ້ງຄ່າແຫຼ່ງຊ່ອງຂອງທ່ານ"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ຊ່ອງອອກອາກາດສົດລວມເອົາປະສົບການຂອງຊ່ອງໂທລະພາບແບບເດີມເຂົ້າກັບຊ່ອງທີ່ໃຊ້ການສະຕຣີມທີ່ສະໜອງໃຫ້ໂດຍແອັບ. \n\nເລີ່ມຕົ້ນນຳໃຊ້ໂດຍການຕັ້ງຄ່າແຫຼ່ງຊ່ອງທີ່ຕິດຕັ້ງແລ້ວ. ຫຼື ຊອກຫາແອັບເພີ່ມເຕີມທີ່ໃຫ້ຊ່ອງອອກອາກາດສົດໃນ Google Play Store."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ການບັນທຶກ ແລະ ການຕັ້ງເວລາ"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 ນາທີ"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 ນາທີ"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ຊົ່ວໂມງ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ຊົ່ວໂມງ"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ຫຼ້າສຸດ"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"ຕັ້ງເວລາໄວ້ແລ້ວ"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"ຊີຣີ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"ອື່ນໆ"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ບໍ່ສາມາດບັນທຶກຊ່ອງໄດ້."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"ບໍ່ສາມາດບັນທຶກລາຍການໄດ້."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ຖືກຕັ້ງເວລາໃຫ້ບັນທຶກໄວ້ແລ້ວ"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ກຳລັງບັນທຶກ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ຈາກຕອນນີ້ຫາ <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"ຕາລາງແບບເຕັມ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d ມື້ຖັດໄປ</item>
+ <item quantity="one">%1$d ມື້ຖັດໄປ</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d ນາທີ</item>
+ <item quantity="one">%1$d ນາທີ</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d ການບັນທຶກສຽງໃໝ່</item>
+ <item quantity="one">%1$d ການບັນທຶກສຽງໃໝ່</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d ການບັນທຶກ</item>
+ <item quantity="one">%1$d ການບັນທຶກ</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d ການບັນທຶກທີ່ຕັ້ງເວລາໄວ້ແລ້ວ</item>
+ <item quantity="one">%1$d ການບັນທຶກທີ່ຕັ້ງເວລາໄວ້ແລ້ວ</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ເບິ່ງ"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"ຫຼິ້ນຕັ້ງແຕ່ຕົ້ນ"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ສືບຕໍ່ຫຼິ້ນວິດີໂອ"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"​ລຶບ"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ລຶບການບັນທຶກອອກ"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"ສືບຕໍ່"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"ຊີຊັນ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"ເບິ່ງຕາຕາລາງ"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"ອ່ານເພີ່ມເຕີມ"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ລຶບການບັນທຶກອອກ"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ເລືອກເອັບພິໂສດທີ່ທ່ານຕ້ອງການລຶບອອກ. ພວກມັນຈະບໍ່ສາມາດກູ້ກັບຄືນມາໄດ້ຫຼັງຈາກທີ່ລຶບອອກໄປແລ້ວ."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ບໍ່ມີການບັນທຶກໃຫ້ລຶບ."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"ເລືອກເອັບພິໂສດທີ່ເບິ່ງແລ້ວ"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"ເລືອກເອັບພິໂສດທັງໝົດ"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ບໍ່ເລືອກເອັບພິໂສດທັງໝົດ"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"ເບິ່ງໄປແລ້ວ <xliff:g id="WATCHED">%1$d</xliff:g> ນາທີຈາກທັງໝົດ <xliff:g id="DURATION">%2$d</xliff:g> ນາທີ"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"ເບິ່ງໄປແລ້ວ <xliff:g id="WATCHED">%1$d</xliff:g> ວິນາທີຈາກທັງໝົດ <xliff:g id="DURATION">%2$d</xliff:g> ວິນາທີ"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"ຍັງບໍ່ເຄີຍເບິ່ງ"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">ລຶບເອັບພິໂສດ %1$d ຕອນຈາກທັງໝົດ %2$d ຕອນອອກແລ້ວ</item>
+ <item quantity="one">ລຶບເອັບພິໂສດ %1$d ຕອນຈາກທັງໝົດ %2$d ຕອນອອກແລ້ວ</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ຄວາມສຳຄັນ"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"ສູງສຸດ"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ຕ່ຳສຸດ"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"ບໍ່. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"​ຊ່ອງ"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ອັນ​ໃດ​ກໍ່​ໄດ້"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ເລືອກຄວາມສຳຄັນ"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"ເມື່ອມີໂປຣແກຣມໃຫ້ບັນທຶກຫຼາຍເກີນໄປໃນເວລາດຽວກັນ, ລະບົບຈະບັນທຶກລາຍການທີ່ມີຄວາມສຳຄັນສູງກວ່າເທົ່ານັ້ນ."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"ບັນທຶກ"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ການບັນທຶກຕາມເວລາມີຄວາມສຳຄັນສູງສຸດ"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"​ຍົກເລີກ"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"ຍົກເລີກ"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"ລືມ"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"ຢຸດ"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ເບິ່ງຕາຕາລາງການບັນທຶກ"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ນີ້ເປັນລາຍການດ່ຽວ"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ຕອນນີ້ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"ທັງຊີຣີ…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"ຕັ້ງເວລາຕໍ່ໄປໂລດ"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"ບັນທຶກອັນນີ້ແທນ"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ຍົກເລີກການບັນທຶກນີ້"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ເບິ່ງດຽວນີ້"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ບັນທຶກໄດ້"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ຕັ້ງເວລາບັນທຶກແລ້ວ"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ເກີດຄວາມຂັດແຍ່ງໃນການບັນທຶກ"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ກຳລັງບັນທຶກ"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ບັນທຶກບໍ່ສຳເລັດ"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"ກຳລັງອ່ານເນື້ອຫາລາຍການເພື່ອຕັ້ງເວລາບັນທຶກ"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"ກຳລັງອ່ານລາຍການ"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR ຕ້ອງໃຊ້ບ່ອນຈັດເກັບຂໍ້ມູນເພີ່ມເຕີມ"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"ທ່ານຈະສາມາດບັນທຶກລາຍການດ້ວຍ DVR ໄດ້. ຢ່າງໃດກໍຕາມ, ອຸປະກອນຂອງທ່ານບໍ່ມີບ່ອນຈັດເກັບຂໍ້ມູນພຽງພໍໃຫ້ DVR ເຮັດວຽກໄດ້. ກະລຸນາເຊື່ອມຕໍ່ຫາໄດຣຟ໌ພາຍນອກທີ່ມີຂະໜາດ <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB ຫຼືໃຫຍ່ກວ່າ ແລ້ວເຮັດຕາມຂັ້ນຕອນໃນການໃຊ້ມັນເປັນອຸປະກອນຈັດເກັບຂໍ້ມູນ."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"ບໍ່ພົບບ່ອນຈັດເກັບຂໍ້ມູນ"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"ບໍ່ພົບບ່ອນຈັດເກັບຂໍ້ມູນບາງອັນທີ່ໃຊ້ໂດຍ DVR. ກະລຸນາເຊື່ອມຕໍ່ໄດຣຟ໌ພາຍນອກທີ່ທ່ານໃຊ້ກ່ອນຈະເປີດໃຊ້ DVR ຄືນໃໝ່. ຫຼືອີກວິທີໜຶ່ງ, ທ່ານສາມາດເລືອກໃຫ້ລືມບ່ອນຈັດເກັບຂໍ້ມູນດັ່ງກ່າວໄດ້ຫາກມັນບໍ່ມີໃຫ້ໃຊ້ອີກຕໍ່ໄປແລ້ວ."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ລືມການຈັດເກັບຂໍ້ມູນບໍ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"ທ່ານຈະສູນເສຍເນື້ອຫາ ແລະ ການຕັ້ງເວລາທັງໝົດທີ່ທ່ານບັນທຶກໄວ້ແລ້ວ."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ຢຸດການບັນທຶກໄວ້ບໍ?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ເນື້ອຫາທີ່ອັດໄວ້ແລ້ວຈະຖືກບັຍທຶກໄວ້."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ຕັ້ງເວລາການບັນທຶກແລ້ວແຕ່ມີຂໍ້ຂັດແຍ່ງເກີດຂຶ້ນ"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ເລີ່ມການບັນທຶກແລ້ວແຕ່ມີຂໍ້ຂັດແຍ່ງ"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ຈະຖືກບັນທຶກໄວ້."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"ກຳລັງບັນທຶກ <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"ບາງສ່ວນຂອງ <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ຈະບໍ່ຖືກບັນທຶກ."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"ບາງສ່ວນຂອງ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ແລະ <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ຈະບໍ່ຖືກບັນທຶກ."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"ບາງສ່ວນຂອງ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ແລະ ອີກໜຶ່ງລາຍການຈະບໍ່ຖືກບັນທຶກ."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">ບາງສ່ວນຂອງ <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ແລະ ເພີ່ມເຕີມອີກ %3$d ລາຍການຈະບໍ່ມີການບັນທຶກໄວ້.</item>
+ <item quantity="one">ບາງສ່ວນຂອງ <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ແລະ ເພີ່ມເຕີມອີກ %3$d ລາຍການຈະບໍ່ມີການບັນທຶກໄວ້.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"ທ່ານຕ້ອງການບັນທຶກຫຍັງ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"ທ່ານຕ້ອງການບັນທຶກດົນປານໃດ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ມີການຕັ້ງເວລາຢູ່ກ່ອນແລ້ວ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"ລາຍການດຽວກັນນີ້ໄດ້ຕັ້ງເວລາໃຫ້ບັນທຶກໄວ້ແລ້ວເວລາ <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ບັນທຶກໄປກ່ອນແລ້ວ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ລາຍການນີ້ຖືກບັນທຶກໄປກ່ອນແລ້ວ. ມັນສາມາດເບິ່ງໄດ້ໃນຫ້ອງສະໝຸດ DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ບໍ່ພົບໂປຣແກຣມທີ່ບັນທຶໄວ້."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ການບັນທຶກທີ່ກ່ຽວຂ້ອງ"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ບໍ່ມີຄຳອະທິບາຍລາຍການ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d ການບັນທຶກ</item>
+ <item quantity="one">%1$d ການບັນທຶກ</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"ລຶບ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ອອກຈາກກຳນົດການບັນທຶກແລ້ວ"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ຈະຖືກບັນທຶກບາງສ່ວນເນື່ອງຈາກມີຄວາມຂັດແຍ່ງໃນຕົວປັບຫາສັນຍານ."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ຈະບໍ່ຖືກບັນທຶກເນື່ອງຈາກມີຄວາມຂັດແຍ່ງໃນຕົວປັບຫາສັນຍານ."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ຍັງບໍ່ມີການຕັ້ງເວລາບັນທຶກເທື່ອ.\nທ່ານສາມາດຕັ້ງເວລາບັນທຶກໄດ້ຈາກຄຳແນະນຳລາຍການ."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d ການບັນທຶກທີ່ຂັດແຍ່ງກັນ</item>
+ <item quantity="one">%1$d ການບັນທຶກທີ່ຂັດແຍ່ງກັນ</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"ການຕັ້ງຄ່າຊີຣີ"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"ເລີ່ມການບັນທຶກຊີຣີ"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"ຢຸດການບັນທຶກຊີຣີ"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"ຢຸດການບັນທຶກຊີຣີບໍ່?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ເອັບພິໂສດທີ່ບັນທຶກໄວ້ແລ້ວຈະຍັງຄົງສາມາດເບິ່ງໄດ້ໃນຫ້ອງສະໝຸດ DVR ຢູ່."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"ຢຸດ"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ຍັງບໍ່ມີເອບພິໂສດທີ່ສາມາດເບິ່ງໄດ້ເທື່ອ.\nພວກມັນຈະຖືກບັນທຶອຶກເມື່ອມີການສາຍ."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d ນາທີ)</item>
+ <item quantity="one">(%1$d ນາທີ) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ມື້ນີ້"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"ມື້ອື່ນ"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ມື້ວານນີ້"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ມື້ນີ້"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ມື້ອື່ນ"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ຄະແນນ"</string>
</resources>
diff --git a/res/values-lt/arrays.xml b/res/values-lt/arrays.xml
index cf74fa4b..e1512c7b 100644
--- a/res/values-lt/arrays.xml
+++ b/res/values-lt/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Visas"</item>
<item msgid="8568284598210500589">"Mastelio keitimas"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Visi kanalai"</item>
- <item msgid="6897460857821394118">"Šeima / vaikai"</item>
- <item msgid="551257741825778215">"Sportas"</item>
- <item msgid="452133796804325879">"Apsipirkimas"</item>
- <item msgid="3296058637230163031">"Filmai"</item>
- <item msgid="1054540282883891201">"Komedijos"</item>
- <item msgid="7900158429062595471">"Kelionės"</item>
- <item msgid="3768998587825611787">"Dramos"</item>
- <item msgid="8340620094959282881">"Išsilavinimas"</item>
- <item msgid="7396447839483867269">"Gyvūnija ir augalija"</item>
- <item msgid="4738043455148062673">"Naujienos"</item>
- <item msgid="7405041316051047427">"Žaidimai"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Visi kanalai"</item>
- <item msgid="7909003973960375395">"Šeima / vaikai"</item>
- <item msgid="3185279732911635789">"Sportas"</item>
- <item msgid="4704858492065325964">"Apsipirkimas"</item>
- <item msgid="6083795019290250078">"Filmai"</item>
- <item msgid="8302638329222449550">"Komedijos"</item>
- <item msgid="3803709976021475052">"Kelionės"</item>
- <item msgid="8116747365234169059">"Dramos"</item>
- <item msgid="7356447541595315913">"Išsilavinimas"</item>
- <item msgid="7511135485827589547">"Gyvūnija ir augalija"</item>
- <item msgid="6961248112238009967">"Naujienos"</item>
- <item msgid="6484685553679698447">"Žaidimai"</item>
- <item msgid="2737158328243183190">"Menai"</item>
- <item msgid="6577176952650166615">"Pramogos"</item>
- <item msgid="7886693831871777617">"Gyvenimo būdas"</item>
- <item msgid="8145832312485577062">"Muzika"</item>
- <item msgid="1345789204804308580">"Geriausias turinys"</item>
- <item msgid="2736680312770771994">"Technol. / mokslas"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Visi kanalai"</item>
+ <item msgid="928298872841713530">"Šeima / vaikai"</item>
+ <item msgid="2751606947569857164">"Sportas"</item>
+ <item msgid="7345749789651321496">"Apsipirkimas"</item>
+ <item msgid="167201149441442173">"Filmai"</item>
+ <item msgid="525966731464264290">"Komedijos"</item>
+ <item msgid="6096710741527327836">"Kelionės"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Švietimas"</item>
+ <item msgid="7221999662426308394">"Gyvūn. / lauk. gamta"</item>
+ <item msgid="375300513250925001">"Naujienos"</item>
+ <item msgid="7746320336582330410">"Žaidimai"</item>
+ <item msgid="1255741860568329178">"Menai"</item>
+ <item msgid="7603949681065702867">"Pramogos"</item>
+ <item msgid="4453821994746804366">"Gyvenimo būdas"</item>
+ <item msgid="3488534597567932843">"Muzika"</item>
+ <item msgid="7452153120614274095">"Premjera"</item>
+ <item msgid="8215762047341133299">"Technol. / mokslas"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Tiesioginiai kanalai"</item>
diff --git a/res/values-lt/rating_system_strings.xml b/res/values-lt/rating_system_strings.xml
index ec5127f1..ffc1b7d6 100644
--- a/res/values-lt/rating_system_strings.xml
+++ b/res/values-lt/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 9f198d30..88afdec0 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Ankstesnis"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programų vadovas"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Galimi nauji kanalai"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nėra jokių nuorodų"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtitrai"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Rodymo režimas"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Antriniai įvert."</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Įveskite PIN kodą, kad galėt. žiūrėti šį kanalą"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Įveskite PIN kodą, kad galėt. žiūrėti šią programą"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Ši programa įvertinta <xliff:g id="RATING">%1$s</xliff:g>. Įveskite PIN kodą, kad galėtumėte žiūrėti šią programą"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Įveskite PIN kodą"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Jei norite nustatyti tėvų valdiklius, sukurkite PIN kodą"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Įveskite naują PIN"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Atvirojo šaltinio licencijos"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Atvirojo šaltinio licencijos"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versija"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Padėti tobulinti „Live TV“"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Bendrinkite anoniminius naudojimo ir diagnostikos duomenis su „Google“, kad galėtume patobulinti Tiesioginius kanalus ir apsaugoti nuo problemų, pvz., užstrigimo."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Jei norite žiūrėti šį kanalą, paspauskite „Tinkamas“ ir įveskite PIN kodą"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Jei norite žiūrėti šią programą, paspauskite „Tinkama“ ir įveskite PIN kodą"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ši programa įvertinta kaip <xliff:g id="RATING">%1$s</xliff:g>.\nJei norite žiūrėti šią programą, paspauskite „Tinkama“ ir įveskite PIN kodą"</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Tik garso įrašas"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Silpnas signalas"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nėra interneto ryšio"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Šio kanalo negalima leisti iki <xliff:g id="END_TIME_1">%1$s</xliff:g>, nes įrašomi kiti kanalai. \n\nPaspauskite mygtuką dešinėn, kad galėtumėte koreguoti įrašymo tvarkaraštį.</item>
+ <item quantity="few">Šio kanalo negalima leisti iki <xliff:g id="END_TIME_1">%1$s</xliff:g>, nes įrašomi kiti kanalai. \n\nPaspauskite mygtuką dešinėn, kad galėtumėte koreguoti įrašymo tvarkaraštį.</item>
+ <item quantity="many">Šio kanalo negalima leisti iki <xliff:g id="END_TIME_1">%1$s</xliff:g>, nes įrašomi kiti kanalai. \n\nPaspauskite mygtuką dešinėn, kad galėtumėte koreguoti įrašymo tvarkaraštį.</item>
+ <item quantity="other">Šio kanalo negalima leisti iki <xliff:g id="END_TIME_1">%1$s</xliff:g>, nes įrašomi kiti kanalai. \n\nPaspauskite mygtuką dešinėn, kad galėtumėte koreguoti įrašymo tvarkaraštį.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Nėra pavadinimo"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanalas užblokuotas"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nauji"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nėra pasiekiamų kanalų"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Naujos"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nenustatyta"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Gauti daugiau šaltinių"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Naršyti programas, kuriose siūlomi tiesioginiai kanalai"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Gauti daugiau šaltinių"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Naršyti programas, kuriose siūlomi tiesioginiai kanalai"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Pasiekiami nauji kanalų šaltiniai"</string>
<string name="new_sources_description" msgid="749649005588426813">"Naujuose kanalų šaltiniuose siūloma kanalų.\nNustatykite juos dabar arba atlikite tai vėliau kanalų šaltinių nustatymo skiltyje."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Nustatyti dabar"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Visi šaltinio kanalai yra paslėpti.\nPasirinkite bent vieną norimą žiūrėti kanalą."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Vaizdo įrašas netikėtai negalimas"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"GRĮŽIMO klavišas skirtas prijungtam įrenginiui. Paspauskite PAGRINDINIO PUSLAPIO mygtuką, kad išeitumėte."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Programa „Live TV“ nepalaikoma šiame įrenginyje, nes jame veikia „Lollipop“ versijos „Android“."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Programai „Live TV“ reikalingas leidimas skaityti TV įrašus."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Nustatykite šaltinius"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Tiesioginiuose kanaluose derinamos tradicinių TV kanalų ir programų srautu perduodamų kanalų funkcijos. \n\nPradėkite nustatydami jau įdiegtų kanalų šaltinius. Arba naršykite „Google Play“ parduotuvę, kur rasite daugiau tiesioginius kanalus teikiančių programų."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Įrašai ir tvarkaraščiai"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 min."</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 min."</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 val."</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 val."</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Naujausi"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Suplanuota"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serialas"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Kiti"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanalo neįmanoma įrašyti."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programos neįmanoma įrašyti."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Programa „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ suplanuota įrašyti"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Įrašoma „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ nuo dabar iki <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Visas tvarkaraštis"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Kita %1$d diena</item>
+ <item quantity="few">Kitos %1$d dienos</item>
+ <item quantity="many">Kitos %1$d dienos</item>
+ <item quantity="other">Kitų %1$d dienų</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minutė</item>
+ <item quantity="few">%1$d minutės</item>
+ <item quantity="many">%1$d minutės</item>
+ <item quantity="other">%1$d minučių</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d naujas įrašas</item>
+ <item quantity="few">%1$d nauji įrašai</item>
+ <item quantity="many">%1$d naujo įrašo</item>
+ <item quantity="other">%1$d naujų įrašų</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d įrašas</item>
+ <item quantity="few">%1$d įrašai</item>
+ <item quantity="many">%1$d įrašo</item>
+ <item quantity="other">%1$d įrašų</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d suplanuotas įrašas</item>
+ <item quantity="few">%1$d suplanuoti įrašai</item>
+ <item quantity="many">%1$d suplanuoto įrašo</item>
+ <item quantity="other">%1$d suplanuotų įrašų</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Žiūrėti"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Leisti nuo pradžios"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Tęsti ir leisti"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Ištrinti"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Ištrinti įrašus"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Tęsti"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g> sezonas"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Žr. tvarkaraštį"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Skaityti daugiau"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Įrašų ištrynimas"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Pasirinkite serijas, kurias norėtumėte ištrinti. Jų nebus galima atkurti, kai ištrinsite."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nėra jokių įr., kuriuos b. gal. ištr."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Pasirinkti žiūrėtas serijas"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Pasirinkti visas serijas"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Atš. visų serijų ištrynimą"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Žiūrėta: <xliff:g id="WATCHED">%1$d</xliff:g> min. iš <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Žiūrėta: <xliff:g id="WATCHED">%1$d</xliff:g> sek. iš <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Niekada nežiūrėti"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">Ištrinta %1$d serija iš %2$d</item>
+ <item quantity="few">Ištrintos %1$d serijos iš %2$d</item>
+ <item quantity="many">Ištrinta %1$d serijos iš %2$d</item>
+ <item quantity="other">Ištrinta %1$d serijų iš %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritetas"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Didžiausias"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Mažiausias"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Ne. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanalai"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Bet koks"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Pasirinkti prioritetą"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Kai vienu metu bus per daug įrašomų programų, bus įrašomos tik aukštesnio prioriteto programos."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Išsaugoti"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Vienkartinis įrašymo veiksmas turi didžiausią prioritetą"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Atšaukti"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Atšaukti"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Pamiršti"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Sustabdyti"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Žr. įrašymo tvarkaraštį"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Ši viena programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"dabar–<xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Visos serijos…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Vis tiek suplanuoti"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Vietoj tos įrašyti šią"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Atšaukti šį įrašymą"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Žiūrėti dabar"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Galima įrašyti"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Įrašymas suplanuotas"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Įrašo nesuderinamumas"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Įrašoma"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Įrašyti nepavyko"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Nuskaitomos programos, kad būtų sukurti įrašymo tvarkaraščiai"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Nuskaitomos programos"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Norint naudoti DVR reikia daugiau saugyklos vietos"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Naudodami DVR galėsite įrašyti programas. Tačiau dabar įrenginyje nepakanka saugyklos vietos, kad DVR veiktų. Prijunkite išorinį diską, kuris yra <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB arba didesnis, ir atlikite veiksmus, kad formatuotumėte jį kaip įrenginio saugyklą."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Nėra saugyklos"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Nėra kai kurių saugyklų, kurias naudoja DVR. Prijunkite anksčiau naudotą išorinį diską, kad iš naujo įgalintumėte DVR. Taip pat galite pasirinkti pamiršti saugyklą, jei ji nebepasiekiama."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Pamiršti saugyklą?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Visas įrašytas turinys ir tvarkaraščiai bus prarasti."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Sustabdyti įrašymą?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Įrašytas turinys bus išsaugotas."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Įrašymas suplanuotas, bet yra neatitikimų"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Įrašymo procesas pradėtas, bet yra neatitikimų"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Programa „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ bus įrašyta."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Kanalas „<xliff:g id="CHANNELNAME">%1$s</xliff:g>“ įrašomas."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Kai kurios programos „<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>“ dalys nebus įrašytos."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>“ ir „<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>“ dalys nebus įrašytos."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>“ dalys ir dar vienas tvarkaraštis nebus įrašyti."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>“ dalys ir dar %3$d tvarkaraštis nebus įrašyti.</item>
+ <item quantity="few">Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>“ dalys ir dar %3$d tvarkaraščiai nebus įrašyti.</item>
+ <item quantity="many">Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>“ dalys ir dar %3$d tvarkaraščio nebus įrašyti.</item>
+ <item quantity="other">Kai kurios programų „<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>“, „<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>“ dalys ir dar %3$d tvarkaraščių nebus įrašyti.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ką norėtumėte įrašyti?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Kaip ilgai norėtumėte tęsti įrašymo procesą?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Jau suplanuota"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Ta pati programa jau suplanuota įrašyti <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Jau įrašyta"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Ši programa jau buvo įrašyta. Ji pasiekiama DVR bibliotekoje."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Įrašyta programa nerasta."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Susiję įrašai"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nėra laidos aprašo)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d įrašas</item>
+ <item quantity="few">%1$d įrašai</item>
+ <item quantity="many">%1$d įrašo</item>
+ <item quantity="other">%1$d įrašų</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Programa „<xliff:g id="PROGRAMNAME">%1$s</xliff:g>“ pašalinta iš įrašymo tvarkaraščio"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Dėl radijo imtuvo konfliktų bus įrašyta tik dalis."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Dėl radijo imtuvo konfliktų nebus įrašyta."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Dar nėra suplanuota jokių įrašymo veiksmų.\nĮrašymo veiksmą galite suplanuoti iš programų vadovo."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d įrašo nesuderinamumas</item>
+ <item quantity="few">%1$d įrašų nesuderinamumai</item>
+ <item quantity="many">%1$d įrašo nesuderinamumo</item>
+ <item quantity="other">%1$d įrašų nesuderinamumų</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Serijos nustatymai"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Pradėti serijos įrašymą"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Sustabd. serijos įrašymą"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Sustabdyti serijos įrašymą?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Įrašytos serijos bus pasiekiamos DVR bibliotekoje."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Sustabdyti"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nėra jokių serijų.\nSerijos bus įrašytos, kai jų bus."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minutė)</item>
+ <item quantity="few">(%1$d minutės)</item>
+ <item quantity="many">(%1$d minutės)</item>
+ <item quantity="other">(%1$d minučių)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Šiandien"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Rytoj"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Vakar"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> šiandien"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> rytoj"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Įvertinimas"</string>
</resources>
diff --git a/res/values-lv/arrays.xml b/res/values-lv/arrays.xml
index 902751c3..4e074e39 100644
--- a/res/values-lv/arrays.xml
+++ b/res/values-lv/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Pilns"</item>
<item msgid="8568284598210500589">"Tālummaiņa"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Visi kanāli"</item>
- <item msgid="6897460857821394118">"Ģimenei/bērniem"</item>
- <item msgid="551257741825778215">"Sports"</item>
- <item msgid="452133796804325879">"Iepirkšanās"</item>
- <item msgid="3296058637230163031">"Filmas"</item>
- <item msgid="1054540282883891201">"Komēdijas"</item>
- <item msgid="7900158429062595471">"Ceļojumi"</item>
- <item msgid="3768998587825611787">"Drāmas"</item>
- <item msgid="8340620094959282881">"Izglītība"</item>
- <item msgid="7396447839483867269">"Dzīvnieki/daba"</item>
- <item msgid="4738043455148062673">"Ziņas"</item>
- <item msgid="7405041316051047427">"Spēles"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Visi kanāli"</item>
- <item msgid="7909003973960375395">"Ģimenei/bērniem"</item>
- <item msgid="3185279732911635789">"Sports"</item>
- <item msgid="4704858492065325964">"Iepirkšanās"</item>
- <item msgid="6083795019290250078">"Filmas"</item>
- <item msgid="8302638329222449550">"Komēdijas"</item>
- <item msgid="3803709976021475052">"Ceļojumi"</item>
- <item msgid="8116747365234169059">"Drāmas"</item>
- <item msgid="7356447541595315913">"Izglītība"</item>
- <item msgid="7511135485827589547">"Dzīvnieki/daba"</item>
- <item msgid="6961248112238009967">"Ziņas"</item>
- <item msgid="6484685553679698447">"Spēles"</item>
- <item msgid="2737158328243183190">"Māksla"</item>
- <item msgid="6577176952650166615">"Izklaide"</item>
- <item msgid="7886693831871777617">"Dzīvesveids"</item>
- <item msgid="8145832312485577062">"Mūzika"</item>
- <item msgid="1345789204804308580">"Svarīgākais"</item>
- <item msgid="2736680312770771994">"Tehnoloģijas/zinātne"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Visi kanāli"</item>
+ <item msgid="928298872841713530">"Ģimenei/bērniem"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Iepirkšanās"</item>
+ <item msgid="167201149441442173">"Filmas"</item>
+ <item msgid="525966731464264290">"Komēdijas"</item>
+ <item msgid="6096710741527327836">"Ceļojumi"</item>
+ <item msgid="2851882187117833883">"Drāmas"</item>
+ <item msgid="78492781188719038">"Izglītība"</item>
+ <item msgid="7221999662426308394">"Dzīvnieki/daba"</item>
+ <item msgid="375300513250925001">"Ziņas"</item>
+ <item msgid="7746320336582330410">"Spēles"</item>
+ <item msgid="1255741860568329178">"Māksla"</item>
+ <item msgid="7603949681065702867">"Izklaide"</item>
+ <item msgid="4453821994746804366">"Dzīvesveids"</item>
+ <item msgid="3488534597567932843">"Mūzika"</item>
+ <item msgid="7452153120614274095">"Svarīgākais"</item>
+ <item msgid="8215762047341133299">"Tehnoloģijas/zinātne"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Dzīvie kanāli"</item>
diff --git a/res/values-lv/rating_system_strings.xml b/res/values-lv/rating_system_strings.xml
index e4a3959b..3bbdacaf 100644
--- a/res/values-lv/rating_system_strings.xml
+++ b/res/values-lv/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index affcd230..00021bca 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Atpakaļ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programmu ceļvedis"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Pieejami jauni kanāli"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Saite nav pieejama."</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Atvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Slēgtie paraksti"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Attēla režīms"</string>
@@ -125,6 +124,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Detalizēti vērtējumi"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"PIN ievade, lai skatītos šo kanālu"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"PIN ievade, lai skatītos šo programmu"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Šī programma ir novērtēta kā <xliff:g id="RATING">%1$s</xliff:g>. Lai skatītos šo programmu, ievadiet PIN kodu."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN ievade"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Lai iestatītu vecāku kontroli, izveidojiet PIN kodu."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Ievadiet jauno PIN"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Atklātā pirmkoda licences"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Atklātā pirmkoda licences"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versija"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Palīdzēt uzlabot tiešraides kanālus"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Kopīgojiet anonīmus lietojuma un diagnostikas datus ar uzņēmumu Google, lai mēs varētu uzlabot lietotni Dzīvie kanāli un novērst tādas problēmas kā avarēšana vai lēna reaģēšana."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Lai skatītos šo kanālu, nospiediet pa labi vērsto bultiņu un ievadiet PIN kodu."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Lai skatītos šo programmu, nospiediet pa labi vērsto bultiņu un ievadiet PIN kodu."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Šī programma ir novērtēta kā “<xliff:g id="RATING">%1$s</xliff:g>”.\nLai skatītos šo programmu, nospiediet pa labi vērsto bultiņu un ievadiet PIN kodu."</string>
@@ -159,6 +157,11 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Tikai audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Vājš signāls"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Nav interneta savienojuma."</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="zero">Šo kanālu nevar atskaņot līdz plkst. <xliff:g id="END_TIME_1">%1$s</xliff:g>, jo tiek ierakstīti citi kanāli. \n\nNospiediet “Pa labi”, lai pielāgotu ierakstīšanas grafiku.</item>
+ <item quantity="one">Šo kanālu nevar atskaņot līdz plkst. <xliff:g id="END_TIME_1">%1$s</xliff:g>, jo tiek ierakstīti citi kanāli. \n\nNospiediet “Pa labi”, lai pielāgotu ierakstīšanas grafiku.</item>
+ <item quantity="other">Šo kanālu nevar atskaņot līdz plkst. <xliff:g id="END_TIME_1">%1$s</xliff:g>, jo tiek ierakstīti citi kanāli. \n\nNospiediet “Pa labi”, lai pielāgotu ierakstīšanas grafiku.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Nav nosaukuma"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanāls bloķēts"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Jauni"</string>
@@ -171,8 +174,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nav pieejams neviens kanāls"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Jauna"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nav iestatīts"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Iegūt vairāk avotu"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Pārlūkojiet lietotnes, kas piedāvā tiešraides kanālus"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Iegūt vairāk avotu"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Pārlūkot lietotnes, kas piedāvā tiešsaistes kanālus"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Pieejami jauni kanālu avoti"</string>
<string name="new_sources_description" msgid="749649005588426813">"Jaunajos kanālu avotos ir pieejami kanāli.\nIestatiet tos tūlīt vai vēlāk — izmantojot kanālu avotu iestatījumu."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Iestatīt tūlīt"</string>
@@ -190,8 +193,169 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Visi avota kanāli ir paslēpti.\nAtlasiet vismaz vienu kanālu, ko skatīties."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videoklips negaidīti nav pieejams."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Poga ATPAKAĻ ir paredzēta pievienotajai ierīcei. Lai izietu, nospiediet pogu SĀKUMS."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Šajā ierīcē, kurā instalēta operētājsistēma Android Lollipop, netiek atbalstīta lietotne Tiešraides kanāli."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Lietotnei Tiešraides kanāli ir nepieciešama atļauja lasīt TV sarakstus."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Iestatiet avotus"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Lietotnē Dzīvie kanāli varat skatīties tradicionālos TV kanālus, kā arī straumēt kanālus no citām lietotnēm. \n\nLai sāktu, iestatiet jau instalētos kanālu avotus. Vai pārlūkojiet Google Play veikalu, kurā pieejamas citas dzīvo kanālu lietotnes."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Ieraksti un grafiki"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minūtes"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minūtes"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 stunda"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 stundas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nesenie"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ieplānotie"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Sērijas"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Citas"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanālu nevar ierakstīt."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programmu nevar ierakstīt."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Tika ieplānota programmas <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ierakstīšana."</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Tiek ierakstīta programma <xliff:g id="PROGRAMNAME">%1$s</xliff:g>, sākot no šī brīža līdz: <xliff:g id="ENDTIME">%2$s</xliff:g>."</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Pilns grafiks"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="zero">Nākamās %1$d dienas</item>
+ <item quantity="one">Nākamā %1$d diena</item>
+ <item quantity="other">Nākamās %1$d dienas</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="zero">%1$d minūšu</item>
+ <item quantity="one">%1$d minūte</item>
+ <item quantity="other">%1$d minūtes</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="zero">%1$d jaunu ierakstu</item>
+ <item quantity="one">%1$d jauns ieraksts</item>
+ <item quantity="other">%1$d jauni ieraksti</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="zero">%1$d ierakstu</item>
+ <item quantity="one">%1$d ieraksts</item>
+ <item quantity="other">%1$d ieraksti</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="zero">%1$d ieplānotu ierakstu</item>
+ <item quantity="one">%1$d ieplānots ieraksts</item>
+ <item quantity="other">%1$d ieplānoti ieraksti</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Skatīties"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Atskaņot no sākuma"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Atsākt atskaņošanu"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Dzēst"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Dzēst ierakstus"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Atsākt"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Skatīt grafiku"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Uzzināt vairāk"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Ierakstu dzēšana"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Atlasiet sērijas, kuras vēlaties dzēst. Pēc dzēšanas tās nevarēs atjaunot."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nav neviena ieraksta, ko dzēst."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Atlasīt skatītās sērijas"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Atlasīt visas sērijas"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Noņemt atlasi visām sērijām"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Noskatīts: <xliff:g id="WATCHED">%1$d</xliff:g> no <xliff:g id="DURATION">%2$d</xliff:g> min"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Noskatīts: <xliff:g id="WATCHED">%1$d</xliff:g> no <xliff:g id="DURATION">%2$d</xliff:g> s"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nekad nav skatīti"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="zero">%1$d no %2$d sērijām ir izdzēstas</item>
+ <item quantity="one">%1$d no %2$d sērijām ir izdzēsta</item>
+ <item quantity="other">%1$d no %2$d sērijām ir izdzēstas</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritāte"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Visaugstākā"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Viszemākā"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanāli"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Jebkurš"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Prioritātes izvēle"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Ja vēlaties ierakstīt pārāk daudz programmu vienlaikus, tiks ierakstītas tikai programmas ar augstāku prioritāti."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Saglabāt"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Vienreizējiem ierakstiem ir visaugstākā prioritāte"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Atcelt"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Atcelt"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Aizmirst"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Apturēt"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Skatīt ierakstīšanas grafiku"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Šī viena programma"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"šobrīd–<xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Visas sērijas…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Vienalga ieplānot"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Tā vietā ierakstīt tālāk norādīto"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Atcelt šo ierakstīšanu"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Skatīties tūlīt"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Var ierakstīt"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Ierakstīšana ir ieplānota"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Ierakstīšanas konflikts"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Ierakstīšana"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Neizdevās ierakstīt"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Tiek lasītas programmas, lai izveidotu ierakstīšanas grafikus."</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Tiek lasītas programmas"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Ciparvideo ierakstītājam nepieciešama lielāka krātuve"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Jūs varēsiet ierakstīt programmas, izmantojot ciparvideo ierakstītāju. Taču pašlaik jūsu ierīces krātuvē nav pietiekami daudz vietas, lai tas darbotos. Lūdzu, pievienojiet vismaz <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB lielu ārējo disku un izpildiet sniegtos norādījumus, lai formatētu to kā ierīces krātuvi."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Trūkst krātuves"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Trūkst ciparvideo ierakstītāja izmantotās krātuves. Lūdzu, pievienojiet ārējo disku, ko izmantojāt iepriekš ciparvideo ierakstītāja atkārtotai iespējošanai. Varat arī izvēlēties aizmirst krātuvi, ja tā vairs nav pieejama."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Vai aizmirst krātuvi?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Viss jūsu ierakstītais saturs un grafiki tiks zaudēti."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Vai apturēt ierakstīšanu?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Ierakstītais saturs tiks saglabāts."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Ierakstīšana ir ieplānota, taču ir konflikti"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Ierakstīšana tika sākta, taču ir konflikti"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Programma <xliff:g id="PROGRAMNAME">%1$s</xliff:g> tiks ierakstīta."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Notiek kanāla <xliff:g id="CHANNELNAME">%1$s</xliff:g> ierakstīšana."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Dažas programmas <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> daļas netiks ierakstītas."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Dažas programmu <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> un <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> daļas netiks ierakstītas."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Dažas programmu <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> daļas un vēl viena ieplānotā programma netiks ierakstīta."</string>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for dvr_program_conflict_dialog_description_many (1008340710252647947) -->
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ko jūs vēlaties ierakstīt?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Cik ilgi vēlaties veikt ierakstīšanu?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Jau ieplānots"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Šo pārraidi jau ir plānots ierakstīt plkst. <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Jau tika ierakstīta"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Šī pārraide jau ir ierakstīta. Tā ir pieejama DVR bibliotēkā."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Ierakstītā programma netika atrasta."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Saistītie ieraksti"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nav programmas apraksta)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="zero">%1$d ierakstu</item>
+ <item quantity="one">%1$d ieraksts</item>
+ <item quantity="other">%1$d ieraksti</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Programma “<xliff:g id="PROGRAMNAME">%1$s</xliff:g>” ir noņemta no ierakstīšanas grafika"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Kanālu meklētāja konfliktu dēļ tiks ierakstīts daļēji"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Kanālu meklētāja konfliktu dēļ netiks ierakstīts"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Grafikā pašlaik nevienas pārraides ierakstīšana nav ieplānota.\nVarat ieplānot ierakstīšanu no pārraižu ceļveža."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="zero">%1$d ierakstīšanas konflikti</item>
+ <item quantity="one">%1$d ierakstīšanas konflikts</item>
+ <item quantity="other">%1$d ierakstīšanas konflikti</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Sērijas iestatījumi"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Sākt sērijas ierakstīšanu"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Apturēt sērijas ierakst."</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Vai apturēt sērijas ierakstīšanu?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Ierakstītās sērijas būs pieejamas DVR bibliotēkā."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Apturēt"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nav pieejama neviena sērija.\nTās tiks ierakstītas, kad būs pieejamas."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="zero">(%1$d minūtes)</item>
+ <item quantity="one">(%1$d minūte)</item>
+ <item quantity="other">(%1$d minūtes)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Šodien"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Rīt"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Vakar"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Plkst. <xliff:g id="TIME_RANGE">%1$s</xliff:g> šodien"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Plkst. <xliff:g id="TIME_RANGE">%1$s</xliff:g> rīt"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Rezultāts"</string>
</resources>
diff --git a/res/values-mk-rMK/arrays.xml b/res/values-mk-rMK/arrays.xml
index 007b18b1..b1ae7467 100644
--- a/res/values-mk-rMK/arrays.xml
+++ b/res/values-mk-rMK/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Цел"</item>
<item msgid="8568284598210500589">"Зум"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Сите канали"</item>
- <item msgid="6897460857821394118">"Семејство/деца"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Пазарење"</item>
- <item msgid="3296058637230163031">"Филмови"</item>
- <item msgid="1054540282883891201">"Комедија"</item>
- <item msgid="7900158429062595471">"Патување"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Образование"</item>
- <item msgid="7396447839483867269">"Животни/див свет"</item>
- <item msgid="4738043455148062673">"Вести"</item>
- <item msgid="7405041316051047427">"Игри"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Сите канали"</item>
- <item msgid="7909003973960375395">"Семејство/деца"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Пазарење"</item>
- <item msgid="6083795019290250078">"Филмови"</item>
- <item msgid="8302638329222449550">"Комедија"</item>
- <item msgid="3803709976021475052">"Патување"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Образование"</item>
- <item msgid="7511135485827589547">"Животни/див свет"</item>
- <item msgid="6961248112238009967">"Вести"</item>
- <item msgid="6484685553679698447">"Игри"</item>
- <item msgid="2737158328243183190">"Уметности"</item>
- <item msgid="6577176952650166615">"Забава"</item>
- <item msgid="7886693831871777617">"Стил на живеење"</item>
- <item msgid="8145832312485577062">"Музика"</item>
- <item msgid="1345789204804308580">"Главно"</item>
- <item msgid="2736680312770771994">"Техника/наука"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Сите канали"</item>
+ <item msgid="928298872841713530">"Семејство/деца"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Пазарење"</item>
+ <item msgid="167201149441442173">"Филмови"</item>
+ <item msgid="525966731464264290">"Комедија"</item>
+ <item msgid="6096710741527327836">"Патување"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Образование"</item>
+ <item msgid="7221999662426308394">"Животни/див свет"</item>
+ <item msgid="375300513250925001">"Вести"</item>
+ <item msgid="7746320336582330410">"Игри"</item>
+ <item msgid="1255741860568329178">"Уметности"</item>
+ <item msgid="7603949681065702867">"Забава"</item>
+ <item msgid="4453821994746804366">"Стил на живеење"</item>
+ <item msgid="3488534597567932843">"Музика"</item>
+ <item msgid="7452153120614274095">"Главно"</item>
+ <item msgid="8215762047341133299">"Техника/наука"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ТВ канали во живо"</item>
diff --git a/res/values-mk-rMK/rating_system_strings.xml b/res/values-mk-rMK/rating_system_strings.xml
index 36cd59d6..da9a40b3 100644
--- a/res/values-mk-rMK/rating_system_strings.xml
+++ b/res/values-mk-rMK/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-mk-rMK/strings.xml b/res/values-mk-rMK/strings.xml
index db0f4c5d..566377a8 100644
--- a/res/values-mk-rMK/strings.xml
+++ b/res/values-mk-rMK/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Претходно"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Програмски водич"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Достапни се нови канали"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Не е достапна врска"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Отвори <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Затворени титли"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Реж. на прикаж."</string>
@@ -102,7 +101,7 @@
<string name="option_channels_unlock_all" msgid="6839513296447567623">"Одблокирај ги сите"</string>
<string name="option_channels_subheader_hidden" msgid="4669425935426972078">"Сокриени канали"</string>
<string name="option_program_restrictions" msgid="241342023067364108">"Прог. ограничувања"</string>
- <string name="option_change_pin" msgid="2881594075631152566">"Измени ПИН"</string>
+ <string name="option_change_pin" msgid="2881594075631152566">"Измени PIN"</string>
<string name="option_country_rating_systems" msgid="7288569813945260224">"Систем за процена"</string>
<string name="option_ratings" msgid="4009116954188688616">"Проценки"</string>
<string name="option_see_all_rating_systems" msgid="7702673500014877288">"Види ги сите сист."</string>
@@ -122,19 +121,20 @@
<skip />
<string name="option_subrating_title" msgid="5485055507818077595">"%1$s и под-рејтинг"</string>
<string name="option_subrating_header" msgid="4637961301549615855">"Под-рејтинг"</string>
- <string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Внесете го вашиот ПИН за да го гледате каналот"</string>
- <string name="pin_enter_unlock_program" msgid="7311628843209871203">"Внесете го вашиот ПИН за да ја гледате програмата"</string>
- <string name="pin_enter_pin" msgid="249314665028035038">"Внесете го вашиот ПИН"</string>
- <string name="pin_enter_create_pin" msgid="3385754356793309946">"За да поставите родителска контрола, креирајте ПИН."</string>
- <string name="pin_enter_new_pin" msgid="1739471585849790384">"Внесете го новиот ПИН"</string>
- <string name="pin_enter_again" msgid="2618999754723090427">"Потврдете го вашиот ПИН"</string>
- <string name="pin_enter_old_pin" msgid="4588282612931041919">"Внесете го тековниот ПИН"</string>
+ <string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Внесете го вашиот PIN за да го гледате каналот"</string>
+ <string name="pin_enter_unlock_program" msgid="7311628843209871203">"Внесете го вашиот PIN за да ја гледате програмата"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Програмава е оценета со <xliff:g id="RATING">%1$s</xliff:g>. Внесете го PIN-кодот за да ја гледате"</string>
+ <string name="pin_enter_pin" msgid="249314665028035038">"Внесете го вашиот PIN"</string>
+ <string name="pin_enter_create_pin" msgid="3385754356793309946">"За да поставите родителска контрола, креирајте PIN."</string>
+ <string name="pin_enter_new_pin" msgid="1739471585849790384">"Внесете го новиот PIN"</string>
+ <string name="pin_enter_again" msgid="2618999754723090427">"Потврдете го вашиот PIN"</string>
+ <string name="pin_enter_old_pin" msgid="4588282612931041919">"Внесете го тековниот PIN"</string>
<plurals name="pin_enter_countdown" formatted="false" msgid="3415233538538544309">
- <item quantity="one">Внесовте погрешен ПИН-код 5 пати.\nОбидете се повторно за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунда.</item>
- <item quantity="other">Внесовте погрешен ПИН-код 5 пати.\nОбидете се повторно за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунди.</item>
+ <item quantity="one">Внесовте погрешен PIN-код 5 пати.\nОбидете се повторно за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунда.</item>
+ <item quantity="other">Внесовте погрешен PIN-код 5 пати.\nОбидете се повторно за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунди.</item>
</plurals>
- <string name="pin_toast_wrong" msgid="2126295626095048746">"ПИН-кодот е погрешен. Обидете се повторно."</string>
- <string name="pin_toast_not_match" msgid="4283624338659521768">"Обидете се повторно, ПИН-кодот не се совпаѓа"</string>
+ <string name="pin_toast_wrong" msgid="2126295626095048746">"PIN-кодот е погрешен. Обидете се повторно."</string>
+ <string name="pin_toast_not_match" msgid="4283624338659521768">"Обидете се повторно, PIN-кодот не се совпаѓа"</string>
<string name="side_panel_title_settings" msgid="8244327316510918755">"Поставки"</string>
<string name="settings_channel_source_item_customize_channels" msgid="6115770679732624593">"Приспособи го списокот канали"</string>
<string name="settings_channel_source_item_customize_channels_description" msgid="8966243790328235580">"Изберете канали за програмскиот водич"</string>
@@ -144,11 +144,9 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Лиценци за софтвер со отворен код"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Лиценци за отворен код"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Верзија"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Помогнете да се подобрат каналите во живо"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Споделувајте анонимни употреба и дијагностика со Google за да можеме да ги подобриме ТВ каналите во живо и да спречиме проблеми како падови и замрзнување."</string>
- <string name="tvview_channel_locked" msgid="6486375335718400728">"За да го гледате овој канал, притиснете Во ред и внесете го вашиот ПИН"</string>
- <string name="tvview_content_locked" msgid="391823084917017730">"За да ја гледате оваа програма, притиснете Во ред и внесете го вашиот ПИН"</string>
- <string name="tvview_content_locked_format" msgid="3741874636031338247">"Оваа програма е оценета <xliff:g id="RATING">%1$s</xliff:g>.\nЗа да ја гледате оваа програма, притиснете Во ред и внесете го ПИН-от."</string>
+ <string name="tvview_channel_locked" msgid="6486375335718400728">"За да го гледате овој канал, притиснете Во ред и внесете го вашиот PIN"</string>
+ <string name="tvview_content_locked" msgid="391823084917017730">"За да ја гледате оваа програма, притиснете Во ред и внесете го вашиот PIN"</string>
+ <string name="tvview_content_locked_format" msgid="3741874636031338247">"Оваа програма е оценета <xliff:g id="RATING">%1$s</xliff:g>.\nЗа да ја гледате оваа програма, притиснете Во ред и внесете го PIN-от."</string>
<string name="tvview_channel_locked_no_permission" msgid="677653135227590620">"За да го гледате овој канал, користете ја стандардната апликација за телевизија во живо."</string>
<string name="tvview_content_locked_no_permission" msgid="2279126235895507764">"За да ја гледате програмава, користете ја стандардната апликација за телевизија во живо."</string>
<string name="tvview_content_locked_format_no_permission" msgid="5690794624572767106">"Оваа програма е оценета <xliff:g id="RATING">%1$s</xliff:g>.\nЗа да ја гледате програмава, користете ја стандардната апликација за телевизија во живо."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Само звук"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Слаб сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Нема интернет-врска"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Каналов не може да се пушти сѐ до <xliff:g id="END_TIME_1">%1$s</xliff:g> бидејќи се снимаат други канали. \n\nДопрете “Десно“ за приспособување на распоредот на снимање.</item>
+ <item quantity="other">Каналов не може да се пушти сѐ до <xliff:g id="END_TIME_1">%1$s</xliff:g> бидејќи се снимаат други канали. \n\nДопрете “Десно“ за приспособување на распоредот на снимање.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Без наслов"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Каналот е блокиран"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Нов"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Нема достапни канали"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Нов"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Не е поставен"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Земете повеќе извори"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Прелистувајте апликации што нудат канали во живо"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Преземете повеќе извори"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Прелистувајте апликации што нудат канали во живо"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Достапни се нови извори на канали"</string>
<string name="new_sources_description" msgid="749649005588426813">"Нови извори на канали имаат понуда на канали.\nПоставете ги сега или направете го тоа подоцна во поставките за извори на канали."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Постави сега"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Сите изворни канали се сокриени.\nИзберете барем еден канал за да го гледате."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Видеото е неочекувано недостапно"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Копчето НАЗАД е за поврзаниот уред. Притиснете на копчето ПОЧЕТНА СТРАНИЦА за да излезете."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Каналите во живо не се поддржани на уредов со Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"На каналите во живо им е потребна дозвола за да ги читаат ТВ-листите."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Поставете ги изворите"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ТВ каналите во живо го комбинираат искуството на традиционалните ТВ канали со преносот на канали што го овозможуваат апликациите. \n\nЗапочнете со поставување на изворите на канали што се веќе инсталирани. Или прелистајте во Google Play Store за повеќе апликации што нудат ТВ канали во живо."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Снимки и распореди"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 минути"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 минути"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 час"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 часа"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Неодамнешни"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Закажани"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Серии"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Други"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Каналот не може да се сними."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Програмата не може да се сними."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> е закажана за снимање."</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Се снима <xliff:g id="PROGRAMNAME">%1$s</xliff:g> од сега до <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Целосен распоред"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Следниот %1$d ден</item>
+ <item quantity="other">Следните %1$d дена</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d минута</item>
+ <item quantity="other">%1$d минути</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d ново снимање</item>
+ <item quantity="other">%1$d нови снимања</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d снимање</item>
+ <item quantity="other">%1$d снимања</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d закажано снимање</item>
+ <item quantity="other">%1$d закажани снимања</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Часовник"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Репродуцирај отпочеток"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Прод. репродукција"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Избриши"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Избриши ги снимките"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Продолжи"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Сезона <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Види распоред"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Прочитајте повеќе"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Избриши ги снимките"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Изберете ги епизодите што сакате да ги избришете. Не може да се вратат откако ќе се избришат."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Нема снимки за бришење."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Изберете ги гледаните епизоди"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Изберете ги сите епизоди"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Откажи избор на сите епизоди"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Изгледани се <xliff:g id="WATCHED">%1$d</xliff:g> од <xliff:g id="DURATION">%2$d</xliff:g> минути"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Изгледани се <xliff:g id="WATCHED">%1$d</xliff:g> од <xliff:g id="DURATION">%2$d</xliff:g> секунди"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Никогаш не се гледани"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d од %2$d епизода се избришани</item>
+ <item quantity="other">%1$d од %2$d епизоди се избришани</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Приоритет"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Највисок"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Најнизок"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Бр. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Канали"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Кој било"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Изберете приоритет"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Кога има повеќе програми што треба да се снимаат во исто време, ќе се снимат само оние со повисок приоритет."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Зачувај"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Еднократните снимања имаат највисок приоритет"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Откажи"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Откажи"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Заборави"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Сопри"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Прикажи распоред на снимање"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Само оваа програма"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"сега - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Целата серија…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Сепак закажи"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Наместо неа, снимај ја оваа"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Откажете го снимањево"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Гледајте сега"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Може да се снима"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Снимањето е закажано"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Конфликт при снимање"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Се снима"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Неуспешно снимање"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Се читаат програми за да се создадат распореди за снимање"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Се читаат програми"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Потребна е поголема меморија за DVR"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Ќе може да снимате програми со DVR. Но во моментов нема доволно простор на вашиот уред за да може DVR да функционира. Поврзете надворешна податочна едница од <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB или повеќе и следете ги чекорите за да ја форматирате како меморија на уредот."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Недостасува простор"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Недостасува дел од просторот што го користи DVR. Поврзете го надворешниот диск што го користевте претходно за да овозможите DVR повторно. Во спротивно, може да изберете да се заборави просторот ако веќе не е достапен."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Да се заборави просторот?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Сите ваши снимени содржини и распореди ќе се изгубат."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Да се сопре со снимање?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Снимените содржини ќе се зачуваат."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Снимањето е закажано, но постојат конфликти"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Снимањето започна, но постојат конфликти"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ќе се сними."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> се снима."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Некои делови од <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> нема да се снимат."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Некои делови од <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> нема да се снимат."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Некои делови од <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> и уште една закажана нема да се снимат."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Некои делови од <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> и уште %4$d закажана нема да се снимат.</item>
+ <item quantity="other">Некои делови од <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> и уште %4$d закажани нема да се снимат.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Што би сакале да снимите?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Колку долго би сакале да снимате?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Веќе е закажана"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Истата програма е веќе закажана за снимање во <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Веќе е снимена"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Програмава е веќе снимена. Достапна е во DVR-збирката."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Снимената програма не е пронајдена."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Поврзани снимки"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Нема опис на програмата)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d снимка</item>
+ <item quantity="other">%1$d снимки</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> е отстранета од распоредот на снимање"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Ќе се сними делумно поради конфликти со приемникот."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Нема да се сними поради конфликти со приемникот."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Сѐ уште нема закажани снимања.\nМоже да закажете снимање од програмскиот водич."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d конфликт на снимање</item>
+ <item quantity="other">%1$d конфликти на снимање</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Поставки за серии"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Започни со снимање серија"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Сопри го снимањето серија"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Да се сопре снимањето на серијата?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Снимените епизоди ќе останат достапни во DVR-збирката."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Сопри"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Не се достапни епизоди.\nЌе се снимат штом ќе бидат достапни."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d минута)</item>
+ <item quantity="other">(%1$d минути)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Денес"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Утре"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Вчера"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> денес"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> утре"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Оценка"</string>
</resources>
diff --git a/res/values-ml-rIN/arrays.xml b/res/values-ml-rIN/arrays.xml
index 3c772200..383837e7 100644
--- a/res/values-ml-rIN/arrays.xml
+++ b/res/values-ml-rIN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"നിറഞ്ഞു"</item>
<item msgid="8568284598210500589">"സൂം ചെയ്യുക"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"എല്ലാ ചാനലുകളും"</item>
- <item msgid="6897460857821394118">"കുടുംബം/കുട്ടികൾ"</item>
- <item msgid="551257741825778215">"സ്‌പോർട്സ്"</item>
- <item msgid="452133796804325879">"ഷോപ്പിംഗ്"</item>
- <item msgid="3296058637230163031">"സിനിമകൾ"</item>
- <item msgid="1054540282883891201">"തമാശ"</item>
- <item msgid="7900158429062595471">"യാത്ര"</item>
- <item msgid="3768998587825611787">"നാടകം"</item>
- <item msgid="8340620094959282881">"വിദ്യാഭ്യാസം"</item>
- <item msgid="7396447839483867269">"മൃഗങ്ങൾ/വൈൽഡ്‌‌ലൈഫ്"</item>
- <item msgid="4738043455148062673">"വാർത്ത"</item>
- <item msgid="7405041316051047427">"ഗെയിമിംഗ്"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"എല്ലാ ചാനലുകളും"</item>
- <item msgid="7909003973960375395">"കുടുംബം/കുട്ടികൾ"</item>
- <item msgid="3185279732911635789">"സ്‌പോർട്സ്"</item>
- <item msgid="4704858492065325964">"ഷോപ്പിംഗ്"</item>
- <item msgid="6083795019290250078">"സിനിമകൾ"</item>
- <item msgid="8302638329222449550">"തമാശ"</item>
- <item msgid="3803709976021475052">"യാത്ര"</item>
- <item msgid="8116747365234169059">"നാടകം"</item>
- <item msgid="7356447541595315913">"വിദ്യാഭ്യാസം"</item>
- <item msgid="7511135485827589547">"മൃഗങ്ങൾ/വൈൽഡ്‌‌ലൈഫ്"</item>
- <item msgid="6961248112238009967">"വാർത്ത"</item>
- <item msgid="6484685553679698447">"ഗെയിമിംഗ്"</item>
- <item msgid="2737158328243183190">"കലകൾ"</item>
- <item msgid="6577176952650166615">"വിനോദം"</item>
- <item msgid="7886693831871777617">"ജീവിതശൈലി"</item>
- <item msgid="8145832312485577062">"സംഗീതം"</item>
- <item msgid="1345789204804308580">"പ്രീമിയർ"</item>
- <item msgid="2736680312770771994">"സാങ്കേതികം/ശാസ്‌ത്രം"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"എല്ലാ ചാനലുകളും"</item>
+ <item msgid="928298872841713530">"കുടുംബാംഗങ്ങൾ/കുട്ടികൾ"</item>
+ <item msgid="2751606947569857164">"സ്‌പോർട്സ്"</item>
+ <item msgid="7345749789651321496">"ഷോപ്പിംഗ്"</item>
+ <item msgid="167201149441442173">"സിനിമകൾ"</item>
+ <item msgid="525966731464264290">"ഹാസ്യം"</item>
+ <item msgid="6096710741527327836">"യാത്ര"</item>
+ <item msgid="2851882187117833883">"നാടകം"</item>
+ <item msgid="78492781188719038">"വിദ്യാഭ്യാസം"</item>
+ <item msgid="7221999662426308394">"മൃഗങ്ങൾ/വൈൽഡ്‌‌ലൈഫ്"</item>
+ <item msgid="375300513250925001">"വാർത്ത"</item>
+ <item msgid="7746320336582330410">"ഗെയിമിംഗ്"</item>
+ <item msgid="1255741860568329178">"കലകള്‍"</item>
+ <item msgid="7603949681065702867">"വിനോദം"</item>
+ <item msgid="4453821994746804366">"ജീവിതശൈലി"</item>
+ <item msgid="3488534597567932843">"സംഗീതം"</item>
+ <item msgid="7452153120614274095">"പ്രീമിയർ"</item>
+ <item msgid="8215762047341133299">"സാങ്കേതികവിദ്യ/ശാസ്‌ത്രം"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"തത്സമയ ചാനലുകൾ"</item>
diff --git a/res/values-ml-rIN/rating_system_strings.xml b/res/values-ml-rIN/rating_system_strings.xml
index 15e3a612..e17f91f8 100644
--- a/res/values-ml-rIN/rating_system_strings.xml
+++ b/res/values-ml-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ml-rIN/strings.xml b/res/values-ml-rIN/strings.xml
index 3289f763..e29a8755 100644
--- a/res/values-ml-rIN/strings.xml
+++ b/res/values-ml-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"മുമ്പത്തെ"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"പ്രോഗ്രാം സഹായി"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"പുതിയ ചാനലുകൾ ലഭ്യമാണ്"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ലിങ്കുകളൊന്നും ലഭ്യമല്ല"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> തുറക്കുക"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"അടച്ച അടിക്കുറിപ്പുകൾ"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ഡിസ്‌പ്ലേ മോഡ്"</string>
@@ -85,7 +84,7 @@
<string name="side_panel_title_group_by" msgid="1783176601425788939">"ഗ്രൂപ്പ് അനുസരിച്ച്"</string>
<string name="program_guide_content_locked" msgid="198056836554559553">"ഈ പ്രോഗ്രാം തടഞ്ഞിരിക്കുന്നു"</string>
<string name="program_guide_content_locked_format" msgid="514915272862967389">"ഈ പ്രോഗ്രാമിനെ <xliff:g id="RATING">%1$s</xliff:g> എന്ന് റേറ്റുചെയ്‌തു"</string>
- <string name="msg_no_setup_activity" msgid="7746893144640239857">"യാന്ത്രികമായി സ്‌കാൻ ചെയ്യുന്നതിനെ ഇൻപുട്ട് പിന്തുണയ്‌ക്കുന്നില്ല"</string>
+ <string name="msg_no_setup_activity" msgid="7746893144640239857">"സ്വയമേവ സ്‌കാൻ ചെയ്യുന്നതിനെ ഇൻപുട്ട് പിന്തുണയ്‌ക്കുന്നില്ല"</string>
<string name="msg_unable_to_start_setup_activity" msgid="8402612466599977855">"\'<xliff:g id="TV_INPUT">%s</xliff:g>\' എന്നതിനായി യാന്ത്രിക സ്‌കാൻ ആരംഭിക്കാനായില്ല"</string>
<string name="msg_unable_to_start_system_captioning_settings" msgid="705242616044165668">"അടച്ച അടിക്കുറിപ്പുകൾക്കായി സിസ്‌‌റ്റത്തിലെ മുൻഗണനകൾ ആരംഭിക്കാനാകില്ല."</string>
<!-- String.format failed for translation -->
@@ -122,6 +121,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ഉപറേറ്റിംഗുകൾ"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ഈ ചാനൽ കാണാൻ നിങ്ങളുടെ പിൻ നൽകുക"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ഈ പ്രോഗ്രാം കാണാൻ നിങ്ങളുടെ പിൻ നൽകുക"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ഈ പ്രോഗ്രാമിനെ <xliff:g id="RATING">%1$s</xliff:g> എന്ന് റേറ്റുചെയ്‌തു. ഈ പ്രോഗ്രാം കാണുന്നതിന് നിങ്ങളുടെ പിൻ നൽകുക."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"നിങ്ങളുടെ പിൻ നൽകുക"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"രക്ഷാകർതൃ നിയന്ത്രണങ്ങൾ സജ്ജമാക്കാൻ, ഒരു പിൻ സൃഷ്‌ടിക്കുക"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"പുതിയ പിൻ നൽകുക"</string>
@@ -142,8 +142,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ഓപ്പൺ സോഴ്‌സ് ലൈസൻസ്"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ഓപ്പൺ സോഴ്‌സ് ലൈസൻസുകൾ"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"പതിപ്പ്"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"തത്സമയ ചാനലുകൾ മെച്ചപ്പെടുത്താൻ സഹായിക്കുക"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"പേരുവിവരങ്ങളില്ലാത്ത ഉപയോഗ വിവരങ്ങളും പ്രശ്നനിർണ്ണയ വിവരങ്ങളും Google-മായി പങ്കിടുക, അതുവഴി ഞങ്ങൾക്ക് തത്സമയ ചാനലുകൾ കൂടുതൽ മെച്ചപ്പെടുത്താനും ക്രാഷിംഗും ഫ്രീസിംഗും പോലുള്ള പ്രശ്നങ്ങൾ തടയാനും കഴിയും."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ഈ ചാനൽ കാണുന്നതിന് വലതുവശത്ത് അമർത്തിക്കൊണ്ട് നിങ്ങളുടെ പിൻ നൽകുക"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ഈ പ്രോഗ്രാം കാണുന്നതിന് വലതുവശത്ത് അമർത്തിക്കൊണ്ട് നിങ്ങളുടെ പിൻ നൽകുക"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ഈ പ്രോഗ്രാമിനെ <xliff:g id="RATING">%1$s</xliff:g> എന്ന് റേറ്റുചെയ്‌തു.\nഈ പ്രോഗ്രാം കാണുന്നതിന് വലതുവശത്ത് അമർത്തിക്കൊണ്ട് നിങ്ങളുടെ പിൻ നൽകുക."</string>
@@ -155,6 +153,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ഓഡിയോ മാത്രം"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"സിഗ്‌നൽ ദുർബലമാണ്"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ഇന്റർനെറ്റ് കണക്ഷനില്ല"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">മറ്റ് ചാനലുകൾ റെക്കോർഡ് ചെയ്തുകൊണ്ടിരിക്കുന്നതിനാൽ <xliff:g id="END_TIME_1">%1$s</xliff:g> വരെ ഈ ചാനൽ പ്ലേ ചെയ്യാൻ കഴിയില്ല. \n\nറെക്കോർഡിംഗ് ഷെഡ്യൂൾ ക്രമപ്പെടുത്തുന്നതിന് വലത് അമർത്തുക.</item>
+ <item quantity="one">മറ്റൊരു ചാനൽ റെക്കോർഡ് ചെയ്തുകൊണ്ടിരിക്കുന്നതിനാൽ <xliff:g id="END_TIME_0">%1$s</xliff:g> വരെ ഈ ചാനൽ പ്ലേ ചെയ്യാൻ കഴിയില്ല. \n\nറെക്കോർഡിംഗ് ഷെഡ്യൂൾ ക്രമപ്പെടുത്തുന്നതിന് വലത് അമർത്തുക.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ശീർഷകമൊന്നുമില്ല"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"ചാനൽ തടഞ്ഞിരിക്കുന്നു"</string>
<string name="setup_category_new" msgid="2899355289563443627">"പുതിയത്"</string>
@@ -166,8 +168,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ചാനലുകളൊന്നും ലഭ്യമല്ല"</string>
<string name="setup_input_new" msgid="3337725672277046798">"പുതിയത്"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"സജ്ജീകരിച്ചിട്ടില്ല"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"കൂടുതൽ ഉറവിടങ്ങൾ സ്വീകരിക്കുക"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"തത്സമയ ചാനലുകൾ നൽകുന്ന ആപ്‌സ് ബ്രൗസുചെയ്യുക"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"കൂടുതൽ ഉറവിടങ്ങൾ സ്വീകരിക്കുക"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"തത്സമയ ചാനലുകൾ നൽകുന്ന ആപ്‌സ് ബ്രൗസുചെയ്യുക"</string>
<string name="new_sources_title" msgid="3878933676500061895">"ലഭ്യമായ പുതിയ ചാനൽ ഉറവിടങ്ങൾ"</string>
<string name="new_sources_description" msgid="749649005588426813">"പുതിയ ചാനൽ ഉറവിടങ്ങളിൽ ആസ്വദിക്കുന്നതിന് കൂടുതൽ ചാനലുകളുണ്ട്.\nഅവയിപ്പോൾ സജ്ജീകരിക്കുകയോ ചാനൽ ഉറവിട ക്രമീകരണത്തിൽ പിന്നീട് സജ്ജീകരിക്കുകയോ ചെയ്യാം."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ഇപ്പോൾ സജ്ജീകരിക്കുക"</string>
@@ -185,8 +187,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"എല്ലാ ഉറവിട ചാനലുകളും മറച്ചിരിക്കുന്നു.\nകാണാനായി ഒരു ചാനലെങ്കിലും തിരഞ്ഞെടുക്കുക."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"അപ്രതീക്ഷിതമായി വീഡിയോ ലഭ്യമല്ല"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"കണക്‌റ്റു‌ചെയ്‌തിരിക്കുന്ന ഉപകരണത്തിനുള്ളതാണ് മടങ്ങുക എന്ന കീ. പുറത്തുകടക്കാൻ ഹോം ബട്ടൺ അമർത്തുക."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop ഉള്ള ഈ ഉപകരണത്തിൽ തത്സമയ ചാനലുകൾക്ക് പിന്തുണയില്ല."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"TV ലിസ്റ്റിംഗുകൾ വായിക്കുന്നതിന് തത്സമയ ചാനലുകൾക്ക് അനുമതി ആവശ്യമാണ്."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"നിങ്ങളുടെ ഉറവിടങ്ങൾ സജ്ജമാക്കുക"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"പരമ്പരാഗത ടിവി ചാനലുകളുടെയും ആപ്‌സ് നൽകുന്ന സ്‌ട്രീമിംഗ് ചാനലുകളുടെയും അനുഭവമാണ് തത്സമയ ചാനലുകൾ ഒരുമിപ്പിക്കുന്നത്. \n\nഇതിനകം തന്നെ ഇൻസ്റ്റാൾ ചെയ്തിട്ടുള്ള ചാനൽ ഉറവിടങ്ങൾ സജ്ജമാക്കിക്കൊണ്ട് തുടങ്ങുക. അല്ലെങ്കിൽ Google Play സ്റ്റോറിൽ നിന്ന് തത്സമയ ചാനലുകൾ നൽകുന്ന കൂടുതൽ ആപ്‌സ് ബ്രൗസുചെയ്യുക."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"റെക്കോർഡിംഗുകളും ഷെഡ്യൂളുകളും"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 മിനിറ്റ്"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 മിനിറ്റ്"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 മണിക്കൂർ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 മണിക്കൂർ"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ഏറ്റവും പുതിയത്"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"ഷെഡ്യൂൾചെയ്‌തു"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"സീരീസ്"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"മറ്റുള്ളവ"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ചാനൽ റെക്കോർഡുചെയ്യാൻ കഴിയില്ല."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"പ്രോഗ്രാം റെക്കോർഡുചെയ്യാൻ കഴിയില്ല."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"റെക്കോർഡുചെയ്യുന്നതിന് <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ഷെഡ്യൂൾ ചെയ്തിരിക്കുന്നു"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ഇപ്പോൾ മുതൽ <xliff:g id="ENDTIME">%2$s</xliff:g> വരെ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> റെക്കോർഡുചെയ്യുന്നു"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"പൂർണ്ണമായ ഷെഡ്യൂൾ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">അടുത്ത %1$d ദിവസം</item>
+ <item quantity="one">അടുത്ത %1$d ദിവസം</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d മിനിറ്റ്</item>
+ <item quantity="one">%1$d മിനിറ്റ്</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d പുതിയ റെക്കോർഡിംഗുകൾ</item>
+ <item quantity="one">%1$d പുതിയ റെക്കോർഡിംഗ്</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d റെക്കോർഡിംഗുകൾ</item>
+ <item quantity="one">%1$d റെക്കോർഡിംഗ്</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d റെക്കോർഡിംഗുകൾ ഷെഡ്യൂൾ ചെയ്തു</item>
+ <item quantity="one">%1$d റെക്കോർഡിംഗ് ഷെഡ്യൂൾ ചെയ്തു</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"കാ‍ണുക"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"തുടക്കം മുതൽ പ്ലേ ചെയ്യുക"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"പ്ലേ പുനരാരംഭിക്കുക"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"ഇല്ലാതാക്കുക"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"റെക്കോർഡിംഗ് ഇല്ലാതാക്കൂ"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"പുനരാരംഭിക്കുക"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"സീസൺ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"ഷെഡ്യൂൾ കാണുക"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"കൂടുതൽ വായിക്കുക"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"റെക്കോർഡിംഗ് ഇല്ലാതാക്കൂ"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ഇല്ലാതാക്കാൻ ആഗ്രഹിക്കുന്ന എപ്പിസോഡുകൾ തിരഞ്ഞെടുക്കുക. ഇല്ലാതാക്കിക്കഴിഞ്ഞാൽ അവ വീണ്ടെടുക്കാനാവില്ല."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ഇല്ലാതാക്കാൻ റെക്കോർഡിംഗുകൾ ഒന്നുമില്ല."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"കണ്ടവ തിരഞ്ഞെടുക്കുക"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"എല്ലാം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"എപ്പിസോഡ് തിരഞ്ഞെടുത്തത് മാറ്റൂ"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> / <xliff:g id="DURATION">%2$d</xliff:g> മിനിറ്റ് കണ്ടു"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> / <xliff:g id="DURATION">%2$d</xliff:g> സെക്കൻഡ് കണ്ടു"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"ഒരിക്കലും കണ്ടിട്ടില്ല"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d / %2$d എപ്പിസോഡുകൾ ഇല്ലാതാക്കി</item>
+ <item quantity="one">%1$d / %2$d എപ്പിസോഡ് ഇല്ലാതാക്കി</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"മു‌ൻഗണന"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"ഏറ്റവും ഉയർന്നത്"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ഏറ്റവും കുറഞ്ഞത്"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"നമ്പർ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ചാനലുകൾ"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ഏതെങ്കിലും"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"മുൻഗണന തിരഞ്ഞെടുക്കുക"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"ഒരേ സമയം നിരവധി പരിപാടികൾ റെക്കോർഡുചെയ്യേണ്ടതുണ്ടെങ്കിൽ, ഉയർന്ന മുൻഗണനകളുള്ള പ്രോഗ്രാമുകൾ മാത്രം റെക്കോർഡുചെയ്യപ്പെടും."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"സംരക്ഷിക്കുക"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ഒറ്റത്തവണ റെക്കോർഡിംഗുകൾക്ക് ഏറ്റവും ഉയർന്ന മുൻഗണന"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"റദ്ദാക്കൂ"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"റദ്ദാക്കുക"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"മറക്കുക"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"നിർത്തുക"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"റെക്കോർഡിംഗ് ഷെഡ്യൂൾ കാണുക"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ഈ ഒരൊറ്റ പ്രോഗ്രാം"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ഇപ്പോൾ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"മൊത്തം സീരീസ്…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"എന്തായാലും ഷെഡ്യൂൾ ചെയ്യുക"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"പകരം, ഇത് റെക്കോർഡ് ചെയ്യുക"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ഈ റെക്കോർഡിംഗ് റദ്ദാക്കുക"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ഇപ്പോൾ കാണുക"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"റെക്കോർഡുചെയ്യാവുന്നത്"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"റെക്കോർഡിംഗ് ഷെഡ്യൂൾചെയ്‌തു"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"റെക്കോർഡിംഗ് പൊരുത്തക്കേട്"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"റെക്കോർഡിംഗ്"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"റെക്കോർഡുചെയ്യൽ പരാജയപ്പെട്ടു"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"റെക്കോർഡിംഗ് ഷെഡ്യൂളുകൾ സൃഷ്ടിക്കാൻ പ്രോഗ്രാമുകൾ വായിക്കുന്നു"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"വായനാ പ്രോഗ്രാമുകൾ"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR-ന് കൂടുതൽ സ്റ്റോറേജ് ആവശ്യമാണ്"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"DVR ഉപയോഗിച്ച് നിങ്ങൾക്ക് പ്രോഗ്രാമുകൾ റെക്കോർഡുചെയ്യാനാകും. എന്നിരുന്നാലും, DVR പ്രവർത്തിക്കുന്നതിന് നിങ്ങളുടെ ഉപകരണത്തിൽ ഇപ്പോൾ വേണ്ടത്ര സ്റ്റോറേജ് ഇല്ല. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB-യോ കൂടുതലോ ഉള്ള ഒരു എക്സ്റ്റേണൽ ഡ്രൈവ് കണക്റ്റുചെയ്യുകയും ഉപകരണ സ്റ്റോറേജായി അത് ഫോർമാറ്റുചെയ്യുന്നതിന് നിർദ്ദേശങ്ങൾ പിന്തുടരുകയും ചെയ്യുക."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"നഷ്ടമായ സ്റ്റോറേജ്"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR ഉപയോഗിക്കുന്ന സ്റ്റോറേജിന്റെ ചിലത് നഷ്ടമായിരിക്കുന്നു. വീണ്ടും DVR പ്രവർത്തനക്ഷമമാക്കുന്നതിന്, നിങ്ങൾ മുമ്പ് ഉപയോഗിച്ച എക്സ്റ്റേണൽ ഡ്രൈവ് കണക്റ്റുചെയ്യുക. സ്റ്റോറേജ് തുടർന്നങ്ങോട്ട് ലഭ്യമല്ലെങ്കിൽ, ഇതരമാർഗ്ഗമെന്ന നിലയിൽ, നിങ്ങൾക്ക് മറക്കുന്നതിന് തിരഞ്ഞെടുക്കാവുന്നതാണ്."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"സ്റ്റോറേജ് മറക്കണോ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"നിങ്ങളുടെ റെക്കോർഡ് ചെയ്തിട്ടുള്ള എല്ലാ ഉള്ളടക്കവും ഷെഡ്യൂളുകളും നഷ്ടപ്പെടും."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"റെക്കോർഡിംഗ് നിർത്തണോ?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"റെക്കോർഡുചെയ്തിട്ടുള്ള ഉള്ളടക്കം സംരക്ഷിക്കപ്പെടും."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"റെക്കോർഡിംഗ് ഷെഡ്യൂൾ ചെയ്തിരിക്കുന്നു, എന്നാൽ പൊരുത്തക്കേടുകൾ ഉണ്ട്"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"റെക്കോർഡിംഗ് ആരംഭിച്ചിരിക്കുന്നു, എന്നാൽ പൊരുത്തക്കേടുകൾ ഉണ്ട്"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> റെക്കോർഡുചെയ്യപ്പെടും."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> റെക്കോർഡുചെയ്യുന്നു."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> പ്രോഗ്രാമിന്റെ ചില ഭാഗങ്ങൾ റെക്കോർഡുചെയ്യപ്പെടില്ല."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> എന്നീ പ്രോഗ്രാമുകളുടെ ചില ഭാഗങ്ങൾ റെക്കോർഡുചെയ്യപ്പെടില്ല."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> എന്നീ പ്രോഗ്രാമുകളുടെ ചില ഭാഗങ്ങളും ഒരു ഷെഡ്യൂളും റെക്കോർഡുചെയ്യപ്പെടില്ല."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> എന്നീ പ്രോഗ്രാമുകളുടെ ചില ഭാഗങ്ങളും %3$d ഷെഡ്യൂളുകളും റെക്കോർഡുചെയ്യപ്പെടില്ല.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> എന്നീ പ്രോഗ്രാമുകളുടെ ചില ഭാഗങ്ങളും %3$d ഷെഡ്യൂളും റെക്കോർഡുചെയ്യപ്പെടില്ല.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"എന്താണ് റെക്കോർഡുചെയ്യേണ്ടത്?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"എത്ര സമയം റെക്കോർഡ് ചെയ്യാനാണ് നിങ്ങൾ ആഗ്രഹിക്കുന്നത്?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ഇതിനകം തന്നെ ഷെഡ്യൂൾ ചെയ്തിട്ടുണ്ട്"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"ഇതേ പ്രോഗ്രാം <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>-ന് റെക്കോർഡ് ചെയ്യുന്നതിനായി ഇതിനകം തന്നെ ഷെഡ്യൂൾ ചെയ്തിട്ടുണ്ട്."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ഇതിനകം തന്നെ റെക്കോർഡ് ചെയ്തു"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ഈ പ്രോഗ്രാം ഇതിനകം തന്നെ റെക്കോർഡ് ചെയ്തിട്ടുണ്ട്. DVR ലൈഒബ്രറിയിൽ ഇത് ലഭ്യമാണ്."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"റെക്കോർഡുചെയ്ത പ്രോഗ്രാം കണ്ടെത്തിയില്ല."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ബന്ധപ്പെട്ട റെക്കോർഡിംഗുകൾ"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(പ്രോഗ്രാം വിവരണമില്ല)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d റെക്കോർഡിംഗുകൾ</item>
+ <item quantity="one">%1$d റെക്കോർഡിംഗ്</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"റെക്കോർഡിംഗ് ഷെഡ്യൂളിൽ നിന്ന് <xliff:g id="PROGRAMNAME">%1$s</xliff:g> നീക്കംചെയ്തു"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ട്യൂണർ പൊരുത്തക്കേടുള്ളതിനാൽ ഭാഗികമായി റെക്കോർഡ് ചെയ്യും."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ട്യൂണർ പൊരുത്തക്കേടുള്ളതിനാൽ റെക്കോർഡ് ചെയ്യില്ല."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ഷെഡ്യൂളിൽ ഇതുവരെയും റെക്കോർഡിംഗുകളൊന്നും ഇല്ല.\nപ്രോഗ്രാം ഗൈഡിൽ നിന്ന് നിങ്ങൾക്ക് റെക്കോർഡിംഗ് ഷെഡ്യൂൾ ചെയ്യാവുന്നതാണ്."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d റെക്കോർഡിംഗ് പൊരുത്തക്കേടുകൾ</item>
+ <item quantity="one">%1$d റെക്കോർഡിംഗ് പൊരുത്തക്കേട്</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"സീരീസ് ക്രമീകരണം"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"സീരീസ് റെക്കോർഡുചെയ്യുന്നത് ആരംഭിക്കുക"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"സീരീസ് റെക്കോർഡുചെയ്യുന്നത് നിർത്തുക"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"സീരീസ് റെക്കോർഡുചെയ്യുന്നത് നിർത്തണോ?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"റെക്കോർഡുചെയ്ത എപ്പിസോഡുകൾ DVR ലൈബ്രറിയിൽ ലഭ്യമാകുന്നത് തുടരും."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"നിർത്തുക"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"എപ്പിസോഡുകളൊന്നും ലഭ്യമല്ല.\nലഭ്യമായിക്കഴിഞ്ഞാൽ അവ റെക്കോർഡ് ചെയ്യപ്പെടും."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d മിനിറ്റ്)</item>
+ <item quantity="one">(%1$d മിനിറ്റ്) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ഇന്ന്"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"നാളെ"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ഇന്നലെ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ഇന്ന്"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> നാളെ"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"സ്കോർ"</string>
</resources>
diff --git a/res/values-mn-rMN/arrays.xml b/res/values-mn-rMN/arrays.xml
index 952ee618..3d0b16ba 100644
--- a/res/values-mn-rMN/arrays.xml
+++ b/res/values-mn-rMN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Дүүрэн"</item>
<item msgid="8568284598210500589">"Томруулах"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Бүх суваг"</item>
- <item msgid="6897460857821394118">"Гэр бүл/Хүүхдүүд"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Худалдаа"</item>
- <item msgid="3296058637230163031">"Кино"</item>
- <item msgid="1054540282883891201">"Инээдмийн"</item>
- <item msgid="7900158429062595471">"Аялал"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Боловсрол"</item>
- <item msgid="7396447839483867269">"Амьтад/Зэрлэг байгаль"</item>
- <item msgid="4738043455148062673">"Мэдээ"</item>
- <item msgid="7405041316051047427">"Тоглоом"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Бүх суваг"</item>
- <item msgid="7909003973960375395">"Гэр бүл/Хүүхдүүд"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Дэлгүүр"</item>
- <item msgid="6083795019290250078">"Кино"</item>
- <item msgid="8302638329222449550">"Инээдмийн"</item>
- <item msgid="3803709976021475052">"Аялал"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Боловсрол"</item>
- <item msgid="7511135485827589547">"Амьтад/Зэрлэг байгаль"</item>
- <item msgid="6961248112238009967">"Мэдээ"</item>
- <item msgid="6484685553679698447">"Тоглоом"</item>
- <item msgid="2737158328243183190">"Урлаг"</item>
- <item msgid="6577176952650166615">"Энтертэйнмент"</item>
- <item msgid="7886693831871777617">"Амьдралын хэв маяг"</item>
- <item msgid="8145832312485577062">"Дуу хөгжим"</item>
- <item msgid="1345789204804308580">"Эхний"</item>
- <item msgid="2736680312770771994">"Технологи/шинжлэх ухаан"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Бүх суваг"</item>
+ <item msgid="928298872841713530">"Гэр бүл/Хүүхдүүд"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Худалдаа"</item>
+ <item msgid="167201149441442173">"Кино"</item>
+ <item msgid="525966731464264290">"Инээдмийн"</item>
+ <item msgid="6096710741527327836">"Аялал"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Боловсрол"</item>
+ <item msgid="7221999662426308394">"Амьтад/Зэрлэг байгаль"</item>
+ <item msgid="375300513250925001">"Мэдээ"</item>
+ <item msgid="7746320336582330410">"Тоглоом"</item>
+ <item msgid="1255741860568329178">"Урлаг"</item>
+ <item msgid="7603949681065702867">"Цэнгээн"</item>
+ <item msgid="4453821994746804366">"Амьдралын хэв маяг"</item>
+ <item msgid="3488534597567932843">"Дуу хөгжим"</item>
+ <item msgid="7452153120614274095">"Эхний"</item>
+ <item msgid="8215762047341133299">"Технологи/ШУ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Шууд суваг"</item>
diff --git a/res/values-mn-rMN/rating_system_strings.xml b/res/values-mn-rMN/rating_system_strings.xml
index fc17077e..7c883a13 100644
--- a/res/values-mn-rMN/rating_system_strings.xml
+++ b/res/values-mn-rMN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-mn-rMN/strings.xml b/res/values-mn-rMN/strings.xml
index 5fd5b644..e99f8a0e 100644
--- a/res/values-mn-rMN/strings.xml
+++ b/res/values-mn-rMN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Өмнөх"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Хөтөлбөр"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Шинэ суваг нээлттэй байна"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Холбоос байхгүй байна"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нээх"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Хаалттай капшн"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Дэлгэцийн горим"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Дэд-үнэлгээ"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Энэ сувгийг үзэхийн тулд PIN оруулна уу"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Энэ хөтөлбөрийг үзэхийн тулд PIN оруулна уу"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Энэ хөтөлбөр нь <xliff:g id="RATING">%1$s</xliff:g> үнэлгээтэй байна. Энэ хөтөлбөрийг үзэхийн тулд ПИН-ээ оруулна уу."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Өөрийн PIN оруулна уу"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Эцэг эхийн хяналт тохируулахын тулд PIN үүсгээрэй"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Шинэ PIN оруулна уу"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Нээлттэй эхийн лиценз"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Нээлттэй эхийн лиценз"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Хувилбар"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Шууд сувгийг сайжруулахад туслах"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Та хэрэглээ, оношлогооны мэдээг Google-д автоматаар хуваалцсанаар бид шууд сувгийг гэмтэх, зогсохоос сэргийлж, сайжруулах болно."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Энэ сувгийг үзэхийн тулд Баруун товчийг дараад өөрийн PIN-г оруулна уу"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Энэ хөтөлбөрийг үзэхийн тулд Баруун товчийг дараад өөрийн PIN-г оруулна уу"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Энэ хөтөлбөр <xliff:g id="RATING">%1$s</xliff:g> үнэлгээтэй байна.\nэнэ хөтөлбөрийг үзэхийн тулд Баруун товчийг дараад өөрийн PIN-г оруулна уу."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Зөвхөн аудио"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Дохио муу"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Интернэт холболт байхгүй"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Бусад сувгийг бичиж байгаа тул энэ сувгийг <xliff:g id="END_TIME_1">%1$s</xliff:g> хүртэл тоглуулах боломжгүй. \n\nБичих хуваарийг тохируулахын тулд Баруун товчлуурыг дарна уу.</item>
+ <item quantity="one">Өөр сувгийг бичиж байгаа тул энэ сувгийг <xliff:g id="END_TIME_0">%1$s</xliff:g> хүртэл тоглуулах боломжгүй. \n\nБичих хуваарийг тохируулахын тулд Баруун товчлуурыг дарна уу.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Гарчиггүй"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Сувгийг хориглосон"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Шинэ"</string>
@@ -168,12 +170,12 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ямар ч суваг байхгүй байна"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Шинэ"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Тохируулаагүй"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Бусад сурвалж авах"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Шууд сувгийн апп хайх"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Бусад сурвалж авах"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Шууд сувгийн апп хайх"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Шинэ сувгийн эх сурвалж боломжтой байна"</string>
<string name="new_sources_description" msgid="749649005588426813">"Шинэ сувгийн эх сурвалжууд суваг санал болгож байна.\nТа эдгээрийг эх сурвалжийн тохиргоо хэсэгт одоо эсвэл дараа нь тохируулаарай."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Одоо тохируулах"</string>
- <string name="new_sources_action_skip" msgid="2501296961258184330">"Тийм, ойлголоо"</string>
+ <string name="new_sources_action_skip" msgid="2501296961258184330">"За, ойлголоо"</string>
<!-- no translation found for intro_title (251772896916795556) -->
<skip />
<string name="intro_description" msgid="7806473686446937307">"ТВ цэс рүү хандахын тулд "<b>"СОНГОХ гэснийг дарна уу"</b></string>
@@ -187,8 +189,160 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Бүх эх сурвалж сувгуудыг нууцалсан.\nҮзэхийн тулд дор хаяж нэг суваг сонгоно уу."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Энэ видеог үзэх боломжгүй болсон."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Буцах товчийг холбогдсон төхөөрөмжүүдэд ашиглана. Гарахын тулд Нүүр товчийг дарна уу."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop-той төхөөрөмжид шууд сувгийг дэмжихгүй."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Шууд сувагт TВ-н жагсаалтыг унших зөвшөөрөл шаардлагатай."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Эх сурвалжаа тохируулах"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Шууд суваг нь апп-с хангадаг TV-н уламжлалт урсгал сувгийн хэрэглээтэй хосолдог. \n\nЭхлүүлэхийн тулд өмнө нь суулгасан сувгийн эх сурвалжийг тохируулаарай. Эсвэл Google Play Store-с шууд суваг дамжуулдаг бусад апп-г хайгаарай."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Бичлэг, хуваарь"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 минут"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 минут"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 цаг"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 цаг"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Сүүлийн"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Хуваарилсан"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Цуврал"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Бусад"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Сувгийг бичих боломжгүй."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Хөтөлбөрийг бичих боломжгүй."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>-г бичихээр товлосон"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>-г одооноос <xliff:g id="ENDTIME">%2$s</xliff:g> хүртэл бичиж байна"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Бүтэн цагийн хуваарь"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Дараагийн %1$d хоног</item>
+ <item quantity="one">Дараагийн %1$d хоног</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d минут</item>
+ <item quantity="one">%1$d минут</item>
+ </plurals>
+ <!-- String.format failed for translation -->
+ <!-- no translation found for dvr_count_new_recordings (3569310208305402815) -->
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d бичлэг</item>
+ <item quantity="one">%1$d бичлэг</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d бичлэгийг товлосон</item>
+ <item quantity="one">%1$d бичлэгийг товлосон</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Үзэх"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Эхнээс нь тоглуулах"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Үргэлжлүүлэн тоглуулах"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Устгах"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Бичлэгийг устгах"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Үргэлжлүүлэх"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-р цуврал"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Хуваарь харах"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Дэлгэрэнгүй унших"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Бичлэгийг устгах"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Устгах ангийг сонгоно уу. Устгасан тохиолдолд дахин сэргээх боломжгүй."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Устгах ямар ч бичлэг алга."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Үзсэн ангийг сонгох"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Бүх ангийг сонгох"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Бүх ангийн сонголтыг цуцлах"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g>-с <xliff:g id="WATCHED">%1$d</xliff:g> минут үзсэн"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g>-с <xliff:g id="WATCHED">%1$d</xliff:g> секунд үзсэн"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Огт үзээгүй"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d-ийн %1$d ангийг устгасан</item>
+ <item quantity="one">%2$d-ийн %1$d ангийг устгасан</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Ач холбогдол"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Хамгийн өндөр"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Хамгийн бага"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Үгүй. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Суваг"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Дурын"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Ач холбогдол сонгох"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Олон хөтөлбөрийг зэрэг бичихээр сонгосон тохиолдолд зөвхөн өндөр ач холбогдолтой хөтөлбөрийг бичнэ."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Хадгалах"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Нэг удаагийн бичлэг өндөр ач холбогдолтой"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Цуцлах"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Цуцлах"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Мартах"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Зогсоох"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Бичих хуваарийг харах"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Зөвхөн энэ хөтөлбөр"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"одоо - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Бүтэн цуврал..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Ямартай ч товлох"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Оронд нь үүнийг бичих"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Энэ бичлэгийг цуцлах"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Одоо үзэх"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Дүрс бичих боломжтой"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Дүрс бичихээр товлосон"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Дүрс бичих боломжгүй"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Бичиж байна"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Бичиж чадсангүй"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Бичлэгийн хуваарь үүсгэхийн тулд хөтөлбөрийг уншиж байна"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Хөтөлбөрийг уншиж байна"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR-д илүү багтаамж шаардлагатай"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Та DVR-р хөтөлбөр бичих боломжтой болно. Гэсэн хэдий ч таны төхөөрөмжид DVR ажиллуулах хангалттай багтаамж алга. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>гигабайт, эсвэл үүнээс дээш багтаамжтай гадаад драйв холбож, үүнийг төхөөрөмжийн сан болгож хэлбэршүүлэхийн тулд зааврыг дагана уу."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Сан алга"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR-н ашигласан зарим сан алга. DVR-г дахин идэвхжүүлэхээс өмнө ашигласан гадаад драйвыг холбоно уу. Хэрэв сан байхгүй бол үүнийг мартах боломжтой."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Санг мартах уу?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Таны бичсэн агуулга, хуваарь устах болно."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Бичлэгийг зогсоох уу?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Бичсэн агуулгыг хадгална."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Бичихээр товлосон ч зөрчилтэй байна"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Бичлэг эхлүүлсэн хэдий ч зөрчилтэй байна"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>-г бичих болно."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g>-г бичиж байна."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>-н зарим хэсгийг бичихгүй."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> болон <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>-н зарим хэсгийг бичихгүй."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> -н зарим хэсэг болон өөр нэг хуваарийг бичихгүй."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>-н зарим хэсэг болон %3$d бусад хуваарийг бичихгүй.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>-н зарим хэсэг болон %3$d бусад хуваарийг бичихгүй.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Та юу бичих вэ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Та хэр удаан бичих вэ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Аль хэдийн товлосон"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Үүнтэй ижил хөтөлбөрийг <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>-д бичихээр товлосон байна."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Аль хэдийн бичсэн"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Энэ хөтөлбөрийг аль хэдийн бичсэн байна. Энэ нь DVR санд боломжтой."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Бичсэн хөтөлбөр олдсонгүй."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Холбоотой бичлэг"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Хөтөлбөрийн тодорхойлолт алга)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d бичлэг</item>
+ <item quantity="one">%1$d бичлэг</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>-г бичих хуваариас хассан"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Тааруулагчийн алдааны улмаас хэсэгчлэн бичих болно."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Тааруулагч алдаатай тул бичихгүй."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Одоогоор хуваарьт бичлэг байхгүй байна.\nТа ТВ хөтөлбөрөөс бичлэг товлох боломжтой."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d бичлэгийн зөрчил</item>
+ <item quantity="one">%1$d бичлэгийн зөрчил</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Цувралын тохиргоо"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Цувралыг бичиж эхлэх"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Цувралыг бичихээ зогсоох"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Цувралыг бичихээ зогсоох уу?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Бичсэн цувралыг DVR санд хадгална."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Зогсоох"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Ямар ч анги алга.\nТэд боломжтой болсон үедээ бичих болно."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d минут)</item>
+ <item quantity="one">(%1$d минут) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Өнөөдөр"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Маргааш"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Өчигдөр"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"өнөөдрийн <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Маргаашийн <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Оноо"</string>
</resources>
diff --git a/res/values-mr-rIN/arrays.xml b/res/values-mr-rIN/arrays.xml
index 4272a4c2..a91434f4 100644
--- a/res/values-mr-rIN/arrays.xml
+++ b/res/values-mr-rIN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"पूर्ण"</item>
<item msgid="8568284598210500589">"झूम करा"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"सर्व चॅनेल"</item>
- <item msgid="6897460857821394118">"कुटुंब/मुले"</item>
- <item msgid="551257741825778215">"क्रिडा"</item>
- <item msgid="452133796804325879">"खरेदी"</item>
- <item msgid="3296058637230163031">"चित्रपट"</item>
- <item msgid="1054540282883891201">"विनोदी"</item>
- <item msgid="7900158429062595471">"प्रवास"</item>
- <item msgid="3768998587825611787">"नाटक"</item>
- <item msgid="8340620094959282881">"शिक्षण"</item>
- <item msgid="7396447839483867269">"प्राणी/वन्यजीवन"</item>
- <item msgid="4738043455148062673">"बातम्या"</item>
- <item msgid="7405041316051047427">"गेमिंग"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"सर्व चॅनेल"</item>
- <item msgid="7909003973960375395">"कुटुंब/मुले"</item>
- <item msgid="3185279732911635789">"क्रिडा"</item>
- <item msgid="4704858492065325964">"खरेदी"</item>
- <item msgid="6083795019290250078">"चित्रपट"</item>
- <item msgid="8302638329222449550">"विनोदी"</item>
- <item msgid="3803709976021475052">"प्रवास"</item>
- <item msgid="8116747365234169059">"नाटक"</item>
- <item msgid="7356447541595315913">"शिक्षण"</item>
- <item msgid="7511135485827589547">"प्राणी/वन्यजीवन"</item>
- <item msgid="6961248112238009967">"बातम्या"</item>
- <item msgid="6484685553679698447">"गेमिंग"</item>
- <item msgid="2737158328243183190">"कला"</item>
- <item msgid="6577176952650166615">"मनोरंजन"</item>
- <item msgid="7886693831871777617">"जीवनशैली"</item>
- <item msgid="8145832312485577062">"संगीत"</item>
- <item msgid="1345789204804308580">"प्रमुख"</item>
- <item msgid="2736680312770771994">"तंत्रज्ञान/विज्ञान"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"सर्व चॅनेल"</item>
+ <item msgid="928298872841713530">"कुटुंब/मुले"</item>
+ <item msgid="2751606947569857164">"क्रीडा"</item>
+ <item msgid="7345749789651321496">"खरेदी"</item>
+ <item msgid="167201149441442173">"चित्रपट"</item>
+ <item msgid="525966731464264290">"विनोदी"</item>
+ <item msgid="6096710741527327836">"प्रवास"</item>
+ <item msgid="2851882187117833883">"नाटक"</item>
+ <item msgid="78492781188719038">"शिक्षण"</item>
+ <item msgid="7221999662426308394">"प्राणी/वन्यजीवन"</item>
+ <item msgid="375300513250925001">"बातम्या"</item>
+ <item msgid="7746320336582330410">"गेमिंग"</item>
+ <item msgid="1255741860568329178">"कला"</item>
+ <item msgid="7603949681065702867">"मनोरंजन"</item>
+ <item msgid="4453821994746804366">"जीवनशैली"</item>
+ <item msgid="3488534597567932843">"संगीत"</item>
+ <item msgid="7452153120614274095">"प्रमुख"</item>
+ <item msgid="8215762047341133299">"तंत्रज्ञान/विज्ञान"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"थेट चॅनेल"</item>
diff --git a/res/values-mr-rIN/rating_system_strings.xml b/res/values-mr-rIN/rating_system_strings.xml
index 14b98174..d192c799 100644
--- a/res/values-mr-rIN/rating_system_strings.xml
+++ b/res/values-mr-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-mr-rIN/strings.xml b/res/values-mr-rIN/strings.xml
index 2ddbeec9..1888e9de 100644
--- a/res/values-mr-rIN/strings.xml
+++ b/res/values-mr-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"मागील"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"कार्यक्रम मार्गदर्शक"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"उपलब्ध नवीन चॅनेल"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"दुवा उपलब्ध नाही"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> उघडा"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"उपशीर्षक"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"प्रदर्शन मोड"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"उप रेटिंग"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"हे चॅनेल पाहण्‍यासाठी आपला पिन प्रविष्‍ट करा"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"हा कार्यक्रम पाहण्‍यासाठी आपला पिन प्रविष्‍ट करा"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"हा प्रोग्राम <xliff:g id="RATING">%1$s</xliff:g> रेट केलेला आहे. हा प्रोग्राम पाहण्यासाठी आपला PIN प्रविष्ट करा"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"आपला पिन प्रविष्‍ट करा"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"पालक नियंत्रणे सेट करण्यासाठी, एक पिन तयार करा"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"नवीन पिन प्रविष्ट करा"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"मुक्त स्त्रोत परवाने"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"मुक्त स्त्रोत परवाने"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"आवृत्ती"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"थेट चॅनेल सुधारण्यात मदत करा"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google सह अनामित वापर आणि निदान डेटा सामायिक करा जेणेकरून आम्‍ही थेट चॅनेल आणखी चांगले बनवू शकू आणि क्रॅश होणे आणि गोठविणे यासारख्‍या समस्या प्रतिबंधित करू शकू."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"हे चॅनेल पाहण्यासाठी, उजवे दाबा आणि आपला पिन प्रविष्‍ट करा"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"हा कार्यक्रम पाहण्‍यासाठी, उजवे दाबा आणि आपला पिन प्रविष्‍ट करा"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"हा कार्यक्रम <xliff:g id="RATING">%1$s</xliff:g> रेट केला आहे.\n हा कार्यक्रम पाहण्‍यासाठी, उजवे दाबा आणि आपला पिन प्रविष्‍ट करा."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"फक्त ऑडिओ"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"खराब सिग्नल"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"कोणतेही इंटरनेट कनेक्शन नाही"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">दुसरे चॅनेल रेकॉर्ड केले जात असल्याने <xliff:g id="END_TIME_1">%1$s</xliff:g> पर्यंत हे चॅनेल प्ले केले जाऊ शकत नाही. \n\nरेकॉर्डिंग अनुसूची समायोजित करण्यासाठी उजवीकडे दाबा.</item>
+ <item quantity="other">दुसरे चॅनेल रेकॉर्ड केले जात असल्याने <xliff:g id="END_TIME_1">%1$s</xliff:g> पर्यंत हे चॅनेल प्ले केले जाऊ शकत नाही. \n\nरेकॉर्डिंग अनुसूची समायोजित करण्यासाठी उजवीकडे दाबा.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"शीर्षक नाही"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"चॅनेल अवरोधित केले"</string>
<string name="setup_category_new" msgid="2899355289563443627">"नवीन"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"कोणतेही चॅनेल उपलब्ध नाही"</string>
<string name="setup_input_new" msgid="3337725672277046798">"नवीन"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"सेट केलेले नाही"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"अधिक स्रोत मिळवा"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"थेट चॅनेल प्रदान करणारे अॅप्स ब्राउझ करा"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"अधिक स्रोत मिळवा"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"थेट चॅनेल प्रदान करणारे अॅप्स ब्राउझ करा"</string>
<string name="new_sources_title" msgid="3878933676500061895">"नवीन चॅनेल स्रोत उपलब्ध आहेत"</string>
<string name="new_sources_description" msgid="749649005588426813">"प्रदान करण्‍यासाठी नवीन चॅनेल स्रोतांमध्‍ये चॅनेल आहेत. \n आता ते सेट करा किंवा चॅनेल स्रोत सेटिंगमध्ये हे नंतर करा."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"आता सेट करा"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"सर्व स्त्रोत चॅनेल लपविले आहेत.\nपाहण्‍यासाठी कमीतकमी एक चॅनेल निवडा."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"व्‍हिडिओ अनपेक्षितपणे अनुपलब्ध आहे"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"बॅक की कनेक्ट केलेल्या डिव्हाइससाठी आहे. बाहेर पडण्यासाठी मुख्यपृष्ठ बटण दाबा."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop सह थेट चॅनेल या डिव्हाइसवर समर्थित नाहीत."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"थेट चॅनेलना टीव्ही सूचींचे वाचन करण्यासाठी परवानगीची आवश्यकता आहे."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"आपले स्रोत सेट करा"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"थेट चॅनेल पारंपारिक TV चॅनेलच्या अनुभवास अॅप्सने प्रदान केलेल्या प्रवाहित केलेल्या चॅनेलसह एकत्रित करतात. \n\nआधीपासून स्थापित केलेले चॅनेल स्रोत सेट करून प्रारंभ करा किंवा थेट चॅनेल प्रदान करणार्‍या आणखी अॅप्ससाठी Google Play स्टोअर ब्राउझ करा."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"रेकॉर्डिंग आणि अनुसूची"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 मिनिटे"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 मिनिटे"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 तास"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 तास"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"अलीकडील"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"अनुसूचित"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"मालिका"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"इतर"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"चॅनेल रेकॉर्ड केले जाऊ शकत नाही."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"प्रोग्राम रेकॉर्ड केला जाऊ शकतो."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"रेकॉर्ड करण्‍यासाठी <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ची अनुसूची केली गेली"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> चे रेकॉर्डिंग आतापासून <xliff:g id="ENDTIME">%2$s</xliff:g> पर्यंत"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"पूर्ण अनुसूची"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">पुढील %1$d दिवस</item>
+ <item quantity="other">पुढील %1$d दिवस</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d मिनिट</item>
+ <item quantity="other">%1$d मिनिटे</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d नवीन रेकॉर्डिंग</item>
+ <item quantity="other">%1$d नवीन रेकॉर्डिंग</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d रेकॉर्डिंग</item>
+ <item quantity="other">%1$d रेकॉर्डिंग</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d रेकॉर्डिंगची अनुसूची केली</item>
+ <item quantity="other">%1$d रेकॉर्डिंगची अनुसूची केली</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"पहा"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"सुरूवातीपासून प्ले करा"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"प्ले करणे पुनः सुरु करा"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"हटवा"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"रेकॉर्डिंग हटवा"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"पुनः सुरु करा"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"हंगाम <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"अनुसूची पहा"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"आणखी वाचा"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"रेकॉर्डिंग हटवा"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"आपण हटवू इच्छिता ते भाग निवडा. एकदा हटविले की ते पुनर्प्राप्त केले जाऊ शकत नाहीत."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"हटविण्यासाठी कोणतेही रेकॉर्डिंग नाहीत."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"पाहिलेले भाग निवडा"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"सर्व भाग निवडा"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"सर्व भागांची निवड रद्द करा"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> पैकी <xliff:g id="WATCHED">%1$d</xliff:g> मिनिटांची रेकॉर्डिंग पाहिली"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> पैकी <xliff:g id="WATCHED">%1$d</xliff:g> सेकंदांची रेकॉर्डिंग पाहिली"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"कधीही पाहिली नाहीत"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%2$d पैकी %1$d भाग हटविला आहे</item>
+ <item quantity="other">%2$d पैकी %1$d भाग हटविले आहेत</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"प्राधान्य"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"सर्वोच्च"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"सर्वात निम्न"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"<xliff:g id="RANK">%1$d</xliff:g> क्र."</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"चॅनेल"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"कोणतेही"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"प्राधान्य निवडा"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"एकाच वेळी रेकॉर्ड करण्यासाठी खूप जास्त प्रोग्राम असतात तेव्हा, केवळ अधिक प्राधान्ये असलेले प्रोग्राम रेकॉर्ड केले जातील."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"जतन करा"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"एक-वेळ रेकॉर्डिंगला सर्वोच्च प्राधान्य आहे"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"रद्द करा"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"रद्द करा"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"विसरा"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"थांबा"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"रेकॉर्डिंग अनुसूची पहा"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"हा एक कार्यक्रम"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"आता - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"संपूर्ण मालिका…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"तरीही शेड्यूल करा"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"त्याऐवजी हे रेकॉर्ड करा"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"हे रेकॉर्डिंग रद्द करा"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"आता पहा"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"रेकॉर्ड करण्यायोग्य"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"रेकॉर्डिंग अनुसूचित केले"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"रेकॉर्डिंग संबंधी विरोध"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"रेकॉर्डिंग"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"रेकॉर्डिंग अयशस्वी झाले"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"रेकॉर्डिंग अनुसूची तयार करण्यासाठी प्रोग्राम वाचत आहे"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"वाचन कार्यक्रम"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR साठी आणखी संचय आवश्यक आहे"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"आपण DVR ने प्रोग्राम रेकॉर्ड करण्यात सक्षम असाल. तथापि DVR ने कार्य करण्यासाठी आपल्या डिव्हाइसवर आता पुरेसा संचय नाही. कृपया <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB किंवा त्यापेक्षा मोठ्या बाह्य ड्राइव्हशी कनेक्ट करा आणि त्यास डिव्हाइस संचय म्हणून स्वरूपित करण्‍यासाठी चरणांचे अनुसरण करा."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"संचय गहाळ आहे"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR ने वापरलेला काही संचय गहाळ आहे. कृपया DVR पुन्हा सक्षम करण्‍यासाठी आपण पूर्वी वापरलेला बाह्य ड्राइव्ह कनेक्ट करा. वैकल्पिकपणे, यापुढे संचय उपलब्ध नसल्यास आपण तो विसरणे निवडू शकता."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"संचय विसरलात?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"आपली सर्व रेकॉर्ड केलेली सामग्री आणि अनुसूची गमावल्या जातील."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"रेकॉर्डिंग थांबवायचे?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"रेकॉर्ड केलेली सामग्री जतन केली जाईल."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"रेकॉर्डिंगची अनुसूची केली परंतु त्यासंबंधी विरोध आहेत"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"रेकॉर्डिंग सुरू झाली परंतु त्यासंबंधी विरोध आहेत"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> रेकॉर्ड केला जाईल."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> रेकॉर्ड केला जात आहे."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> चे काही भाग रेकॉर्ड केले जाणार नाहीत."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> आणि <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> चे काही भाग रेकॉर्ड केले जाणार नाहीत."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> चे काही भाग आणि आणखी एक अनुसूची रेकॉर्ड केली जाणार नाही."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> आणि आणखी %3$d अनुसूची रेकॉर्ड केली जाणार नाही.</item>
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> आणि आणखी %3$d अनुसूची रेकॉर्ड केली जाणार नाही.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"आपल्याला काय रेकॉर्ड करायला आवडेल?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"आपल्याला किती वेळ रेकॉर्ड करायला आवडेल?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"आधीच शेड्यूल केला आहे"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> रोजी रेकॉर्ड करण्यासाठी तोच कार्यक्रम आधीच शेड्यूल केला आहे."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"आधीच रेकॉर्ड केला आहे"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"हा कार्यक्रम आधीच रेकॉर्ड केला गेला आहे. तो DVR लायब्ररीमध्ये उपलब्ध आहे."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"रेकॉर्ड केलेला प्रोग्राम सापडला नाही."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"संबंधित रेकॉर्डिंग"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(कोणत्याही प्रोग्रामचे वर्णन नाही)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d रेकॉर्डिंग</item>
+ <item quantity="other">%1$d रेकॉर्डिंग</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> रेकॉर्डिंग अनुसूची मधून काढला"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ट्यूनर विरोधामुळे अंशतः रेकॉर्ड केले जाईल."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ट्यूनर विरोधामुळे रेकॉर्ड केले जाणार नाही."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"अद्याप कोणतेही रेकॉर्डिंग शेड्यूल केलेले नाही\nआपण कार्यक्रम मार्गदर्शकामधून रेकॉर्डिंग शेड्यूल करू शकता."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d रेकॉर्डिंग संबंधी विरोध</item>
+ <item quantity="other">%1$d रेकॉर्डिंग संबंधी विरोध</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"मालिका सेटिंग्ज"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"मालिका रेकॉर्ड करणे प्रारंभ करा"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"मालिका रेकॉर्ड करणे थांबवा"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"मालिका रेकॉर्ड करणे थांबवायचे?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"रेकॉर्ड केलेले भाग DVR लायब्ररी मध्ये उपलब्ध राहतील."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"थांबा"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"कोणतेही भाग उपलब्ध नाहीत.\nते उपलब्ध झाल्यावर रेकॉर्ड केले जातील."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d मिनिट)</item>
+ <item quantity="other">(%1$d मिनिटे)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"आज"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"उद्या"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"काल"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"आज <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"उद्या <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"गुणसंख्‍या"</string>
</resources>
diff --git a/res/values-ms-rMY/arrays.xml b/res/values-ms-rMY/arrays.xml
index 9d285575..16ccce64 100644
--- a/res/values-ms-rMY/arrays.xml
+++ b/res/values-ms-rMY/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Penuh"</item>
<item msgid="8568284598210500589">"Zum"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Semua saluran"</item>
- <item msgid="6897460857821394118">"Keluarga/Kanak-Kanak"</item>
- <item msgid="551257741825778215">"Sukan"</item>
- <item msgid="452133796804325879">"Beli-belah"</item>
- <item msgid="3296058637230163031">"Filem"</item>
- <item msgid="1054540282883891201">"Komedi"</item>
- <item msgid="7900158429062595471">"Pelancongan"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Pendidikan"</item>
- <item msgid="7396447839483867269">"Haiwan/Hidupan Liar"</item>
- <item msgid="4738043455148062673">"Berita"</item>
- <item msgid="7405041316051047427">"Permainan"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Semua saluran"</item>
- <item msgid="7909003973960375395">"Keluarga/Kanak-Kanak"</item>
- <item msgid="3185279732911635789">"Sukan"</item>
- <item msgid="4704858492065325964">"Beli-belah"</item>
- <item msgid="6083795019290250078">"Filem"</item>
- <item msgid="8302638329222449550">"Komedi"</item>
- <item msgid="3803709976021475052">"Pelancongan"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Pendidikan"</item>
- <item msgid="7511135485827589547">"Haiwan/Hidupan Liar"</item>
- <item msgid="6961248112238009967">"Berita"</item>
- <item msgid="6484685553679698447">"Permainan"</item>
- <item msgid="2737158328243183190">"Seni"</item>
- <item msgid="6577176952650166615">"Hiburan"</item>
- <item msgid="7886693831871777617">"Gaya hidup"</item>
- <item msgid="8145832312485577062">"Muzik"</item>
- <item msgid="1345789204804308580">"Perdana"</item>
- <item msgid="2736680312770771994">"Teknikal/Sains"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Semua saluran"</item>
+ <item msgid="928298872841713530">"Keluarga/Kanak-Kanak"</item>
+ <item msgid="2751606947569857164">"Sukan"</item>
+ <item msgid="7345749789651321496">"Beli-belah"</item>
+ <item msgid="167201149441442173">"Filem"</item>
+ <item msgid="525966731464264290">"Komedi"</item>
+ <item msgid="6096710741527327836">"Pelancongan"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Pendidikan"</item>
+ <item msgid="7221999662426308394">"Haiwan/Hidupan Liar"</item>
+ <item msgid="375300513250925001">"Berita"</item>
+ <item msgid="7746320336582330410">"Permainan"</item>
+ <item msgid="1255741860568329178">"Seni"</item>
+ <item msgid="7603949681065702867">"Hiburan"</item>
+ <item msgid="4453821994746804366">"Gaya Hidup"</item>
+ <item msgid="3488534597567932843">"Muzik"</item>
+ <item msgid="7452153120614274095">"Perdana"</item>
+ <item msgid="8215762047341133299">"Teknikal/Sains"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Saluran Langsung"</item>
diff --git a/res/values-ms-rMY/rating_system_strings.xml b/res/values-ms-rMY/rating_system_strings.xml
index 92af90a3..a5f781fe 100644
--- a/res/values-ms-rMY/rating_system_strings.xml
+++ b/res/values-ms-rMY/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ms-rMY/strings.xml b/res/values-ms-rMY/strings.xml
index abcf09b1..816dee35 100644
--- a/res/values-ms-rMY/strings.xml
+++ b/res/values-ms-rMY/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Sebelumnya"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Panduan program"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Saluran baharu tersedia"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Pautan tidak tersedia"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Buka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Sari kata"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mod paparan"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subpenilaian"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Masukkan PIN anda untuk menonton saluran ini"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Masukkan PIN anda untuk menonton rancangan ini"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Rancangan ini diberi rating <xliff:g id="RATING">%1$s</xliff:g>. Masukkan PIN anda untuk menonton rancangan ini"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Masukkan PIN anda"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Untuk menetapkan kawalan ibu bapa, buat PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Masukkan PIN baharu"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Lesen sumber terbuka"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Lesen sumber terbuka"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versi"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Bantu meningkatkan Saluran Langsung"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Kongsi data penggunaan dan diagnostik awanama dengan Google supaya kami dapat menjadikan Saluran Langsung lebih baik dan menghalang isu seperti ranap dan pegun."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Untuk menonton saluran ini, tekan Kanan dan masukkan PIN anda"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Untuk menonton rancangan ini, tekan Kanan dan masukkan PIN anda"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Rancangan ini diberi rating <xliff:g id="RATING">%1$s</xliff:g>.\nUntuk menonton rancangan ini, tekan Kanan, kemudian masukkan PIN anda."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio sahaja"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Isyarat lemah"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Tiada sambungan Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Saluran ini tidak dapat dimainkan hingga <xliff:g id="END_TIME_1">%1$s</xliff:g> kerana saluran lain sedang dirakamkan. \n\nTekan Kanan untuk melaraskan jadual rakaman.</item>
+ <item quantity="one">Saluran ini tidak dapat dimainkan hingga <xliff:g id="END_TIME_0">%1$s</xliff:g> kerana saluran lain sedang dirakamkan. \n\nTekan Kanan untuk melaraskan jadual rakaman.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Tiada tajuk"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Saluran disekat"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Baharu"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Tiada saluran yang tersedia"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Baharu"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Tidak disediakan"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Dapatkan lebih banyak sumber"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Semak imbas apl yang menawarkan saluran langsung"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Dapatkan lebih banyak sumber"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Semak imbas apl yang menawarkan saluran langsung"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Sumber saluran yang baharu tersedia"</string>
<string name="new_sources_description" msgid="749649005588426813">"Sumber saluran baharu mempunyai saluran untuk ditawarkan.\nSediakan saluran sekarang atau lakukannya kemudian dalam tetapan sumber saluran."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Sediakan sekarang"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Semua saluran sumber disembunyikan.\nPilih sekurang-kurangnya satu saluran untuk ditonton."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video ini tidak tersedia tanpa dijangka"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Kekunci BACK adalah untuk peranti yang tersambung. Tekan butang HOME untuk keluar."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Saluran Langsung tidak disokong pada peranti ini dengan Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Saluran Langsung memerlukan kebenaran untuk membaca penyenaraian TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Sediakan sumber anda"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Saluran langsung menggabungkan pengalaman saluran TV tradisional dengan saluran penstriman yang disediakan oleh apl. \n\nMulakan dengan menyediakan sumber saluran yang sudah dipasang. Selain itu, semak imbas Gedung Google Play untuk mendapatkan lebih banyak apl yang menawarkan saluran langsung."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Rakaman &amp; jadual"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minit"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minit"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 jam"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 jam"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Terbaharu"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Dijadualkan"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Siri"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Lain-lain"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Saluran ini tidak boleh dirakam."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Rancangan ini tidak boleh dirakam."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> telah dijadualkan untuk dirakamkan"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Merakam <xliff:g id="PROGRAMNAME">%1$s</xliff:g> mulai sekarang hingga <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Jadual penuh"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d hari seterusnya</item>
+ <item quantity="one">%1$d hari seterusnya</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minit</item>
+ <item quantity="one">%1$d minit</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d rakaman baharu</item>
+ <item quantity="one">%1$d rakaman baharu</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d rakaman</item>
+ <item quantity="one">%1$d rakaman</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d rakaman dijadualkan</item>
+ <item quantity="one">%1$d rakaman dijadualkan</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Tonton"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Mainkan dari mula"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Sbg smula prses main"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Padam"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Padam rakaman"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Sambung semula"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Musim <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Lihat jadual"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Baca lagi"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Padam rakaman"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Pilih episod yang anda ingin padamkan. Episod ini tidak boleh dipulihkan setelah dipadamkan."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Tiada rakaman untuk dipadamkan."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Pilih episod yg sudah ditonton"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Pilih semua episod"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Nyahpilih semua episod"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> daripada <xliff:g id="DURATION">%2$d</xliff:g> minit tontonan"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> daripada <xliff:g id="DURATION">%2$d</xliff:g> saat tontonan"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Belum pernah ditonton"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d daripada %2$d episod dipadamkan</item>
+ <item quantity="one">%1$d daripada %2$d episod dipadamkan</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Keutamaan"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Tertinggi"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Terendah"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nombor <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Saluran"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Sebarang"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Pilih keutamaan"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Apabila ada terlalu banyak rancangan yang ingin dirakamkan secara serentak, rancangan yang berkeutamaan lebih tinggi sahaja yang akan dirakamkan."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Simpan"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Rakaman bersifat sekali sahaja mendapat keutamaan tertinggi"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Batal"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Batal"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Lupakan"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Berhenti"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Lihat jadual rakaman"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Program ini sahaja"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"sekarang - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Keseluruhan siri..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Jadualkan juga"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Sebaliknya rakamkan yang ini"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Batalkan rakaman ini"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Tonton sekarang"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Boleh rakam"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Rakaman dijadualkan"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflik rakaman"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Merakam"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Perakaman gagal"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Membaca rancangan untuk membuat jadual rakaman"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Membaca rancangan"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR memerlukan storan yang lebih besar"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Anda boleh merakam rancangan menggunakan DVR. Walau bagaimanapun storan pada peranti anda kini tidak mencukupi untuk DVR berfungsi. Sila sambungkan pemacu luaran <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB atau lebih besar dan ikut langkah untuk memformat pemacu itu sebagai storan peranti."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Storan hilang"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Beberapa storan yang digunakan oleh DVR telah hilang. Sila sambungkan pemacu luaran yang anda gunakan sebelum ini untuk mendayakan semula DVR. Secara alternatif, anda boleh memilih untuk melupakan storan jika storan itu tidak lagi tersedia."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Lupakan storan?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Semua kandungan dan jadual anda yang dirakamkan akan hilang."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Berhenti merakam?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Kandungan yang dirakamkan akan disimpan."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Rakaman dijadualkan tetapi wujud konflik"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Rakaman telah bermula tetapi wujud konflik"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> akan dirakamkan."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> sedang dirakamkan."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Sebahagian <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> tidak akan dirakamkan."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Sebahagian <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> dan <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> tidak akan dirakamkan."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Sebahagian <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> dan satu lagi jadual tidak akan dirakamkan."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Sebahagian <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> dan %3$d lagi jadual tidak akan dirakamkan.</item>
+ <item quantity="one">Sebahagian <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> dan %3$d lagi jadual tidak akan dirakamkan.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Apakah jenis rakaman yg anda ingin buat?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Berapa lama anda ingin merakam?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Sudah dijadualkan"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Rancangan yang sama telah dijadualkan akan dirakamkan pada <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Sudah dirakamkan"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Rancangan ini telah dirakamkan dan tersedia di pustaka DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Program yang dirakam tidak ditemui."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Rakaman yang berkaitan"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Tiada perihalan program)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d rakaman</item>
+ <item quantity="one">%1$d rakaman</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> dialih keluar daripada jadual rakaman"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Sebahagian sahaja yang akan dirakamkan kerana konflik penala."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Tidak akan dirakamkan kerana konflik penala."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Belum ada lagi rakaman yang dijadualkan.\nAnda boleh menjadualkan rakaman daripada panduan rancangan."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d konflik rakaman</item>
+ <item quantity="one">%1$d konflik rakaman</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Tetapan siri"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Mulakan rakaman siri"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Hentikan rakaman siri"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Berhenti merakam siri?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Episod yang dirakamkan akan kekal tersedia dalam pustaka DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Berhenti"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Tiada episod yang tersedia.\nEpisod ini akan dirakamkan apabila sudah tersedia."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minit)</item>
+ <item quantity="one">(%1$d minit) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hari ini"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Esok"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Semalam"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> hari ini"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> esok"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Markah"</string>
</resources>
diff --git a/res/values-my-rMM/arrays.xml b/res/values-my-rMM/arrays.xml
index 944e116a..e302ceac 100644
--- a/res/values-my-rMM/arrays.xml
+++ b/res/values-my-rMM/arrays.xml
@@ -20,41 +20,27 @@
<string-array name="display_mode_labels">
<item msgid="2259828487212953611">"ပုံမှန်"</item>
<item msgid="2533030282864800794">"အပြည့်"</item>
- <item msgid="8568284598210500589">"ချဲ့ချုံ့ရန်"</item>
+ <item msgid="8568284598210500589">"ဇူးမ်"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ချန်နယ်များအားလုံး"</item>
- <item msgid="6897460857821394118">"မိသားစု/ကလေးများ"</item>
- <item msgid="551257741825778215">"အားကစား"</item>
- <item msgid="452133796804325879">"​ဈေးဝယ်ခြင်း"</item>
- <item msgid="3296058637230163031">"ရုပ်ရှင်များ"</item>
- <item msgid="1054540282883891201">"ဟာသ"</item>
- <item msgid="7900158429062595471">"ခရီးသွားခြင်း"</item>
- <item msgid="3768998587825611787">"ဒရာမာ"</item>
- <item msgid="8340620094959282881">"ပညာရေး"</item>
- <item msgid="7396447839483867269">"တိရိစ္ဆာန်/တောရိုင်း"</item>
- <item msgid="4738043455148062673">"News"</item>
- <item msgid="7405041316051047427">"ဂိမ်းကစားခြင်း"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ချန်နယ်များအားလုံး"</item>
- <item msgid="7909003973960375395">"မိသားစု/ကလေးများ"</item>
- <item msgid="3185279732911635789">"အားကစား"</item>
- <item msgid="4704858492065325964">"​ဈေးဝယ်ခြင်း"</item>
- <item msgid="6083795019290250078">"ရုပ်ရှင်များ"</item>
- <item msgid="8302638329222449550">"ဟာသ"</item>
- <item msgid="3803709976021475052">"ခရီးသွားခြင်း"</item>
- <item msgid="8116747365234169059">"ဒရာမာ"</item>
- <item msgid="7356447541595315913">"ပညာရေး"</item>
- <item msgid="7511135485827589547">"တိရိစ္ဆာန်/တောရိုင်း"</item>
- <item msgid="6961248112238009967">"News"</item>
- <item msgid="6484685553679698447">"ဂိမ်းကစားခြင်း"</item>
- <item msgid="2737158328243183190">"အနုပညာများ"</item>
- <item msgid="6577176952650166615">"ဖျော်ဖြေမှု"</item>
- <item msgid="7886693831871777617">"လူနေမှုဘဝပုံစံ"</item>
- <item msgid="8145832312485577062">"သီချင်း"</item>
- <item msgid="1345789204804308580">"ပရီးမီးယား"</item>
- <item msgid="2736680312770771994">"စက်မှု/သိပ္ပံ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"ချာနယ်များ အားလုံး"</item>
+ <item msgid="928298872841713530">"မိသားစု/ကလေးများ"</item>
+ <item msgid="2751606947569857164">"အားကစား"</item>
+ <item msgid="7345749789651321496">"​ဈေးဝယ်ခြင်း"</item>
+ <item msgid="167201149441442173">"ရုပ်ရှင်များ"</item>
+ <item msgid="525966731464264290">"ဟာသ"</item>
+ <item msgid="6096710741527327836">"ခရီးလှည့်မှု"</item>
+ <item msgid="2851882187117833883">"ပြဇာတ်"</item>
+ <item msgid="78492781188719038">"ပညာရေး"</item>
+ <item msgid="7221999662426308394">"တိရိစ္ဆာန်/တောရိုင်း"</item>
+ <item msgid="375300513250925001">"သတင်း"</item>
+ <item msgid="7746320336582330410">"ဂိမ်းကစားခြင်း"</item>
+ <item msgid="1255741860568329178">"အနုပညာများ"</item>
+ <item msgid="7603949681065702867">"ဖြေဖျော်မှု"</item>
+ <item msgid="4453821994746804366">"ဘဝပုံစံ"</item>
+ <item msgid="3488534597567932843">"ဂီတ"</item>
+ <item msgid="7452153120614274095">"ပွဲဦး"</item>
+ <item msgid="8215762047341133299">"စက်မှု/သိပ္ပံ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"တိုက်ရိုက်လွှင့် ချန်နယ်များ"</item>
diff --git a/res/values-my-rMM/rating_system_strings.xml b/res/values-my-rMM/rating_system_strings.xml
index b2206835..153ad407 100644
--- a/res/values-my-rMM/rating_system_strings.xml
+++ b/res/values-my-rMM/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-my-rMM/strings.xml b/res/values-my-rMM/strings.xml
index 13378d42..1ab6baf7 100644
--- a/res/values-my-rMM/strings.xml
+++ b/res/values-my-rMM/strings.xml
@@ -27,11 +27,10 @@
<string name="play_controls_description_play_pause" msgid="7225542861669250558">"ဖွင့်ပါ သို့မဟုတ် ခဏရပ်ပါ"</string>
<string name="play_controls_description_fast_forward" msgid="4414963867482448652">"ရှေ့သို့ အမြန်သွားရန်"</string>
<string name="play_controls_description_fast_rewind" msgid="953488122681015803">"ပြန်ရစ်ရန်"</string>
- <string name="play_controls_description_skip_next" msgid="1603587562124694592">"နောက်တစ်ခု"</string>
+ <string name="play_controls_description_skip_next" msgid="1603587562124694592">"ရှေ့သို့"</string>
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"ယခင်"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"အစီအစဉ် လမ်းညွှန်"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"ရရှိနိုင်သည့် ချန်နယ်အသစ်များ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"လင့်ခ်မရနိုင်ပါ"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ဖွင့်ရန်"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"စာတမ်းထိုးများ"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"မြင်ကွင်း မုဒ်"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ထပ်ဆင့်-အမှတ်ပေးမှု"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ဒီချာနယ်ကို ကြည့်ရန် သင့် PIN ရိုက်ထည့်ပါ"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ဒီအစီအစဉ်ကို ကြည့်ရန် သင့် PIN ရိုက်ထည့်ပါ"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ဤပရိုဂရမ်ကို <xliff:g id="RATING">%1$s</xliff:g> အဆင့်သတ်မှတ်ထားပါသည်။ ဤပရိုဂရမ်ကို ကြည့်ရှုရန် သင့်ပင်နံပါတ်ကို ထည့်ပါ"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"သင့် PIN ရိုက်ထည့်ပါ"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"မိဘ ထိန်းချုပ်မှုကို သတ်မှတ်ရန်၊ PIN ကို ဖန်တီးပါ"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"PIN အသစ်ကို ထည့်သွင်းရန်"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"အခမဲ့အရင်းအမြစ်လိုင်စင်များ"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"အခမဲ့ ရင်းမြစ် လိုင်စင်များ"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ဗားရှင်း"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"တိုက်ရိုက်လွှင့်ချန်နယ်များ တိုးတက်အောင်ကူညီပါ"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"အသုံးပြုမှုနှင့် အမှားရှာဖွေမှုဒေတာများကို Google နှင့်မျှဝေခြင်းဖြင့် ပျက်စီးခြင်းနှင့် ရပ်တန့်သွားခြင်းကဲ့သို့သော ပြဿနာများကို ကာကွယ်ပြီး တိုက်ရိုက်လွှင့်နေသောချယ်နယ်များကို ပိုမိုကောင်းမွန်စေပါ။"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ဤချာနယ်ကို ကြည့်ရန်၊ ညာဘက် နှိပ်ပြီး PIN ရိုက်ထည့်ပါ"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ဤအစီအစဉ်ကို ကြည့်ရန်၊ ညာဘက် နှိပ်ပြီး PIN ရိုက်ထည့်ပါ"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ဤအစီအစဉ်သည် အဆင့် <xliff:g id="RATING">%1$s</xliff:g> ရှိ၏။ \nဤအစီအစဉ်အား ကြည့်ရန်၊ ညာဘက် နှိပ်ပြီး PIN ရိုက်ထည့်ပါ။"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"အသံ သီးသန့်"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"လှိုင်းဆွဲအားနည်းသည်"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"အင်တာနက်ချိတ်ဆက်မှု မရှိပါ"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">အခြားချန်နယ်လိုင်းများကို ဖမ်းယူနေသောကြောင့် ဤချန်နယ်လိုင်းကို <xliff:g id="END_TIME_1">%1$s</xliff:g> အထိ ဖွင့်၍ရမည်မဟုတ်ပါ။ \n\nဖမ်းယူခြင်းအချိန်ဇယားကို ချိန်ညှိရန် ညာဘက်ကိုနှိပ်ပါ။</item>
+ <item quantity="one">အခြားချန်နယ်လိုင်းကို ဖမ်းယူနေသောကြောင့် ဤချန်နယ်လိုင်းကို <xliff:g id="END_TIME_0">%1$s</xliff:g> အထိ ဖွင့်၍ရမည်မဟုတ်ပါ။ \n\nဖမ်းယူခြင်းအချိန်ဇယားကို ချိန်ညှိရန် ညာဘက်ကိုနှိပ်ပါ။</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ခေါင်းစဉ် မပါ"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"ချာနယ် ပိတ်ဆို့ထား"</string>
<string name="setup_category_new" msgid="2899355289563443627">"အသစ်"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"လိုင်းမရှိပါ"</string>
<string name="setup_input_new" msgid="3337725672277046798">"အသစ်"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"စဖွင့်မသတ်မှတ်ရသေးပါ"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"အရင်းအမြစ်များကို ပိုမိုရယူပါ"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"တိုက်ရိုက်လွှင့်နေသော ချန်နယ်များကို ကမ်းလှမ်းသည့် အက်ပ်များကို ရှာကြည့်ပါ"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"နောက်ထပ် အရင်းအမြစ်များ ရယူပါ"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"တိုက်ရိုက်လွှင့်ချန်နယ်များရှိသည့် အက်ပ်များကို ရှာပါ"</string>
<string name="new_sources_title" msgid="3878933676500061895">"ချန်နယ် အရင်းအမြစ် အသစ်များ ရှိပါသည်"</string>
<string name="new_sources_description" msgid="749649005588426813">"ချန်နယ် အရင်းအမြစ် အသစ်များမှ ကမ်းလှမ်းလိုသည့် ချန်နယ်များ ရှိပါသည်။ \n၎င်းတို့ကို ယခု စဖွင့်သတ်မှတ်ပါ၊ သို့မဟုတ် နောက်ပိုင်းတွင် ချန်နယ် အရင်းအမြစ်များ ဆက်တင်ထဲတွင် သတ်မှတ်ပါ။"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ယခု စဖွင့်သတ်မှတ်ပါ"</string>
@@ -181,14 +183,168 @@
<string name="msg_no_specific_input" msgid="2688885987104249852">"တီဗီ ထည့်သွင်းမှု ရှာမတွေ့နိုင်ပါ။"</string>
<string name="msg_no_pip_support" msgid="161508628996629445">"PIP ကို ပံ့ပိုးမထားပါ။"</string>
<string name="msg_no_available_input_by_pip" msgid="7038191654524679666">"PIP နှင့် ပြနိုင်သည့် ထည့်သွင်းစရာ မရှိပါ။"</string>
- <string name="msg_not_passthrough_input" msgid="4502101097091087411">"သင့်တော်သည့် တျူနာ အမျိုးအစား မဟုတ်ပါ။ တီဗွီ အဝင်ပေါက်အတွက် တိုက်ရိုက်လွှင့် ချန်နယ်များ app အား ဖွင့်ပါ။"</string>
+ <string name="msg_not_passthrough_input" msgid="4502101097091087411">"သင့်တော်သည့် တျူနာ အမျိုးအစား မဟုတ်ပါ။ တီဗွီ အဝင်ပေါက်အတွက် တိုက်ရိုက်လွှင့် ချန်နယ်များ အက်ပ်အား ဖွင့်ပါ။"</string>
<string name="msg_tune_failed" msgid="3277419551849972252">"ညှိမှု မအောင်မြင်ပါ"</string>
- <string name="msg_missing_app" msgid="8291542072400042076">"ဤလုပ်ဆောင်ချက်ကို ကိုင်တွယ်နိုင်သည့် အပလီကေးရှင်း မရှိပါ။"</string>
+ <string name="msg_missing_app" msgid="8291542072400042076">"ဤလုပ်ဆောင်ချက်ကို ကိုင်တွယ်နိုင်သည့် အက်ပ်မရှိပါ။"</string>
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ရင်းမြစ် ချာနယ် အားလုံးကို ဝှက်ထားသည်။ \n ကြည့်ရန် အနည်းဆုံး ချာနယ် တစ်ခုကို ရွေးပါ။"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ဗီဒီယို မမျှော်လင့်ဘဲ မရရှိနိုင်ပါ။"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK ကီးသည် ချိတ်ဆက် စက်ကိရိယာ အတွက်ဖြစ်၏။ ထွက်ရန် HOME ခလုတ်ကို နှိပ်ပါ။"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop ဗားရှင်းဖြင့်လည်ပတ်သော ဤကိရိယာတွင် တိုက်ရိုက်ထုတ်လွှင့်သောချန်နယ်လိုင်းများအား အသုံးမပြုနိင်ပါ။"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"တီဗီစာရင်းများကို ဖတ်ရှုရန် တိုက်ရိုက်ထုတ်လွှင့်သောချန်နယ်လိုင်းများတွင် ခွင့်ပြူချက်လိုအပ်သည်။"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"သင့်သတင်းအရင်းအမြစ်များကို တပ်ဆင်ပါ"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"တိုက်ရိုက်လွှင့်သည့် ချန်နယ်များသည် သမားရိုးကျ TV ချန်နယ်များနှင့် အက်ပ်မှလွှင့်ပေးသည့် ချန်နယ်များကို ပူးပေါင်းထားသည့်ခံစားမှုပင်ဖြစ်သည်။ \n\nထည့်သွင်းပြီးသား ချန်နယ်အရင်းမြစ်များကို တပ်ဆင်ခြင်းဖြင့် စတင်လိုက်ပါ။ သို့မဟုတ် တိုက်ရိုက်လွှင့်သည့် ချန်နယ်များပါဝင်သည့် နောက်ထပ်အက်ပ်များအတွက် Google Play Store တွင်ရှာပါ။"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ဖမ်းယူခြင်းနှင့် အချိန်ဇယားမျာ"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"၁၀ မိနစ်"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"၃၀ မိနစ်"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"၁ နာရီ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"၃ နာရီ"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"မကြာမီက"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"စီစဉ်ထားသော"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"စီးရီး"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"အခြား"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ချန်နယ်ကို မှတ်တမ်းတင်၍မရပါ။"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"ပရိုဂရမ်ကို မှတ်တမ်းတင်၍ မရပါ။"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ကို ဖမ်းယူရန် စီစဉ်ထားပါသည်"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ကို ယခုချိန်မှ <xliff:g id="ENDTIME">%2$s</xliff:g> အထိ ရိုက်ကူးမည်"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"အချိန်ဇယားအပြည့်အစုံ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">နောက်ထပ် %1$d ရက်</item>
+ <item quantity="one">နောက်ထပ် %1$d ရက်</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d မိနစ်</item>
+ <item quantity="one">%1$d မိနစ်</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">ရိုက်ကူးမှုအသစ် %1$d ခု</item>
+ <item quantity="one">ရိုက်ကူးမှုအသစ် %1$d ခု</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">ရိုက်ကူးမှု %1$d ခု</item>
+ <item quantity="one">ရိုက်ကူးမှု %1$d ခု</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">ရိုက်ကူးရန် အစီအစဉ်%1$dခု</item>
+ <item quantity="one">ရိုက်ကူးရန် အစီအစဉ်%1$dခု</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ကြည့်ရန်"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"အစမှနေ၍ ဖွင့်ရန်"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ဆက်ဖွင့်ရန်"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"ဖျက်ရန်"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"မှတ်တမ်းတင်ထားသည်ကို ဖျက်ရန်"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"ဆက်ဖွင့်ရန်"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"အတွဲ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"အချိန်ဇယားကိုကြည့်ရန်"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"နောက်ထပ် ဖတ်ရန်"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ရုပ်သံကူးယူမှုဖျက်ပါ"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"သင်ဖျက်ပစ်လိုသော အခန်းဆက်များကို ရွေးပါ။ ဖျက်လိုက်သည်နှင့် ၎င်းတို့ကို ပြန်ဆည်ယူ၍ မရတော့ပါ။"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ဖျက်ရန် ရုပ်သံဖမ်းယူမှုများ မရှိတော့ပါ။"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"ကြည့်ပြီးသောအခန်းဆက်များရွေးပါ"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"အခန်းဆက်များအားလုံးကို ရွေးပါ"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"အခန်းဆက်များအားလုံးကို ဖျက်ပါ"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> မိနစ်ရှိသည့်အနက် <xliff:g id="WATCHED">%1$d</xliff:g> မိနစ် ကြည့်ပြီးသွားပြီ"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> စက္ကန့်ရှိသည့်အနက် <xliff:g id="WATCHED">%1$d</xliff:g> စက္ကန့် ကြည့်ပြီးသွားပြီ"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"လုံးဝမကြည့်ရသေးပါ"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">အခန်းဆက် %2$d ခုအနက် %1$d ခုကို ဖျက်လိုက်သည်</item>
+ <item quantity="one">အခန်းဆက် %2$d ခုအနက် %1$d ခုကို ဖျက်လိုက်သည်</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ဦးစားပေးမှု"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"အမြင့်ဆုံး"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"အနိမ့်ဆုံး"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"နံပါတ် <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ချန်နယ်များ"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"မည်သည့်အရာမဆို"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ဦးစားပေးမှုကို ရွေးရန်"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"တစ်ချိန်တည်းတွင် ဖမ်းယူရမည့်အစီအစဉ် များပြားလွန်းသည့်အခါ ဦးစားပေးမှု ပိုမိုမြင့်မားသည့် အစီအစဉ်များကိုသာ ဖမ်းယူသွားပါမည်။"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"သိမ်းရန်"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"တစ်ကြိမ်တစ်ခါတည်း ဖမ်းယူခြင်းသည် ဦးစားပေးမှုအမြင့်ဆုံးဖြစ်သည်"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"မလုပ်တော့"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"မလုပ်တော့"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"မေ့ပစ်ရန်"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"ရပ်ရန်"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ဖမ်းယူခြင်းအချိန်ဇယားကို ကြည့်ရန်"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ဤအစီအစဉ် တစ်ခုတည်း"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ယခု - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"အခန်းဆက်များ တစ်တွဲလုံး…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"မည်သို့ပင်ဖြစ်စေ စီစဉ်ရန်"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"၎င်းအစား ဤတစ်ခုကို ဖမ်းယူပါ"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ဤဖမ်းယူမှုကို ပယ်ဖျက်ရန်"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ယခုကြည့်ရန်"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ရိုက်ကူးနိုင်သည်"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ရိုက်ကူးရေးအတွက် စီစဉ်ထားပါသည်"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ရိုက်ကူးရေးအစီအစဉ်တိုက်နေပါသည်"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ဖမ်းယူနေသည်"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ဖမ်းယူခြင်း မအောင်မြင်ပါ"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"ရိုက်ကူးရေး အချိန်ဇယားများ သတ်မှတ်ရန် အစီအစဉ်များကို ဖတ်နေသည်"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"ပရိုဂရမ်များကို ဖတ်နေသည်"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR သည် နောက်ထပ်သိုလှောင်ရန်နေရာလွတ် လိုအပ်နေသည်"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"အစီအစဉ်များကို DVR နှင့် ဖမ်းယူသိမ်းဆည်းထားနိုင်ပါသည်။ သို့သော် DVR ကို အသုံးပြုနိုင်ရန် သင့်စက်ပစ္စည်းတွင် လုံလောက်သော နေရာလွတ် လောလောဆယ်မရှိပါ။ <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>ဂစ်ဂါဘိုက် သို့မဟုတ် ၎င်းနှင့်အထက်ရှိသော ပြင်ပသိုလှောင်ကိရိယာနှင့် ချိတ်ဆက်ပြီး ၎င်းကို သိုလှောင်ခန်းစက်ပစ္စည်းအဖြစ် ပြင်ဆင်သတ်မှတ်ရန် ညွှန်ကြားချက်များအတိုင်း လိုက်နာပါ။"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"သိုလှောင်မှုများ ပျောက်ဆုံးနေခြင်း"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR က အသုံးပြုသော သိုလှောင်ခန်းအချို့မှာ ပျောက်ဆုံးနေသည်။ DVR ကို ပြန်ဖွင့်ရန်အတွက် ယခင်က အသုံးပြုခဲ့သော ပြင်ပသုံးအခွေဖွင့်စက်နှင့် ချိတ်ဆက်ပါ။ နောက်တစ်နည်းအနေဖြင့် ၎င်းကို အသုံးပြု၍ မရတော့လျှင် မေ့ပစ်ရန် ရွေးချယ်နိုင်ပါသည်။"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"သိုလှောင်ခန်းကို မေ့ပစ်မလား။"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"သင်မှတ်တမ်းတင်ထားသော အကြောင်းအရာနှင့် အချိန်ဇယားများအားလုံး ဆုံးရှုံးသွားလိမ့်မည်။"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ရိုက်ကူးခြင်းကို ရပ်လိုပါသလား။"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ဖမ်းယူထားသည့် အကြောင်းအရာကို သိမ်းဆည်းထားပါမည်။"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ဖမ်းယူရန် စီစဉ်ထားသော်လည်း အချိန်ဇယားတိုက်နေပါသည်"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ဖမ်းယူမှုကို စတင်လိုက်ပါပြီ။ သို့သော် အချိန်ဇယားတိုက်နေပါသည်"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ကို ဖမ်းယူသွားပါမည်။"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> ကို ဖမ်းယူနေပါသည်။"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ၏ အချို့အစိတ်အပိုင်းများကို ဖမ်းယူသွားမည် မဟုတ်ပါ။"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> နှင့် <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> တို့၏ အချို့အစိတ်အပိုင်းများကို ဖမ်းယူသွားမည် မဟုတ်ပါ။"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>၊ <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> တို့၏ အချို့အစိတ်အပိုင်းများနှင့် နောက်ထပ်အစီအစဉ် တစ်ခုကို ဖမ်းယူသွားမည် မဟုတ်ပါ။"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>၊ <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> တို့၏ အချို့အစိတ်အပိုင်းများနှင့် နောက်ထပ်အစီအစဉ် %3$d ခုတို့ကို ဖမ်းယူသွားမည် မဟုတ်ပါ။</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>၊ <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> တို့၏ အချို့အစိတ်အပိုင်းများနှင့် နောက်ထပ်အစီအစဉ် %3$d ခုတို့ကို ဖမ်းယူသွားမည် မဟုတ်ပါ။</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"သင်ဘယ်ရုပ်/သံကို ဖမ်းယူလိုပါသလဲ။"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"ဘယ်လောက်ကြာကြာ ဖမ်းယူလိုပါသနည်း။"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"စီစဉ်ပြီးပါပြီ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"တူညီသည့် ပရိုဂရမ်ကို <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> ၌ ဖမ်းယူရန် စီစဉ်ထားပြီး ဖြစ်ပါသည်။"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ဖမ်းယူပြီးပါပြီ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ဤပရိုဂရမ်ကို ဖမ်းယူပြီးပါပြီ။ ၎င်းကို DVR စာကြည့်တိုက်တွင် ကြည့်ရှုနိုင်ပါသည်။"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ရိုက်ကူးထားသည့်ပရိုဂရမ်ကို မတွေ့ပါ။"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"ဆက်စပ်နေသည့် ရိုက်ကူးမှုများ"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ပရိုဂရမ် ဖော်ပြချက်မရှိပါ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">ရိုက်ပြီးသား %1$d ခု</item>
+ <item quantity="one">ရိုက်ပြီးသား %1$d ခု</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ကို ဖမ်းယူခြင်းအစီအစဉ်မှ ဖယ်ရှားလိုက်ပါပြီ"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ချန်နယ်ချိန်ကိရိယာလိုင်းပူးနေ၍ တစ်ချို့ကိုသာ ဖမ်းယူနိုင်မည်။"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ချန်နယ်ချိန်ကိရိယာ လိုင်းပူးနေ၍ ဖမ်းယူနိုင်မည်မဟုတ်ပါ။"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"စီစဉ်ထားသည့် ဖမ်းယူမှုများ မရှိသေးပါ။\nဖမ်းယူမှုကို ပရိုဂရမ်လမ်းညွှန်အား ကြည့်ရှု၍ စီစဉ်နိုင်ပါသည်။"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">ရိုက်ကူးမှု %1$d ခု ပဋိပက္ခဖြစ်နေပါသည်</item>
+ <item quantity="one">ရိုက်ကူးမှု %1$d ခု ပဋိပက္ခဖြစ်နေပါသည်</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"ဇာတ်လမ်းတွဲဆက်တင်များ"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"ဇာတ်လမ်းတွဲ စတင်ဖမ်းယူရန်"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"ဇာတ်လမ်းတွဲဖမ်းယူခြင်း ရပ်ရန်"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"ဇာတ်လမ်းတွဲဖမ်းယူခြင်းကို ရပ်မလား။"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ဖမ်းယူထားသည့် အပိုင်းများသည် DVR စာကြည့်တိုက်တွင် ရှိနေဦးမည်ဖြစ်သည်။"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"ရပ်ရန်"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"အပိုင်းငယ်များ မရနိုင်သေးပါ။\nရနိုင်သည်နှင့် ၎င်းတို့ကို ဖမ်းယူသွားပါမည်။"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d မိနစ်)</item>
+ <item quantity="one">(%1$d မိနစ်) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ဒီနေ့"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"မနက်ဖြန်"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"မနေ့က"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"ဒီနေ့ <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"မနက်ဖြန် <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ရမှတ်"</string>
</resources>
diff --git a/res/values-nb/arrays.xml b/res/values-nb/arrays.xml
index 14d83e84..145dd560 100644
--- a/res/values-nb/arrays.xml
+++ b/res/values-nb/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Full"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alle kanaler"</item>
- <item msgid="6897460857821394118">"Familie/barn"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Filmer"</item>
- <item msgid="1054540282883891201">"Komedie"</item>
- <item msgid="7900158429062595471">"Reise"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Utdanning"</item>
- <item msgid="7396447839483867269">"Dyr/villmarksliv"</item>
- <item msgid="4738043455148062673">"Nyheter"</item>
- <item msgid="7405041316051047427">"Spill"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alle kanaler"</item>
- <item msgid="7909003973960375395">"Familie/barn"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Filmer"</item>
- <item msgid="8302638329222449550">"Komedie"</item>
- <item msgid="3803709976021475052">"Reise"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Utdanning"</item>
- <item msgid="7511135485827589547">"Dyr/villmarksliv"</item>
- <item msgid="6961248112238009967">"Nyheter"</item>
- <item msgid="6484685553679698447">"Spill"</item>
- <item msgid="2737158328243183190">"Kunst"</item>
- <item msgid="6577176952650166615">"Underholdning"</item>
- <item msgid="7886693831871777617">"Livsstil"</item>
- <item msgid="8145832312485577062">"Musikk"</item>
- <item msgid="1345789204804308580">"Premiere"</item>
- <item msgid="2736680312770771994">"Teknologi/vitenskap"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alle kanaler"</item>
+ <item msgid="928298872841713530">"Familie/barn"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Filmer"</item>
+ <item msgid="525966731464264290">"Komedie"</item>
+ <item msgid="6096710741527327836">"Reise"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Utdanning"</item>
+ <item msgid="7221999662426308394">"Dyr/villmarksliv"</item>
+ <item msgid="375300513250925001">"Nyheter"</item>
+ <item msgid="7746320336582330410">"Spill"</item>
+ <item msgid="1255741860568329178">"Kunst"</item>
+ <item msgid="7603949681065702867">"Underholdning"</item>
+ <item msgid="4453821994746804366">"Livsstil"</item>
+ <item msgid="3488534597567932843">"Musikk"</item>
+ <item msgid="7452153120614274095">"Premiere"</item>
+ <item msgid="8215762047341133299">"Teknologi/vitenskap"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Direkte-TV"</item>
diff --git a/res/values-nb/rating_system_strings.xml b/res/values-nb/rating_system_strings.xml
index 0b69ad23..1a301434 100644
--- a/res/values-nb/rating_system_strings.xml
+++ b/res/values-nb/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index f56156d8..a2cf46cc 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Forrige"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programoversikt"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nye kanaler er tilgjengelig"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ingen link tilgjengelig"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Åpne <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Teksting"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Visningsmodus"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Ekstravurderinger"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Skriv inn PIN-koden din for å se på denne kanalen"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Skriv inn PIN-koden din for å se på dette programmet"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Dette programmet er vurdert som <xliff:g id="RATING">%1$s</xliff:g>. Skriv inn PIN-koden din for å se dette programmet"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Skriv inn PIN-koden din"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"For å konfigurere foreldrekontroll, angi en PIN-kode"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Skriv inn en ny PIN-kode"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Lisenser for åpen kildekode"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Åpen kildekode-lisenser"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versjon"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Bidra til å forbedre Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Del anonyme bruksdata og diagnostikkdata med Google sånn at vi kan gjøre Direkte-TV bedre og forhindre problemer (for eksempel når appen kræsjer eller fryser)."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"For å se på denne kanalen, trykk til høyre og skriv inn PIN-koden din"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"For å se på dette programmet, trykk til høyre og skriv inn PIN-koden din"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Dette programmet har vurderingen <xliff:g id="RATING">%1$s</xliff:g>.\nFor å se på dette programmet, trykk til høyre og skriv inn PIN-koden din."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Bare lyd"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Svakt signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Ingen Internett-tilkobling"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Denne kanalen kan ikke spilles av før <xliff:g id="END_TIME_1">%1$s</xliff:g> fordi andre kanaler blir tatt opp. \n\nTrykk høyre for å justere tidsplanen for opptak.</item>
+ <item quantity="one">Denne kanalen kan ikke spilles av før <xliff:g id="END_TIME_0">%1$s</xliff:g> fordi en annen kanal blir tatt opp. \n\nTrykk høyre for å justere tidsplanen for opptak.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Ingen tittel"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanalen er blokkert"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nye"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ingen kanaler er tilgjengelig"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Ny"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Ikke konfigurert"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Få flere kilder"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Bla gjennom apper som tilbyr kanaler for direkte-TV"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Få flere kilder"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Bla gjennom apper som tilbyr direkte-TV"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nye kanalkilder er tilgjengelig"</string>
<string name="new_sources_description" msgid="749649005588426813">"Med de nye kanalkildene får du flere kanaler.\nKonfigurer dem nå, eller gjør det senere i innstillingene for kanalkilder."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Konfigurer nå"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alle kildekanalene er skjult.\nDu må velge minst én kanal å se på."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videoen er utilgjengelig på grunn av en uventet feil"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"TILBAKE-tasten er for den tilkoblede enheten. Trykk på STARTSIDE-knappen for å avslutte."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV støttes ikke på denne enheten med Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV trenger tillatelse til å lese TV-programoversikten."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Konfigurer kanalkildene dine"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Med direkte-TV får du både den tradisjonelle TV-opplevelsen og strømming av kanaler via apper. \n\nKom i gang ved å konfigurere de kanalkildene som allerede er installert. Eventuelt kan du bla gjennom Google Play Butikk for å finne flere apper som tilbyr direkte-TV."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Opptak og tidsplaner"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutter"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutter"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 time"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 timer"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nylige"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Planlagt"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serier"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Annet"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanalen kan ikke bli tatt opp."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programmet kan ikke bli tatt opp."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> er planlagt for opptak"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Tar opp <xliff:g id="PROGRAMNAME">%1$s</xliff:g> fra nå til <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Fullstendig tidsplan"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">De neste %1$d dagene</item>
+ <item quantity="one">Den neste dagen</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutter</item>
+ <item quantity="one">%1$d minutt</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nye opptak</item>
+ <item quantity="one">%1$d nytt opptak</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d opptak</item>
+ <item quantity="one">%1$d opptak</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d planlagte opptak</item>
+ <item quantity="one">%1$d planlagt opptak</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Se på"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Spill av fra begynnelsen"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Gjenoppta avspilling"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Slett"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Slett opptak"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Gjenoppta"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Sesong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Se tidsplanen"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Finn ut mer"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Slett opptak"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Velg episodene du vil slette. De kan ikke gjenopprettes når de først er slettet."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Det finnes ingen opptak som kan slettes."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Velg episoder du har sett"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Velg alle episodene"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Opphev merking av episodene"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> av <xliff:g id="DURATION">%2$d</xliff:g> minutter er sett"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> av <xliff:g id="DURATION">%2$d</xliff:g> sekunder er sett"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Aldri sett"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d av %2$d episoder er slettet</item>
+ <item quantity="one">%1$d av %2$d episode er slettet</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Høyest"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lavest"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nei. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanaler"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Alle"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Velg prioritet"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Når det er for mange programmer som skal tas opp samtidig, blir bare programmene med høyere prioritet tatt opp."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Lagre"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Engangsopptak har høyeste prioritet"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Avbryt"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Avbryt"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Glem"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stopp"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Se tidsplanen for opptak"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Bare dette programmet"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"nå – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Hele serien …"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Planlegg likevel"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Spill inn dette i stedet"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Kanseller dette opptaket"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Se nå"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Opptaksbar"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Opptak planlagt"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Opptakskonflikt"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Tar opp"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Opptaket mislyktes"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Leser av programmer for å opprette tidsplaner for opptak"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Leser av programmer"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR trenger mer lagringsplass"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Det kommer til å være mulig til å ta opp programmer med DVR. Det er imidlertid ikke nok lagringsplass på enheten din til at DVR kan fungere. Koble til en ekstern stasjon på <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB eller mer, og følg trinnene for å formatere den som lagringsenhet."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Manglende lagringsplass"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Noe av lagringsplassen som brukes av DVR, mangler. Koble til den eksterne disken du bruke tidligere, for å slå på DVR igjen. Eventuelt kan du velge å glemme lagringsplassen hvis den ikke er tilgjengelig lenger."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Vil du glemme lagring?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Alt innspilt innhold og alle tidsplanene går tapt."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Vil du stoppe opptaket?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Det innspilte innholdet blir lagret."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Opptak er planlagt, men har konflikter"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Opptak har startet, men har konflikter"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> blir tatt opp."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> blir tatt opp."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Enkelte deler av <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> blir ikke tatt opp."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Enkelte deler av <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> og <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> blir ikke tatt opp."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Enkelte deler av <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> og én annen plan blir ikke tatt opp."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Enkelte deler av <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> og %3$d andre planer blir ikke tatt opp.</item>
+ <item quantity="one">Enkelte deler av <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> og %3$d annen plan blir ikke tatt opp.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Hva vil du ta opp?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hvor lenge vil du ta opp?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Allerede planlagt"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Det samme programmet er allerede planlagt for opptak <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Allerede tatt opp"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Dette programmet er allerede tatt opp. Det er tilgjengelig i DVR-biblioteket."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Finner ikke programopptaket."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Relaterte opptak"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ingen programbeskrivelse)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d opptak</item>
+ <item quantity="one">%1$d opptak</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> er fjernet fra tidsplanen for opptak"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Blir delvis tatt opp på grunn av tunerkonflikter."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Blir ikke tatt opp på grunn av tunerkonflikter."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Det finnes ingen planlagte opptak ennå.\nDu kan planlegge opptak fra programoversikten."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d opptakskonflikter</item>
+ <item quantity="one">%1$d opptakskonflikt</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Innstillinger for serier"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Start opptak av serie"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stopp opptak av serie"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Vil du stoppe opptaket av serien?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Episoder som er tatt opp, er fremdeles tilgjengelige i DVR-biblioteket."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stopp"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Ingen episoder er tilgjengelige.\nDe blir tatt opp når de er tilgjengelige."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutter)</item>
+ <item quantity="one">(%1$d minutt) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"I dag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"I morgen"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"I går"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i dag"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i morgen"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Poengsum"</string>
</resources>
diff --git a/res/values-ne-rNP/arrays.xml b/res/values-ne-rNP/arrays.xml
index 711c21f8..a6dc0066 100644
--- a/res/values-ne-rNP/arrays.xml
+++ b/res/values-ne-rNP/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"पूर्ण"</item>
<item msgid="8568284598210500589">"जूम"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"सबै च्यानलहरू"</item>
- <item msgid="6897460857821394118">"पारिवार/बालबालिकाहरू"</item>
- <item msgid="551257741825778215">"खेलकुदहरू"</item>
- <item msgid="452133796804325879">"किनमेल"</item>
- <item msgid="3296058637230163031">"चलचित्रहरू"</item>
- <item msgid="1054540282883891201">"हास्य"</item>
- <item msgid="7900158429062595471">"यात्रा"</item>
- <item msgid="3768998587825611787">"नाटक"</item>
- <item msgid="8340620094959282881">"शिक्षा"</item>
- <item msgid="7396447839483867269">"जनावर/वन्यजन्तु"</item>
- <item msgid="4738043455148062673">"समाचार"</item>
- <item msgid="7405041316051047427">"गेमिङ"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"सबै च्यानलहरू"</item>
- <item msgid="7909003973960375395">"पारिवार/बालबालिकाहरू"</item>
- <item msgid="3185279732911635789">"खेलकुदहरू"</item>
- <item msgid="4704858492065325964">"किनमेल"</item>
- <item msgid="6083795019290250078">"चलचित्रहरू"</item>
- <item msgid="8302638329222449550">"हास्य"</item>
- <item msgid="3803709976021475052">"यात्रा"</item>
- <item msgid="8116747365234169059">"नाटक"</item>
- <item msgid="7356447541595315913">"शिक्षा"</item>
- <item msgid="7511135485827589547">"जनावर/वन्यजन्तु"</item>
- <item msgid="6961248112238009967">"समाचार"</item>
- <item msgid="6484685553679698447">"गेमिङ"</item>
- <item msgid="2737158328243183190">"कलाहरू"</item>
- <item msgid="6577176952650166615">"मनोरञ्जन"</item>
- <item msgid="7886693831871777617">"जीवन शैली"</item>
- <item msgid="8145832312485577062">"संगीत"</item>
- <item msgid="1345789204804308580">"प्रिमियर"</item>
- <item msgid="2736680312770771994">"प्रविधि/विज्ञान"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"सबै च्यानलहरू"</item>
+ <item msgid="928298872841713530">"पारिवार/बच्चाहरु"</item>
+ <item msgid="2751606947569857164">"खेलकुदहरू"</item>
+ <item msgid="7345749789651321496">"किनमेल"</item>
+ <item msgid="167201149441442173">"चलचित्रहरू"</item>
+ <item msgid="525966731464264290">"हास्य"</item>
+ <item msgid="6096710741527327836">"यात्रा"</item>
+ <item msgid="2851882187117833883">"नाटक"</item>
+ <item msgid="78492781188719038">"शिक्षा"</item>
+ <item msgid="7221999662426308394">"जनावर/वन्यजन्तु"</item>
+ <item msgid="375300513250925001">"समाचार"</item>
+ <item msgid="7746320336582330410">"खेल"</item>
+ <item msgid="1255741860568329178">"कलाहरू"</item>
+ <item msgid="7603949681065702867">"मनोरञ्जन"</item>
+ <item msgid="4453821994746804366">"जीवन शैली"</item>
+ <item msgid="3488534597567932843">"संगीत"</item>
+ <item msgid="7452153120614274095">"प्रिमियर"</item>
+ <item msgid="8215762047341133299">"प्रविधि/विज्ञान"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"लाइभ च्यानलहरू"</item>
diff --git a/res/values-ne-rNP/rating_system_strings.xml b/res/values-ne-rNP/rating_system_strings.xml
index 211e4b3c..776e7175 100644
--- a/res/values-ne-rNP/rating_system_strings.xml
+++ b/res/values-ne-rNP/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ne-rNP/strings.xml b/res/values-ne-rNP/strings.xml
index f8b6f4c7..142dfade 100644
--- a/res/values-ne-rNP/strings.xml
+++ b/res/values-ne-rNP/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"अघिल्लो"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"कार्यक्रम गाइड"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"नयाँ च्यानलहरू उपलब्ध"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"कुनै लिंक उपलब्ध छैनन्"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> खोल्नुहोस्"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"बन्द क्याप्सनहरु"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"डिस्प्ले मोड"</string>
@@ -124,10 +123,11 @@
<string name="option_subrating_header" msgid="4637961301549615855">"सहायक स्तर निर्धारण"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"यो च्यानल हेर्न तपाईँको PIN प्रविष्टि गर्नुहोस्"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"यो कार्यक्रम हेर्न तपाईँको PIN प्रविष्टि गर्नुहोस्"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"यस कार्यक्रमलाई <xliff:g id="RATING">%1$s</xliff:g> भनेर मूल्याङ्कन गरिएको छ। यो कार्यक्रम हेर्न आफ्नो PIN प्रविष्ट गर्नुहोस्"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"आफ्नो पिन प्रविष्ट गर्नुहोस्"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"अभिभावकत्वको नियन्त्रण सेट गर्न, एउटा PIN सिर्जना गर्नुहोस्"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"नयाँ PIN प्रविष्टि गर्नुहोस्"</string>
- <string name="pin_enter_again" msgid="2618999754723090427">"तपाईँको PIN निश्चित गर्नुहोस्"</string>
+ <string name="pin_enter_again" msgid="2618999754723090427">"तपाईँको PIN को पुष्टि गर्नुहोस्"</string>
<string name="pin_enter_old_pin" msgid="4588282612931041919">"तपाईंको हालको पिन प्रविष्ट गर्नुहोस्"</string>
<plurals name="pin_enter_countdown" formatted="false" msgid="3415233538538544309">
<item quantity="other">तपाईंले ५ पटक गलत PIN प्रविष्ट गर्नुभयो।\n<xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> सेकेन्डमा पुन: प्रयास गर्नुहोस्।</item>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"स्रोतका इजाजतपत्रहरू खोल्नुहोस्"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"खुला स्रोत इजाजतपत्रहरू"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"संस्करण"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"लाइभ च्यानलहरु सुधार गर्न मद्दत गर्नुहोस्"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google सँग अज्ञात प्रयोग डेटा र लक्षण पहिचान गर्न डेटा साझेदारी गर्नुहोस् ताकि हामी लाइभ च्यानलहरू राम्रो बनाउन र क्र्यास हुने तथा स्थिर हुने समस्याहरूलाई रोक्न सक्छौं।"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"यो च्यानल हेर्न, दायाँ प्रेस गर्नुहोस् र आफ्नो पिन प्रविष्ट गर्नुहोस्"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"यो कार्यक्रम हेर्न, दायाँ प्रेस गर्नुहोस् र आफ्नो पिन प्रविष्ट गर्नुहोस्"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"यो कार्यक्रम मूल्याङ्कन <xliff:g id="RATING">%1$s</xliff:g> गरिएको छ।\nयो कार्यक्रम हेर्न, दायाँ थिच्नुहोस् र आफ्नो PIN प्रविष्ट गर्नुहोस्।"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"अडियो मात्र"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"सिग्नल कमजोर छ"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"इन्टरनेटमा जडान गर्न सकिएन"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">अन्य च्यानलहरू रेकर्ड भइरहेका हुनाले <xliff:g id="END_TIME_1">%1$s</xliff:g> सम्म यो च्यानल प्ले गर्न सकिँदैन। \n\nरेकर्डिङको समय तालिकालाई समायोजन गर्न दायाँ बटन थिच्नुहोस्।</item>
+ <item quantity="one">अर्को च्यानल रेकर्ड भइरहेको हुनाले <xliff:g id="END_TIME_0">%1$s</xliff:g> सम्म यो च्यानल प्ले गर्न सकिँदैन। \n\nरेकर्डिङको समय तालिकालाई समायोजन गर्न दायाँ बटन थिच्नुहोस्।</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"शीर्षक छैन"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"च्यानल अवरुद्ध"</string>
<string name="setup_category_new" msgid="2899355289563443627">"नयाँ"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"कुनै च्यानलहरू उपलब्ध छैनन्"</string>
<string name="setup_input_new" msgid="3337725672277046798">"नयाँ"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"सेटअप गरिएको छैन"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"थप स्रोतहरु प्राप्त गर्नुहोस्"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"प्रत्यक्ष च्यानलहरूको प्रस्ताव गर्ने अनुप्रयोगहरू ब्राउज गर्नुहोस्"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"थप स्रोतहरू प्राप्त गर्नुहोस्"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"लाइभ च्यानलहरू प्रस्तुत गर्ने अनुप्रयोगहरू ब्राउज गर्नुहोस्"</string>
<string name="new_sources_title" msgid="3878933676500061895">"उपलब्ध नयाँ च्यानलका स्रोतहरू"</string>
<string name="new_sources_description" msgid="749649005588426813">"नयाँ च्यानलका स्रोतहरुसँग प्रस्ताव गर्न च्यानलहरू छन्। \n अहिले तिनीहरूलाई सेट गर्नुहोस् वा च्यानल स्रोतहरुका सेटिङमा पछि गर्नुहोस्।"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"अब सेटअप गर्नुहोस्"</string>
@@ -184,11 +186,165 @@
<string name="msg_not_passthrough_input" msgid="4502101097091087411">"ट्यूनर प्रकार अनुपयुक्त। कृपया ट्यूनर प्रकार टिभी स्रोतको लागि Live TV को अनुप्रयोग सुरु गर्नुहोस।"</string>
<string name="msg_tune_failed" msgid="3277419551849972252">"ट्युन गर्न असफल"</string>
<string name="msg_missing_app" msgid="8291542072400042076">"यो कार्य सम्हाल्न कुनै पनि अनुप्रयोग भेटिएन।"</string>
- <string name="msg_all_channels_hidden" msgid="777397634062471936">"सबै स्रोत च्यानलहरू लुकेको छन्। \n हेर्नको लागि कम्तिमा एक च्यानल चयन गर्नुहोस्।"</string>
+ <string name="msg_all_channels_hidden" msgid="777397634062471936">"सबै स्रोत च्यानलहरू लुकेको छन्। \n हेर्नको लागि कम्तीमा एक च्यानल चयन गर्नुहोस्।"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"भिडियो अप्रत्याशित रूपमा अनुपलब्ध।"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK कुञ्जी जडान भएका उपकरणका लागि हो। बाहिर निस्कनका लागि गृह बटन थिच्नुहोस्।"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"लाइभ च्यानलहरु Android Lollipop भएको यस यन्त्रमा समर्थित छैन।"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"लाइभ च्यानलहरुलाई TV सूचीहरूलाई पढ्न अनुमति आवश्यक पदर्छ।"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"आफ्नो स्रोतहरू सेट अप गर्नुहोस्"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"लाइभ च्यानलहरूले TV च्यानलहरूसँगै उपलब्ध गराइएका प्रवाह भइरहेका च्यानलहरूको परम्परागत अनुभवलाई संयोजन गर्छ। \n\nपहिले नै स्थापित च्यानल स्रोतहरू सेट अप गरेर सुरू गरौं। वा लाइभ च्यानलहरू प्रस्ताव गर्ने अझ बढी अनुप्रयोगहरूका लागि Google Play स्टोर ब्राउज गर्नुहोस्।"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"रेकर्डिङ र समयतालिकाहरू"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"१० मिनेट"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"३० मिनेट"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"१ घन्टा"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"३ घन्टा"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"हालको"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"तालिकाबद्ध गरिएको"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"श्रृंखला"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"अन्य"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"यो च्यानल रेकर्ड गर्न सकिँदैन।"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"यो कार्यक्रम रेकर्ड गर्न सकिँदैन।"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> लाई रेकर्ड गर्ने कार्यतालिका निर्धारण गरिएको छ"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"अहिले देखि <xliff:g id="ENDTIME">%2$s</xliff:g> सम्म <xliff:g id="PROGRAMNAME">%1$s</xliff:g> नामक कार्यक्रम रेकर्ड गर्दै"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"समय सहितको पूर्ण कार्यतालिका"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">आगामी %1$d दिन</item>
+ <item quantity="one">आगामी %1$d दिन</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d मिनेट</item>
+ <item quantity="one">%1$d मिनेट</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d नयाँ रेकर्डिङहरू</item>
+ <item quantity="one">%1$d नयाँ रेकर्डिङ</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d रेकर्डिङहरू</item>
+ <item quantity="one">%1$d रेकर्डिङ</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d रेकर्डिङहरूको समय निर्धारण गरियो</item>
+ <item quantity="one">%1$d रेकर्डिङको समय निर्धारण गरियो</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"हेर्नुहोस्"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"सुरुबाट चलाउनुहोस्"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"पुनःसुरु गर्नुहोस्"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"मेट्नुहोस्"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"रेकर्डिङहरू मेट्नुहोस्"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"पुनःसुरु गर्नु"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"सत्र <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"समयतालिका हेर्नु"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"थप पढ्नुहोस्"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"रेकर्डिङ मेट्नुहोस्"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"तपाईँले मेट्न चाहनुहुने एपिसोडहरूलाई चयन गर्नुहोस्। एक पटक मेटाएपछि तिनीहरूलाई पुन:प्राप्त गर्न सकिँदैन।"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"मेट्नका लागि कुनै रेकर्डिङ छैन।"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"हेरिएका एपिसोड चयन गर्नुहोस्"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"सबै एपिसोडहरू चयन गर्नुहोस्"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"सबै एपिसोडहरू चयन नगर्नुहोस्"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> मिनेट मध्ये <xliff:g id="WATCHED">%1$d</xliff:g> मिनेट हेरियो"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> सेकेन्ड मध्ये <xliff:g id="WATCHED">%1$d</xliff:g> सेकेन्ड हेरियो"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"कहिल्यै नहेरिएका"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d मध्ये %1$d एपिसोडहरू मेटाइए</item>
+ <item quantity="one">%2$d मध्ये %1$d एपिसोड मेटाइयो</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"प्राथमिकता"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"सबैभन्दा उच्च"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"सबैभन्दा न्यून"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"नम्बर <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"च्यानलहरू"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"जुनसुकै"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"प्राथमिकता छान्नुहोस्"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"एकै समयमा अत्यन्त धेरै कार्यक्रमहरू रेकर्ड गर्नुपर्ने भएकाले उच्च प्राथमिकता भएका कार्यक्रमहरूलाई मात्र रेकर्ड गरिनेछ।"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"सुरक्षित गर्नुहोस्"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"एक-पटके रेकर्डिङहरूलाई सबैभन्दा उच्च प्राथमिकता दिइन्छ"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"रद्द गर्नु"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"रद्द गर्नुहोस्"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"बिर्सनुहोस्"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"रोक्नुहोस्"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"रेकर्डिङको समयतालिका हेर्नुहोस्"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"यो कार्यक्रम मात्र"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"अहिले - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"सम्पूर्ण शृंखला…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"जे भए पनि समय निर्धारण गर्नुहोस्"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"बरु यो रेकर्ड गर्नुहोस्"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"यस रेकर्डिङलाई रद्द गर्नुहोस्"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"अहिले हेर्नुहोस्"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"रेकर्ड गर्न मिल्ने"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"रेकर्डिङको कार्यतालिका निर्धारण गरिएको छ"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"रेकर्डिङ सम्बन्धी असहमति"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"रेकर्ड गर्दै"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"रेकर्डिङ गर्न सकिएन"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"रेकर्डिङका समय तालिकाहरू सिर्जना गर्न कार्यक्रमहरू पढ्दै"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"कार्यक्रमहरूको जानकारी पढ्दै"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR लाई थप भण्डारण चाहिन्छ"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"तपाईँले DVR मार्फत कार्यक्रमहरू रेकर्ड गर्न सक्नुहुनेछ। यद्यपि, अहिले तपाईँको यन्त्रमा DVR ले काम गर्न पुग्ने गरी पर्याप्त भण्डारण छैन। कृपया <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> जि.बि.वा सो भन्दा बढी भण्डारण क्षमता भएको कुनै बाह्य ड्राइभ जडान गर्नुहोस् र त्यसलाई यन्त्रको भण्डारणका रूपमा फर्म्याट गर्न आवश्यक कदमहरू चाल्नुहोस्।"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"भण्डारण उपलब्ध छैन"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR ले प्रयोग गरेको केही भण्डारण उपलब्ध छैन। DVR लाई पुन: सक्षम पार्न कृपया तपाईँले पहिले प्रयोग गर्नुभएको बाह्य ड्राइभलाई जडान गर्नुहोस्। वैकल्पिक रूपमा, यदि अब भण्डारण उपलब्ध छैन भने तपाईँ त्यसलाई बिर्सने विकल्प छान्न सक्नुहुन्छ।"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"भण्डारण बिर्सने हो?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"तपाईँका रेकर्ड गरिएका सबै सामग्री र समय सहितका कार्यतालिकाहरू हराउने छन्।"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"रेकर्डिङ रोक्ने हो?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"रेकर्ड गरिएको सामग्रीलाई सुरक्षित गरिनेछ।"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"रेकर्डिङको कार्यतालिका निर्धारण गरिएको छ तर यसमा असहमतिहरू छन्"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"रेकर्डिङ सुरु भएको छ तर यसमा असहमतिहरू छन्"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> लाई रेकर्ड गरिनेछ।"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> लाई रेकर्ड गरिँदै छ।"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> का केही भागहरूलाई रेकर्ड गरिने छैन।"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> र <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> का केही भागहरूलाई रेकर्ड गरिने छैन।"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> र थप एक कार्यक्रमका केही भागहरूलाई रेकर्ड गरिने छैन।"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> र थप %3$d कार्यक्रमहरूलाई रेकर्ड गरिने छैन।</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> र थप %3$d कार्यक्रमलाई रेकर्ड गरिने छैन।</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"तपाईँ के रेकर्ड गर्न चाहनुहुन्छ?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"तपाईँ कति बेरसम्म रेकर्ड गर्न चाहनुहुन्छ?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"पहिले नै समय सहितको कार्यतालिका निर्धारण गरिएको छ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"यस कार्यक्रमलाई पहिले नै <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> मा रेकर्ड गर्न समय सहितको कार्यतालिका निर्धारण गरिएको छ।"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"पहिले नै रेकर्ड गरिएको छ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"यस कार्यक्रमलाई पहिले नै रेकर्ड गरिएको छ। यो DVR को लाइब्रेरीमा उपलब्ध छ।"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"रेकर्ड गरिएको कार्यक्रम भेट्टिएन।"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"सम्बन्धित रेकर्डिङहरू"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(कार्यक्रम सम्बन्धी वर्णन छैन)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d रेकर्डिङ</item>
+ <item quantity="one">%1$d रेकर्डिङ</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> लाई रेकर्डिङको समय सहितको कार्यतालिकाबाट हटाइयो"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ट्युनर सम्बन्धी असहमतिका कारण आंशिक रूपमा रेकर्ड गरिनेछ।"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ट्युनर सम्बन्धी असहमतिका कारण रेकर्ड गरिने छैन।"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"अहिलेसम्म समय सहितको कार्यतालिका निर्धारण गरिएको कुनै रेकर्डिङ छैन।\nतपाईँ कार्यक्रम निर्देशिका मार्फत रेकर्डिङको समय सहितको कार्यतालिका निर्धारण गर्न सक्नुहुन्छ।"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">रेकर्डिङ सम्बन्धी %1$d असहमतिहरू</item>
+ <item quantity="one">रेकर्डिङ सम्बन्धी %1$d असहमति</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"शृंखला सम्बन्धी सेटिङहरू"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"शृंखलाको रेकर्डिङ सुरु गर्नुहोस्"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"शृंखलाको रेकर्डिङ रोक्नुहोस्"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"शृंखलाको रेकर्डिङ रोक्ने हो?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"रेकर्ड गरिएका एपिसोडहरू DVR सम्बन्धी लाइब्रेरीमा उपलब्ध रहनेछन्।"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"रोक्नुहोस्"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"कुनै एपिसोड उपलब्ध छैन।\nएपिसोडहरू उपलब्ध भएपछि तिनीहरूलाई रेकर्ड गरिनेछ।"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d मिनेट)</item>
+ <item quantity="one">(%1$d मिनेट) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"आज"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"भोलि"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"हिजो"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"आज <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"भोलि <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"अङ्क"</string>
</resources>
diff --git a/res/values-nl/arrays.xml b/res/values-nl/arrays.xml
index 32ff2095..c2cd937e 100644
--- a/res/values-nl/arrays.xml
+++ b/res/values-nl/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Volledig"</item>
<item msgid="8568284598210500589">"Zoomen"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alle kanalen"</item>
- <item msgid="6897460857821394118">"Familie/kinderen"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Winkelen"</item>
- <item msgid="3296058637230163031">"Films"</item>
- <item msgid="1054540282883891201">"Comedy"</item>
- <item msgid="7900158429062595471">"Reizen"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Onderwijs"</item>
- <item msgid="7396447839483867269">"Dieren/natuur"</item>
- <item msgid="4738043455148062673">"Nieuws"</item>
- <item msgid="7405041316051047427">"Games"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alle kanalen"</item>
- <item msgid="7909003973960375395">"Familie/kinderen"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Winkelen"</item>
- <item msgid="6083795019290250078">"Films"</item>
- <item msgid="8302638329222449550">"Comedy"</item>
- <item msgid="3803709976021475052">"Reizen"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Onderwijs"</item>
- <item msgid="7511135485827589547">"Dieren/natuur"</item>
- <item msgid="6961248112238009967">"Nieuws"</item>
- <item msgid="6484685553679698447">"Games"</item>
- <item msgid="2737158328243183190">"Kunst"</item>
- <item msgid="6577176952650166615">"Entertainment"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Muziek"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Techniek/wetenschap"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alle kanalen"</item>
+ <item msgid="928298872841713530">"Familie/kinderen"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Winkelen"</item>
+ <item msgid="167201149441442173">"Films"</item>
+ <item msgid="525966731464264290">"Komedie"</item>
+ <item msgid="6096710741527327836">"Reizen"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Onderwijs"</item>
+ <item msgid="7221999662426308394">"Dieren/natuur"</item>
+ <item msgid="375300513250925001">"Nieuws"</item>
+ <item msgid="7746320336582330410">"Games"</item>
+ <item msgid="1255741860568329178">"Kunst"</item>
+ <item msgid="7603949681065702867">"Amusement"</item>
+ <item msgid="4453821994746804366">"Lifestyle"</item>
+ <item msgid="3488534597567932843">"Muziek"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Techniek/wetenschap"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Live tv"</item>
diff --git a/res/values-nl/rating_system_strings.xml b/res/values-nl/rating_system_strings.xml
index d3892685..c6819bc7 100644
--- a/res/values-nl/rating_system_strings.xml
+++ b/res/values-nl/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 151cbbcb..f24ed1c3 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Vorige"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programmagids"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Nieuwe kanalen beschikbaar"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Geen link beschikbaar"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Ondertiteling"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Weergavemodus"</string>
@@ -114,9 +113,9 @@
<string name="option_rating_medium" msgid="6455853836426497151">"Gem. beperkingen"</string>
<string name="option_rating_low" msgid="5800146024503377969">"Lage beperkingen"</string>
<string name="option_rating_custom" msgid="3155377834510646436">"Aangepast"</string>
- <string name="option_rating_high_description" msgid="609567565273278745">"Inhoud geschikt voor kinderen"</string>
- <string name="option_rating_medium_description" msgid="7169199016608935280">"Inhoud geschikt voor oudere kinderen"</string>
- <string name="option_rating_low_description" msgid="4740109576615335045">"Inhoud geschikt voor tieners"</string>
+ <string name="option_rating_high_description" msgid="609567565273278745">"Content geschikt voor kinderen"</string>
+ <string name="option_rating_medium_description" msgid="7169199016608935280">"Content geschikt voor oudere kinderen"</string>
+ <string name="option_rating_low_description" msgid="4740109576615335045">"Content geschikt voor tieners"</string>
<string name="option_rating_custom_description" msgid="6180723522991233194">"Handmatige beperkingen"</string>
<!-- no translation found for option_attribution (2967657807178951562) -->
<skip />
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subkijkwijzer"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Je pincode opgeven om dit kanaal te bekijken"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Je pincode opgeven om dit programma te bekijken"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Dit programma heeft de classificatie <xliff:g id="RATING">%1$s</xliff:g>. Geef je pincode op om dit programma te bekijken."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Je pincode opgeven"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Stel een pincode in om ouderlijk toezicht in te stellen"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Nieuwe pincode opgeven"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Open-sourcelicenties"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Open-sourcelicenties"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versie"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Helpen bij het verbeteren van Live kanalen"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Deel anonieme diagnostische en gebruiksgegevens met Google zodat we Live kanalen kunnen verbeteren en problemen, zoals crashen en vastlopen, kunnen voorkomen."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Als je dit kanaal wilt bekijken, druk je rechts en geef je je pincode op"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Als je dit programma wilt bekijken, druk je rechts en geef je je pincode op"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Dit programma is beoordeeld als <xliff:g id="RATING">%1$s</xliff:g>.\nAls je dit programma wilt bekijken, druk je rechts en geef je je pincode op."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Alleen audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Zwak signaal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Geen internetverbinding"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Dit kanaal kan tot <xliff:g id="END_TIME_1">%1$s</xliff:g> niet worden afgespeeld omdat er andere kanalen worden opgenomen. \n\nDruk op de pijl-rechts om de opnameplanning aan te passen.</item>
+ <item quantity="one">Dit kanaal kan tot <xliff:g id="END_TIME_0">%1$s</xliff:g> niet worden afgespeeld omdat er een ander kanaal wordt opgenomen. \n\nDruk op de pijl-rechts om de opnameplanning aan te passen.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Geen titel"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanaal geblokkeerd"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nieuw"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Geen kanalen beschikbaar"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nieuw"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Niet ingesteld"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Meer bronnen ophalen"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Browsen door apps die live kanalen aanbieden"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Meer bronnen ophalen"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Browsen door apps die live kanalen aanbieden"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Nieuwe kanaalbronnen beschikbaar"</string>
<string name="new_sources_description" msgid="749649005588426813">"Er zijn nieuwe kanaalbronnen die kanalen aanbieden.\nStel ze nu in of doe dit later via de instelling voor kanaalbronnen."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Nu instellen"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alle bronkanalen zijn verborgen.\nSelecteer ten minste één kanaal om te bekijken."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"De video is onverwacht niet beschikbaar"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"De toets TERUG is voor verbonden apparaten. Druk op de knop HOME om te sluiten."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"De app \'Live kanalen\' wordt niet ondersteund op dit apparaat met Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"De app \'Live kanalen\' heeft toestemming nodig om tv-vermeldingen te lezen."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Je bronnen configureren"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Live tv combineert de functionaliteit van traditionele tv-kanalen met streaming kanalen die worden geleverd door apps. \n\nJe kunt aan de slag gaan door de kanaalbronnen te configureren die al zijn geïnstalleerd. Of browse in de Google Play Store voor meer apps die live tv aanbieden."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Opnamen en planningen"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuten"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuten"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 uur"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 uur"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recent"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Gepland"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Overige"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Het kanaal kan niet worden opgenomen."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Het programma kan niet worden opgenomen."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> is ingepland voor opname"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> opnemen van nu tot <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Volledig schema"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Komende %1$d dagen</item>
+ <item quantity="one">Komende dag</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minuten</item>
+ <item quantity="one">%1$d minuut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nieuwe opnamen</item>
+ <item quantity="one">%1$d nieuwe opname</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d opnamen</item>
+ <item quantity="one">%1$d opname</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d opnamen gepland</item>
+ <item quantity="one">%1$d opname gepland</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Bekijken"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Afspelen vanaf het begin"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Afspelen hervatten"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Verwijderen"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Opnamen verwijderen"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Hervatten"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Seizoen <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Schema bekijken"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Meer informatie"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Opnamen verwijderen"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecteer de afleveringen die je wilt verwijderen. Ze kunnen na verwijdering niet worden hersteld."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Er zijn geen opnamen om te verwijderen."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Bekeken afleveringen selecteren"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Alle afleveringen selecteren"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Alle afleveringen deselecteren"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> van <xliff:g id="DURATION">%2$d</xliff:g> minuten bekeken"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> van <xliff:g id="DURATION">%2$d</xliff:g> seconden bekeken"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nooit bekeken"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d van %2$d afleveringen zijn verwijderd</item>
+ <item quantity="one">%1$d van %2$d aflevering is verwijderd</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioriteit"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Hoogste"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Laagste"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanalen"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Elke"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Prioriteit kiezen"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Wanneer er te veel programma\'s tegelijk moeten worden opgenomen, worden alleen de programma\'s met de hogere prioriteit opgenomen."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Opslaan"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Eenmalige opnamen krijgen de hoogste prioriteit"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Annuleren"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Annuleren"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Vergeten"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stoppen"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Opnameschema bekijken"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Dit afzonderlijke programma"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"nu - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Volledige serie…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Toch inplannen"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Dit programma opnemen"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Deze opname annuleren"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Nu bekijken"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kan worden opgenomen"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Opname gepland"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Opnameconflict"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Opnemen"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Opname mislukt"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Programma\'s lezen om opnameplanningen te maken"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Programma\'s lezen"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Voor DVR is meer opslagruimte nodig"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Je kunt programma\'s opnemen met DVR. Er is echter momenteel onvoldoende opslagruimte beschikbaar op je apparaat om DVR te gebruiken. Sluit een externe schijf aan die <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB of groter is en volg de stappen om deze te formatteren als apparaatopslag."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Opslag ontbreekt"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Een deel van de opslagruimte ontbreekt die door de DVR wordt gebruikt. Sluit de externe schijf aan die je eerder hebt gebruikt om DVR opnieuw in te schakelen. Je kunt er ook voor kiezen de opslagruimte te vergeten als deze niet langer beschikbaar is."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Opslag vergeten?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Al je opgenomen content en planningen gaan verloren."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Opname stoppen?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"De opgenomen content wordt opgeslagen."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Opname ingepland, maar heeft conflicten"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"De opname is gestart, maar heeft conflicten"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> wordt opgenomen."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> wordt opgenomen."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Sommige delen van <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> worden niet opgenomen."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Sommige delen van <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> en <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> worden niet opgenomen."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Sommige delen van <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> en nog één schema worden niet opgenomen."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Sommige delen van <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> en nog %3$d schema\'s worden niet opgenomen.</item>
+ <item quantity="one">Sommige delen van <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> en nog %3$d schema worden niet opgenomen.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Wat wil je opnemen?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hoe lang wil je opnemen?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Al ingepland"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Hetzelfde programma is al ingepland voor opname om <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Al opgenomen"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Dit programma is al opgenomen. Het is beschikbaar in de DVR-bibliotheek."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Opgenomen programma niet gevonden."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Gerelateerde opnamen"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Geen programmabeschrijving)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d opnamen</item>
+ <item quantity="one">%1$d opname</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" - "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> verwijderd uit het opnameschema"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Wordt gedeeltelijk opgenomen wegens tunerconflicten."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Wordt niet opgenomen wegens tunerconflicten."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Er zijn nog geen ingeplande opnamen.\nJe kunt opnamen inplannen vanuit de tv-gids."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d opnameconflicten</item>
+ <item quantity="one">%1$d opnameconflict</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Serie-instellingen"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Serie-opname starten"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Serie-opname stoppen"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Serie-opname stoppen?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Opgenomen afleveringen blijven beschikbaar in de DVR-bibliotheek."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stoppen"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Er zijn geen afleveringen beschikbaar.\nZe worden opgenomen zodra ze beschikbaar zijn."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minuten)</item>
+ <item quantity="one">(%1$d minuut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Vandaag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Morgen"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Gisteren"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> vandaag"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> morgen"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Score"</string>
</resources>
diff --git a/res/values-pl/arrays.xml b/res/values-pl/arrays.xml
index b8c3af9d..4dc517b9 100644
--- a/res/values-pl/arrays.xml
+++ b/res/values-pl/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Pełny"</item>
<item msgid="8568284598210500589">"Powiększenie"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Wszystkie kanały"</item>
- <item msgid="6897460857821394118">"Rodzina/dzieci"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Zakupy"</item>
- <item msgid="3296058637230163031">"Filmy"</item>
- <item msgid="1054540282883891201">"Komedie"</item>
- <item msgid="7900158429062595471">"Podróże"</item>
- <item msgid="3768998587825611787">"Dramaty"</item>
- <item msgid="8340620094959282881">"Edukacja"</item>
- <item msgid="7396447839483867269">"Zwierzęta/natura"</item>
- <item msgid="4738043455148062673">"Wiadomości"</item>
- <item msgid="7405041316051047427">"Gry"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Wszystkie kanały"</item>
- <item msgid="7909003973960375395">"Rodzina/dzieci"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Zakupy"</item>
- <item msgid="6083795019290250078">"Filmy"</item>
- <item msgid="8302638329222449550">"Komedie"</item>
- <item msgid="3803709976021475052">"Podróże"</item>
- <item msgid="8116747365234169059">"Dramaty"</item>
- <item msgid="7356447541595315913">"Edukacja"</item>
- <item msgid="7511135485827589547">"Zwierzęta/natura"</item>
- <item msgid="6961248112238009967">"Wiadomości"</item>
- <item msgid="6484685553679698447">"Gry"</item>
- <item msgid="2737158328243183190">"Sztuka"</item>
- <item msgid="6577176952650166615">"Rozrywka"</item>
- <item msgid="7886693831871777617">"Styl życia"</item>
- <item msgid="8145832312485577062">"Muzyka"</item>
- <item msgid="1345789204804308580">"Specjalne"</item>
- <item msgid="2736680312770771994">"Nauka i technika"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Wszystkie kanały"</item>
+ <item msgid="928298872841713530">"Rodzina/dzieci"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Zakupy"</item>
+ <item msgid="167201149441442173">"Filmy"</item>
+ <item msgid="525966731464264290">"Komedia"</item>
+ <item msgid="6096710741527327836">"Podróże"</item>
+ <item msgid="2851882187117833883">"Dramat"</item>
+ <item msgid="78492781188719038">"Edukacja"</item>
+ <item msgid="7221999662426308394">"Zwierzęta/natura"</item>
+ <item msgid="375300513250925001">"Wiadomości"</item>
+ <item msgid="7746320336582330410">"Gry"</item>
+ <item msgid="1255741860568329178">"Sztuka"</item>
+ <item msgid="7603949681065702867">"Rozrywka"</item>
+ <item msgid="4453821994746804366">"Styl życia"</item>
+ <item msgid="3488534597567932843">"Muzyka"</item>
+ <item msgid="7452153120614274095">"Specjalne"</item>
+ <item msgid="8215762047341133299">"Nauka i technika"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Telewizja online"</item>
diff --git a/res/values-pl/rating_system_strings.xml b/res/values-pl/rating_system_strings.xml
index cf0294bb..58f05f1b 100644
--- a/res/values-pl/rating_system_strings.xml
+++ b/res/values-pl/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index ede1b713..1e86cb7a 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Wstecz"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Przewodnik TV"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Dostępne są nowe kanały"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Brak linku"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Otwórz <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Napisy"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Tryb wyświetl."</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Oceny podrzędne"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Wpisz kod PIN, by oglądać ten kanał"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Wpisz kod PIN, by oglądać ten program"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Ten program ma ocenę <xliff:g id="RATING">%1$s</xliff:g>. Aby go obejrzeć, podaj kod PIN."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Wpisz kod PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Aby ustawić kontrolę rodzicielską, utwórz PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Wpisz nowy PIN"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licencje open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licencje open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Wersja"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Pomóż w ulepszaniu Telewizji online"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Udostępniaj Google anonimowe informacje o użytkowaniu i dane diagnostyczne, by pomóc w ulepszaniu Telewizji online i usuwaniu błędów takich jak np. zatrzymywanie obrazu."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Aby oglądać ten kanał, naciśnij Prawo i wpisz kod PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Aby oglądać ten program, naciśnij Prawo i wpisz kod PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ten program ma ocenę <xliff:g id="RATING">%1$s</xliff:g>.\nAby go oglądać, naciśnij Prawo i wpisz kod PIN"</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Tylko dźwięk"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Słaby sygnał"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Brak połączenia z internetem"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="few">Do <xliff:g id="END_TIME_1">%1$s</xliff:g> nie możesz oglądać tego kanału – przez ten czas będą nagrywane inne kanały. \n\nNaciśnij przycisk W prawo, by zmienić harmonogram nagrywania.</item>
+ <item quantity="many">Do <xliff:g id="END_TIME_1">%1$s</xliff:g> nie możesz oglądać tego kanału – przez ten czas będą nagrywane inne kanały. \n\nNaciśnij przycisk W prawo, by zmienić harmonogram nagrywania.</item>
+ <item quantity="other">Do <xliff:g id="END_TIME_1">%1$s</xliff:g> nie możesz oglądać tego kanału – przez ten czas będą nagrywane inne kanały. \n\nNaciśnij przycisk W prawo, by zmienić harmonogram nagrywania.</item>
+ <item quantity="one">Do <xliff:g id="END_TIME_0">%1$s</xliff:g> nie możesz oglądać tego kanału – przez ten czas będzie nagrywany inny kanał. \n\nNaciśnij przycisk W prawo, by zmienić harmonogram nagrywania.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Bez tytułu"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanał zablokowany"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nowe"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Brak dostępnych kanałów"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nowe"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nieskonfigurowany"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Poznaj inne źródła"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Przejrzyj aplikacje, które oferują telewizję online"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Poznaj inne źródła"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Przejrzyj aplikacje, które oferują telewizję online"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Dostępne są nowe źródła kanałów"</string>
<string name="new_sources_description" msgid="749649005588426813">"Dostępne są kanały oferowane przez nowe źródła kanałów.\nSkonfiguruj je teraz lub zrób to później w ustawieniu źródeł kanałów."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Skonfiguruj"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Wszystkie kanały źródłowe są ukryte.\nWybierz co najmniej jeden kanał do oglądania."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Sygnał wideo jest nieoczekiwanie niedostępny"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Klawisz BACK steruje podłączonym urządzeniem. Naciśnij przycisk HOME, by wyjść."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Telewizja online nie jest obsługiwana na tym urządzeniu z Androidem Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Aby odczytywać programy telewizyjne, Telewizja online potrzebuje uprawnień."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Skonfiguruj źródła"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Telewizja online to połączenie tradycyjnych kanałów TV i przesyłanych strumieniowo przez aplikacje.\n\nAby rozpocząć, skonfiguruj zainstalowane źródła kanałów. Możesz też przejrzeć Sklep Google Play, by znaleźć więcej aplikacji, które oferują dostęp do telewizji online."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Nagrywanie i harmonogramy"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minut"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minut"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 godzina"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 godziny"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Ostatnie"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Zaplanowane"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriale"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Inne"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Tego kanału nie można nagrać."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Tego programu nie można nagrać."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> został dodany do harmonogramu nagrywania"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Nagrywam program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> od teraz do <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Pełny harmonogram"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="few">Następne %1$d dni</item>
+ <item quantity="many">Następne %1$d dni</item>
+ <item quantity="other">Następne %1$d dnia</item>
+ <item quantity="one">Następny %1$d dzień</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="few">%1$d minuty</item>
+ <item quantity="many">%1$d minut</item>
+ <item quantity="other">%1$d minuty</item>
+ <item quantity="one">%1$d minuta</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="few">%1$d nowe nagrania</item>
+ <item quantity="many">%1$d nowych nagrań</item>
+ <item quantity="other">%1$d nowego nagrania</item>
+ <item quantity="one">%1$d nowe nagranie</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="few">%1$d nagrania</item>
+ <item quantity="many">%1$d nagrań</item>
+ <item quantity="other">%1$d nagrania</item>
+ <item quantity="one">%1$d nagranie</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="few">%1$d zaplanowane nagrania</item>
+ <item quantity="many">%1$d zaplanowanych nagrań</item>
+ <item quantity="other">%1$d zaplanowanego nagrania</item>
+ <item quantity="one">%1$d zaplanowane nagranie</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Obejrzyj"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Odtwórz od początku"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Wznów odtwarzanie"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Usuń"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Usuń nagrania"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Wznów"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Sezon <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Harmonogram"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Więcej informacji"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Usuń nagrania"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Wybierz odcinki, które chcesz usunąć. Po usunięciu nie będzie można ich odzyskać."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Brak nagrań do usunięcia."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Wybierz obejrzane odcinki"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Wybierz wszystkie odcink"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Odznacz wszystkie odcinki"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Obejrzano <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g> minut"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Obejrzano <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g> sekund"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nieobejrzane"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="few">%1$d odcinki %2$d z zostały usunięte</item>
+ <item quantity="many">%1$d odcinków z %2$d zostało usuniętych</item>
+ <item quantity="other">%1$d odcinka %2$d zostało usunięte</item>
+ <item quantity="one">%1$d odcinek z %2$d został usunięty</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorytet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Najwyższy"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Najniższy"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nr <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanały"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Dowolny"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Wybierz priorytet"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Jeśli wybierzesz za dużo programów do nagrania w tym samym czasie, nagrane zostaną tylko te o wyższych priorytetach."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Zapisz"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Nagrania jednorazowe mają najwyższy priorytet"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Anuluj"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Anuluj"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Zapomnij"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Zatrzymaj"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Pokaż harmonogram nagrywania"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Tylko ten program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"od teraz do <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Wszystkie odcinki…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Zaplanuj mimo to"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Nagraj to w zamian"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Anuluj to nagrywanie"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Obejrzyj teraz"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Można nagrać"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Zaplanowano nagrywanie"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflikt nagrywania"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Nagrywam"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Nie udało się nagrać"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Odczytuję programy, by utworzyć harmonogram nagrywania"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Odczytuję programy"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Nagrywarka DVR potrzebuje więcej miejsca"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Dzięki funkcji nagrywarki DVR możesz nagrywać programy, ale obecnie na urządzeniu jest za mało miejsca, by można było z niej korzystać. Podłącz dysk zewnętrzny o pojemności co najmniej <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB i postępuj zgodnie z instrukcjami, by sformatować go jako pamięć urządzenia."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Brak dostępu do pamięci"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Brak dostępu do części pamięci wykorzystywanej przez DVR. Podłącz dysk zewnętrzny, którego używasz, zanim włączysz DVR ponownie. Jeśli nie masz już tego dysku zewnętrznego, możesz go zapomnieć."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Zapomnieć pamięć nagrywarki?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Wszystkie zapisane treści i zaplanowane nagrania zostaną utracone."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Zatrzymać nagrywanie?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Nagrana treść zostanie zapisana."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Nagrywanie zostało zaplanowane, ale wystąpiły konflikty"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Zaczęło się nagrywanie, ale występują konflikty"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> zostanie nagrany."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> – trwa nagrywanie."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Niektóre fragmenty programu <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> nie zostaną nagrane."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Niektóre fragmenty programów <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> i <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> nie zostaną nagrane."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Niektóre fragmenty zaplanowanych do nagrania programów <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> i jeszcze jednego nie zostaną nagrane."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="few">Niektóre fragmenty zaplanowanych do nagrania programów <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> i %3$d innych nie zostaną nagrane.</item>
+ <item quantity="many">Niektóre fragmenty zaplanowanych do nagrania programów <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> i %3$d innych nie zostaną nagrane.</item>
+ <item quantity="other">Niektóre fragmenty zaplanowanych do nagrania programów <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> i %3$d innego nie zostaną nagrane.</item>
+ <item quantity="one">Niektóre fragmenty zaplanowanych do nagrania programów <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> i %3$d innego nie zostaną nagrane.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Co chcesz nagrać?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Jak długo chcesz nagrywać?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Już zaplanowane"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Nagrywanie tego samego programu zostało już zaplanowane na <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Już nagrany"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Ten program został już nagrany. Jest dostępny w bibliotece nagrywarki DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Nie znaleziono nagranego programu."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Powiązane nagrania"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Brak opisu programu)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="few">%1$d nagrania</item>
+ <item quantity="many">%1$d nagrań</item>
+ <item quantity="other">%1$d nagrania</item>
+ <item quantity="one">%1$d nagranie</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> został usunięty z harmonogramu nagrywania"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Zostanie nagrany częściowo z powodu konfliktów w tunerze."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Nie zostanie nagrany z powodu konfliktów w tunerze."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Żadne nagrywanie nie jest jeszcze zaplanowane.\nMożesz utworzyć harmonogram nagrywania, używając przewodnika po programach."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="few">%1$d konflikty nagrywania</item>
+ <item quantity="many">%1$d konfliktów nagrywania</item>
+ <item quantity="other">%1$d konfliktu nagrywania</item>
+ <item quantity="one">%1$d konflikt nagrywania</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Ustawienia nagrywania cyklicznego"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Zacznij nagrywanie cykliczne"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Zatrzymaj nagrywanie cykliczne"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Zatrzymać nagrywanie cykliczne?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Nagrane odcinki będą dostępne w bibliotece nagrywarki DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Zatrzymaj"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Brak dostępnych odcinków.\nZostaną one nagrane, gdy będą dostępne."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="few">(%1$d minuty)</item>
+ <item quantity="many">(%1$d minut)</item>
+ <item quantity="other">(%1$d minuty)</item>
+ <item quantity="one">(%1$d minuta) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Dzisiaj"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Jutro"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Wczoraj"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Dzisiaj, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Jutro, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Ocena"</string>
</resources>
diff --git a/res/values-pt-rPT/arrays.xml b/res/values-pt-rPT/arrays.xml
index 1514c1e0..d2249a07 100644
--- a/res/values-pt-rPT/arrays.xml
+++ b/res/values-pt-rPT/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Completo"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Todos os canais"</item>
- <item msgid="6897460857821394118">"Família/infantil"</item>
- <item msgid="551257741825778215">"Desporto"</item>
- <item msgid="452133796804325879">"Compras"</item>
- <item msgid="3296058637230163031">"Filmes"</item>
- <item msgid="1054540282883891201">"Comédia"</item>
- <item msgid="7900158429062595471">"Viagens"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Educação"</item>
- <item msgid="7396447839483867269">"Animais/vida selv."</item>
- <item msgid="4738043455148062673">"Notícias"</item>
- <item msgid="7405041316051047427">"Jogos"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Todos os canais"</item>
- <item msgid="7909003973960375395">"Família/infantil"</item>
- <item msgid="3185279732911635789">"Desporto"</item>
- <item msgid="4704858492065325964">"Compras"</item>
- <item msgid="6083795019290250078">"Filmes"</item>
- <item msgid="8302638329222449550">"Comédia"</item>
- <item msgid="3803709976021475052">"Viagens"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Educação"</item>
- <item msgid="7511135485827589547">"Animais/vida selv."</item>
- <item msgid="6961248112238009967">"Notícias"</item>
- <item msgid="6484685553679698447">"Jogos"</item>
- <item msgid="2737158328243183190">"Arte"</item>
- <item msgid="6577176952650166615">"Entretenimento"</item>
- <item msgid="7886693831871777617">"Estilo de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"Estreia"</item>
- <item msgid="2736680312770771994">"Tecnologia/ciência"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Todos os canais"</item>
+ <item msgid="928298872841713530">"Família/infantil"</item>
+ <item msgid="2751606947569857164">"Desporto"</item>
+ <item msgid="7345749789651321496">"Compras"</item>
+ <item msgid="167201149441442173">"Filmes"</item>
+ <item msgid="525966731464264290">"Comédia"</item>
+ <item msgid="6096710741527327836">"Viagens"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educação"</item>
+ <item msgid="7221999662426308394">"Animais/vida selv."</item>
+ <item msgid="375300513250925001">"Notícias"</item>
+ <item msgid="7746320336582330410">"Jogos"</item>
+ <item msgid="1255741860568329178">"Arte"</item>
+ <item msgid="7603949681065702867">"Entretenimento"</item>
+ <item msgid="4453821994746804366">"Estilo de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"Estreia"</item>
+ <item msgid="8215762047341133299">"Tecnologia/ciência"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canais em direto"</item>
diff --git a/res/values-pt-rPT/rating_system_strings.xml b/res/values-pt-rPT/rating_system_strings.xml
index 8a01a6c7..6d09040a 100644
--- a/res/values-pt-rPT/rating_system_strings.xml
+++ b/res/values-pt-rPT/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 61ec49d4..45fa4e20 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guia de programação"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Novos canais dispon."</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nenhum link disponível."</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Legendas"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Modo de apres."</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Subclassificações"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Introduzir o PIN para ver este canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Introduzir o PIN para ver este programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Este programa tem a classificação <xliff:g id="RATING">%1$s</xliff:g>. Introduza o PIN para ver este programa"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Introduzir o PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Para definir os controlos parentais, crie um PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Introduzir o novo PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licenças de código aberto"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licenças de código aberto"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versão"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Ajudar a melhorar a aplicação Canais em direto"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Partilhar dados de diagnóstico e de utilização anónimos com a Google para melhorar os Canais em Direto e evitar problemas, como falhas e bloqueios."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Para ver este canal, prima Direito e introduza o PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Para ver este programa, prima Direito e introduza o PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Este programa tem a classificação <xliff:g id="RATING">%1$s</xliff:g>.\nPara ver este programa, prima Direito e introduza o PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Apenas áudio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Sinal fraco"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Sem ligação à Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Não é possível reproduzir este canal até à(s) <xliff:g id="END_TIME_1">%1$s</xliff:g> porque estão a ser gravados outros canais. \n\nPrima para a direita para ajustar o horário de gravação.</item>
+ <item quantity="one">Não é possível reproduzir este canal até à(s) <xliff:g id="END_TIME_0">%1$s</xliff:g> porque está a ser gravado outro canal. \n\nPrima para a direita para ajustar o horário de gravação.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sem título"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal bloqueado"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nova"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nenhum canal disponível"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nova"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Não configurada"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Obter mais fontes"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Procurar aplicações que oferecem canais em direto"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Obter mais fontes"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Procurar aplicações que oferecem canais em direto"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Novas fontes de canais disponíveis"</string>
<string name="new_sources_description" msgid="749649005588426813">"Existem novas fontes de canais com canais disponíveis.\nConfigure-as agora ou efetue essa operação mais tarde na definição de fontes de canais."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurar agora"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Todos os canais de origem estão ocultos.\nSelecione pelo menos um canal para ver."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"O vídeo encontra-se inesperadamente não disponível"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"A tecla RETROCEDER destina-se ao dispositivo ligado. Prima o botão INÍCIO para sair."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"A aplicação Canais em direto não é compatível com este dispositivo com o Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"A aplicação Canais em direto necessita de autorização para ler as listagens de programas de TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configurar fontes"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Os canais em direto combinam a experiência dos canais de TV tradicionais com os canais de transmissão em fluxo contínuo fornecidos pelas aplicações. \n\nComece por configurar as fontes de canais já instaladas. Em alternativa, procure mais aplicações que ofereçam canais em direto na Google Play Store."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Gravações e agendamentos"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutos"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutos"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 horas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recentes"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Agendados"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Série"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Outros"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Não é possível gravar o canal."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Não é possível gravar o programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"O programa <xliff:g id="PROGRAMNAME">%1$s</xliff:g> foi agendado para gravação"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"A gravar <xliff:g id="PROGRAMNAME">%1$s</xliff:g> desde agora até às <xliff:g id="ENDTIME">%2$s</xliff:g>…"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Agenda completa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Próximos %1$d dias</item>
+ <item quantity="one">Próximo dia</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minutos</item>
+ <item quantity="one">%1$d minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d novas gravações</item>
+ <item quantity="one">%1$d nova gravação</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d gravações</item>
+ <item quantity="one">%1$d gravação</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d gravações agendadas</item>
+ <item quantity="one">%1$d gravação agendada</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Ver"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproduzir do início"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Retomar a reprodução"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Eliminar"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Eliminar gravações"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Retomar"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ver horários"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Ler mais"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Eliminar gravações"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecione os episódios que pretende eliminar. Depois da eliminação, não é possível recuperá-los."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Não existem gravações a eliminar."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Selecionar episódios vistos"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Selecionar todos os episódios"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Desselecionar todos os episódios"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> minutos vistos"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> segundos vistos"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nunca vistas"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d de %2$d episódios eliminados</item>
+ <item quantity="one">%1$d de %2$d episódio eliminado</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioridade"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Mais alta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Mais baixa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"N.º <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canais"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Qualquer"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Escolher prioridade"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Quando existem demasiados programas para serem gravados em simultâneo, apenas são gravados os programas com as prioridades mais altas."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Guardar"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"As gravações únicas têm a prioridade mais alta"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancelar"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancelar"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Esquecer"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Parar"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ver horários de gravação"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Este programa único"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"agora - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Toda a série..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Agendar mesmo assim"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Gravar antes este"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancelar esta gravação"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Ver agora"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Gravável"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Gravação agendada"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflito de gravação"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"A gravar"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Falha na gravação"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"A ler os programas para criar horários de gravação…"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"A ler os programas…"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"O DVR necessita de mais armazenamento"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Pode gravar programas com o DVR. Contudo, não existe neste momento armazenamento suficiente no dispositivo para que o DVR funcione. Ligue uma unidade externa que tenha, pelo menos, <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB e siga os passos para a formatar como armazenamento do dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Armazenamento em falta"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Algum do armazenamento utilizado pelo DVR está em falta. Ligue a unidade externa que utilizou anteriormente para reativar o DVR. Em alternativa, pode optar por esquecer o armazenamento se este já não estiver disponível."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Pretende esquecer o armazenamento?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Todos os seus conteúdos e agendamentos gravados serão perdidos."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Pretende parar a gravação?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"O conteúdo gravado será guardado."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Gravação agendada, mas com conflitos"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"A gravação foi iniciada, mas tem conflitos"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"O programa <xliff:g id="PROGRAMNAME">%1$s</xliff:g> será gravado."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"O canal <xliff:g id="CHANNELNAME">%1$s</xliff:g> está a ser gravado…"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> não serão gravadas."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> e de <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> não serão gravadas."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, de <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> e de mais um horário não serão gravadas."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, de <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> e de mais %3$d horários não serão gravadas.</item>
+ <item quantity="one">Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, de <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> e de mais %3$d horário não serão gravadas.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"O que gostaria de gravar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Durante quanto tempo pretende gravar?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Já agendado"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"O mesmo programa já foi agendado para ser gravado às <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Já gravado"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Este programa já foi gravado. Está disponível na biblioteca do DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programa gravado não encontrado."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Gravações relacionadas"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Sem descrição do programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d gravações</item>
+ <item quantity="one">%1$d gravação</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> removido da agenda de gravação"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Será parcialmente grav. devido a conflitos de sintonizador."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Não será gravado devido a conflitos de sintonizador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Ainda não existem gravações agendadas.\nPode agendar a gravação a partir do guia de programação."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d conflitos de gravação</item>
+ <item quantity="one">%1$d conflito de gravação</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Definições de séries"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Iniciar gravação da série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Parar gravação da série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Pretende parar a gravação da série?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Os episódios gravados ficam disponíveis na biblioteca do DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Parar"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Não existem episódios disponíveis.\nVão ser gravados assim que estiverem disponíveis."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minutos)</item>
+ <item quantity="one">(%1$d minuto) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hoje"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Amanhã"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ontem"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> de hoje"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> de amanhã"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Pontuação"</string>
</resources>
diff --git a/res/values-pt/arrays.xml b/res/values-pt/arrays.xml
index 9755f7e8..7aa5b446 100644
--- a/res/values-pt/arrays.xml
+++ b/res/values-pt/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Tela cheia"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Todos os canais"</item>
- <item msgid="6897460857821394118">"Família/crianças"</item>
- <item msgid="551257741825778215">"Esportes"</item>
- <item msgid="452133796804325879">"Compras"</item>
- <item msgid="3296058637230163031">"Filmes"</item>
- <item msgid="1054540282883891201">"Comédia"</item>
- <item msgid="7900158429062595471">"Viagem"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Educação"</item>
- <item msgid="7396447839483867269">"Anim./vida selvagem"</item>
- <item msgid="4738043455148062673">"Notícias"</item>
- <item msgid="7405041316051047427">"Jogos"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Todos os canais"</item>
- <item msgid="7909003973960375395">"Família/crianças"</item>
- <item msgid="3185279732911635789">"Esportes"</item>
- <item msgid="4704858492065325964">"Compras"</item>
- <item msgid="6083795019290250078">"Filmes"</item>
- <item msgid="8302638329222449550">"Comédia"</item>
- <item msgid="3803709976021475052">"Viagem"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Educação"</item>
- <item msgid="7511135485827589547">"Anim./vida selvagem"</item>
- <item msgid="6961248112238009967">"Notícias"</item>
- <item msgid="6484685553679698447">"Jogos"</item>
- <item msgid="2737158328243183190">"Artes"</item>
- <item msgid="6577176952650166615">"Entretenimento"</item>
- <item msgid="7886693831871777617">"Estilo de vida"</item>
- <item msgid="8145832312485577062">"Música"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Tecnologia/Ciência"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Todos os canais"</item>
+ <item msgid="928298872841713530">"Família/crianças"</item>
+ <item msgid="2751606947569857164">"Esportes"</item>
+ <item msgid="7345749789651321496">"Compras"</item>
+ <item msgid="167201149441442173">"Filmes"</item>
+ <item msgid="525966731464264290">"Comédia"</item>
+ <item msgid="6096710741527327836">"Viagem"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Educação"</item>
+ <item msgid="7221999662426308394">"Anim./vida selvagem"</item>
+ <item msgid="375300513250925001">"Notícias"</item>
+ <item msgid="7746320336582330410">"Jogos"</item>
+ <item msgid="1255741860568329178">"Artes"</item>
+ <item msgid="7603949681065702867">"Entretenimento"</item>
+ <item msgid="4453821994746804366">"Estilo de vida"</item>
+ <item msgid="3488534597567932843">"Música"</item>
+ <item msgid="7452153120614274095">"Alto nível"</item>
+ <item msgid="8215762047341133299">"Tecnologia/ciência"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canais ao vivo"</item>
diff --git a/res/values-pt/rating_system_strings.xml b/res/values-pt/rating_system_strings.xml
index 6a45f113..8852f80b 100644
--- a/res/values-pt/rating_system_strings.xml
+++ b/res/values-pt/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 9e1bb27f..9c22a58a 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Anterior"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Guia de programação"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Novos canais disponíveis"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Nenhum link disponível"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Closed captions"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Modo de exibiç."</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sub-classificações"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Digite seu PIN para assistir a este canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Digite seu PIN para assistir a este programa"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Este programa foi classificado como <xliff:g id="RATING">%1$s</xliff:g>. Digite seu PIN para assisti-lo"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Informe seu PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Para definir os controles para os pais, crie um PIN."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Inserir novo PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licenças de código aberto"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licenças de código aberto"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versão"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Ajudar a melhorar os Canais ao vivo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Compartilhar dados anônimos de uso e diagnóstico com o Google para que possamos melhorar os Canais ao vivo e evitar problemas, como falhas e congelamento."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Para assistir a este canal, pressione para a direita e digite o PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Para assistir a este programa, pressione para a direita e digite o PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Este programa foi classificado como <xliff:g id="RATING">%1$s</xliff:g>.\nPara assistir a este programa, pressione para a direita e digite o PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Somente áudio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Sinal fraco"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Sem conexão com a Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Não é possível reproduzir este canal até <xliff:g id="END_TIME_1">%1$s</xliff:g>, porque outro canal está sendo gravado. \n\nPressione o botão à direita para ajustar a programação de gravação.</item>
+ <item quantity="other">Não é possível reproduzir este canal até <xliff:g id="END_TIME_1">%1$s</xliff:g>, porque outros canais estão sendo gravados. \n\nPressione o botão à direita para ajustar a programação de gravação.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Sem título"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal bloqueado"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Novas"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nenhum canal disponível"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Novas"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Não configurada"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Adquirir mais fontes"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Procurar apps que ofereçam canais ao vivo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Adquirir mais fontes"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Procurar apps que ofereçam canais ao vivo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Novas fontes de canais disponíveis"</string>
<string name="new_sources_description" msgid="749649005588426813">"Novas fontes de canais têm canais para oferecer.\nConfigure-as agora ou faça isso mais tarde nas configurações de fontes de canais."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurar agora"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Todos os canais de origem estão ocultos.\nSelecione pelo menos um canal para assistir."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"O vídeo está inesperadamente indisponível"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"A tecla VOLTAR é para dispositivos conectados. Pressione o botão INÍCIO para sair."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"O app \"Canais ao vivo\" não é compatível com este dispositivo com Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"O app \"Canais ao vivo\" precisa de permissão para ler a programação de TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configurar suas fontes"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Os canais ao vivo combinam a experiência dos canais de TV tradicionais com canais de streaming fornecidos por apps. \n\nComece configurando as fontes de canais já instaladas ou procure na Google Play Store mais apps que ofereçam canais ao vivo."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Gravações e programações"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minutos"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minutos"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"Uma hora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"Três horas"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recentes"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programadas"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Série"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Outros"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Não é possível gravar o canal."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Não é possível gravar o programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"A gravação de <xliff:g id="PROGRAMNAME">%1$s</xliff:g> foi programada"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Gravação de <xliff:g id="PROGRAMNAME">%1$s</xliff:g> a partir de agora até <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programação completa"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Próximo %1$d dia</item>
+ <item quantity="other">Próximos %1$d dias</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minuto</item>
+ <item quantity="other">%1$d minutos</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d nova gravação</item>
+ <item quantity="other">%1$d novas gravações</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d gravação</item>
+ <item quantity="other">%1$d gravações</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d gravação programada</item>
+ <item quantity="other">%1$d gravações programadas</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Assistir"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Reproduzir do início"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Retomar reprodução"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Excluir"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Excluir gravações"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Retomar"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Temporada <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Ver programação"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Mais informações"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Excluir gravações"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selecione os episódios que você gostaria de excluir. Não é possível recuperá-los após a exclusão."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Não há nenhuma gravação para excluir."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Selecionar episódios assistidos"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Selecionar todos os episódios"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Desmarcar todos os episódios"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> minutos assistido(s)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> de <xliff:g id="DURATION">%2$d</xliff:g> segundos assistido(s)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nunca assistidas"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d de %2$d episódio foi excluído</item>
+ <item quantity="other">%1$d de %2$d episódios foram excluídos</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioridade"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Mais alta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Mais baixa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Não. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canais"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Qualquer"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Escolher prioridade"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Quando houver muitos programas a serem gravados ao mesmo tempo, apenas os com maior prioridade serão gravados."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Salvar"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Gravações únicas têm a maior prioridade"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Cancelar"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Cancelar"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Ignorar"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Parar"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ver programação de gravação"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Este único programa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"agora - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Toda a série…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programar mesmo assim"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Gravar este, e não o outro"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Cancelar esta gravação"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Assistir agora"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Pode ser gravado"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Gravação programada"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflito de gravação"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Gravação"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Falha na gravação"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Lendo programas para criar programações de gravação"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Lendo programas"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"O DVR precisa de mais armazenamento"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Você poderá gravar programas com DVR. No entanto, não há espaço de armazenamento suficiente no seu dispositivo no momento para que o DVR funcione. Conecte um drive externo que tenha <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB ou mais e siga as etapas para formatá-lo como um armazenamento do dispositivo."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Armazenamento ausente"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Alguns dos armazenamentos usados por DVR estão ausentes. Conecte o drive externo usado antes de reativar o DVR. Também é possível optar por esquecer o armazenamento se ele não estiver mais disponível."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Esquecer armazenamento?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Todo o conteúdo gravado e programações serão perdidos."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Interromper gravação?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"O conteúdo gravado será salvo."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Gravação programada, mas há conflitos"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"A gravação começou, mas há conflitos"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"O programa <xliff:g id="PROGRAMNAME">%1$s</xliff:g> será gravado."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"O canal <xliff:g id="CHANNELNAME">%1$s</xliff:g> está sendo gravado."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> não serão gravadas."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> e <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> não serão gravadas."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> e mais uma programação não serão gravadas."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> e mais %3$d programação não serão gravadas.</item>
+ <item quantity="other">Algumas partes de <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> e mais %3$d programações não serão gravadas.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"O que você gostaria de gravar?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Por quanto tempo você deseja gravar?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Já programado"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"A gravação do mesmo programa já foi programada para <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Já gravado"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Este programa já foi gravado. Ele está disponível na biblioteca de DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programa gravado não encontrado."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Gravações relacionadas"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"Nenhuma descrição do programa"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d gravação</item>
+ <item quantity="other">%1$d gravações</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> removido da programação de gravação"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Será parcialmente gravada devido a conflitos do sintoniz."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Não será gravada devido a conflitos do sintonizador."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Ainda não há gravações programadas.\nElas podem ser programadas a partir do guia de programação."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d conflito de gravação</item>
+ <item quantity="other">%1$d conflitos de gravação</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Configurações da série"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Iniciar gravação da série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Parar gravação da série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Parar gravação da série?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Os episódios gravados permanecerão disponíveis na biblioteca de DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Parar"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nenhum episódio disponível.\nOs episódios serão gravados quando estiverem disponíveis."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minuto)</item>
+ <item quantity="other">(%1$d minutos)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hoje"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Amanhã"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ontem"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> hoje"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> amanhã"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Pontuação"</string>
</resources>
diff --git a/res/values-ro/arrays.xml b/res/values-ro/arrays.xml
index 0c199ff9..60827ee9 100644
--- a/res/values-ro/arrays.xml
+++ b/res/values-ro/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Complet"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Toate canalele"</item>
- <item msgid="6897460857821394118">"Familie/Copii"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Cumpărături"</item>
- <item msgid="3296058637230163031">"Filme"</item>
- <item msgid="1054540282883891201">"Comedie"</item>
- <item msgid="7900158429062595471">"Călătorii"</item>
- <item msgid="3768998587825611787">"Dramă"</item>
- <item msgid="8340620094959282881">"Educație"</item>
- <item msgid="7396447839483867269">"Animale/Faună"</item>
- <item msgid="4738043455148062673">"Știri"</item>
- <item msgid="7405041316051047427">"Jocuri"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Toate canalele"</item>
- <item msgid="7909003973960375395">"Familie/Copii"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Cumpărături"</item>
- <item msgid="6083795019290250078">"Filme"</item>
- <item msgid="8302638329222449550">"Comedie"</item>
- <item msgid="3803709976021475052">"Călătorii"</item>
- <item msgid="8116747365234169059">"Dramă"</item>
- <item msgid="7356447541595315913">"Educație"</item>
- <item msgid="7511135485827589547">"Animale/Faună"</item>
- <item msgid="6961248112238009967">"Știri"</item>
- <item msgid="6484685553679698447">"Jocuri"</item>
- <item msgid="2737158328243183190">"Artă"</item>
- <item msgid="6577176952650166615">"Divertisment"</item>
- <item msgid="7886693831871777617">"Stil de viață"</item>
- <item msgid="8145832312485577062">"Muzică"</item>
- <item msgid="1345789204804308580">"Premiere"</item>
- <item msgid="2736680312770771994">"Tehnică/Știință"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Toate canalele"</item>
+ <item msgid="928298872841713530">"Familie/Copii"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Cumpărături"</item>
+ <item msgid="167201149441442173">"Filme"</item>
+ <item msgid="525966731464264290">"Comedie"</item>
+ <item msgid="6096710741527327836">"Călătorii"</item>
+ <item msgid="2851882187117833883">"Dramă"</item>
+ <item msgid="78492781188719038">"Educație"</item>
+ <item msgid="7221999662426308394">"Animale/Faună"</item>
+ <item msgid="375300513250925001">"Știri"</item>
+ <item msgid="7746320336582330410">"Jocuri"</item>
+ <item msgid="1255741860568329178">"Artă"</item>
+ <item msgid="7603949681065702867">"Divertisment"</item>
+ <item msgid="4453821994746804366">"Stil de viață"</item>
+ <item msgid="3488534597567932843">"Muzică"</item>
+ <item msgid="7452153120614274095">"Premiere"</item>
+ <item msgid="8215762047341133299">"Tehnică/Știință"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canale live"</item>
diff --git a/res/values-ro/rating_system_strings.xml b/res/values-ro/rating_system_strings.xml
index 67d3c309..0e5586bf 100644
--- a/res/values-ro/rating_system_strings.xml
+++ b/res/values-ro/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 82ff24ab..adc3b359 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Înapoi"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Ghid de programe"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Noi canale disponibile"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Niciun link disponibil"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Deschideți <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Subtitrări"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Mod de afișare"</string>
@@ -125,6 +124,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Clasif. secundare"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Introduceți codul PIN pentru a viziona acest canal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Introduceți codul PIN pt. a viziona acest program"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Acest program este evaluat cu <xliff:g id="RATING">%1$s</xliff:g>. Pentru a viziona programul, introduceți codul PIN"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Introduceți codul PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Pentru a seta controlul parental, creați un cod PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Introduceți un nou cod PIN"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licențe open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licențe open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versiune"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Contribuiți la îmbunătățirea aplicației „Canale live”"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Trimiteți la Google date anonime de utilizare și de diagnosticare pentru a îmbunătăți aplicația Canale live și pentru a preveni probleme cum ar blocarea."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Pentru a viziona acest canal, apăsați la dreapta și introduceți codul PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Pentru a viziona acest program, apăsați la dreapta și introduceți codul PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Acest program este clasificat ca <xliff:g id="RATING">%1$s</xliff:g>.\nPentru a viziona acest program, apăsați pe săgeata spre dreapta și introduceți codul PIN."</string>
@@ -159,6 +157,11 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Numai conținut audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Semnal slab"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Fără conexiune la internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="few">Acest canal nu poate fi redat înainte de <xliff:g id="END_TIME_1">%1$s</xliff:g>, deoarece sunt înregistrate alte canale. \n\nApăsați săgeata spre dreapta pentru a ajusta programul de înregistrare.</item>
+ <item quantity="other">Acest canal nu poate fi redat înainte de <xliff:g id="END_TIME_1">%1$s</xliff:g>, deoarece sunt înregistrate alte canale. \n\nApăsați săgeata spre dreapta pentru a ajusta programul de înregistrare.</item>
+ <item quantity="one">Acest canal nu poate fi redat înainte de <xliff:g id="END_TIME_0">%1$s</xliff:g>, deoarece este înregistrat un alt canal. \n\nApăsați săgeata spre dreapta pentru a ajusta programul de înregistrare.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Fără titlu"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Canal blocat"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Noi"</string>
@@ -171,8 +174,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Niciun canal disponibil"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nou"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Neconfigurată"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Găsiți mai multe surse"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Răsfoiți aplicațiile care oferă canale live"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Găsiți mai multe surse"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Răsfoiți aplicațiile care oferă canale live"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Sunt disponibile noi surse de canale"</string>
<string name="new_sources_description" msgid="749649005588426813">"Descoperiți canale din noile surse de canale.\nConfigurați-le acum sau mai târziu din setarea pentru sursele de canale."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Configurați acum"</string>
@@ -190,8 +193,172 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Toate canalele sursă sunt ascunse.\nSelectați cel puțin un canal pentru vizionare."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videoclipul este indisponibil în mod neașteptat"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Tasta BACK este pentru dispozitivul conectat. Apăsați pe butonul HOME pentru a ieși."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Aplicația „Canale live” nu este acceptată pe acest dispozitiv cu Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Aplicația „Canale live” are nevoie de permisiunea de a citi lista de programe TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Configurați sursele"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Canalele live combină experiența canalelor TV tradiționale cu cea a canalelor cu redare în flux, oferită de aplicații. \n\nÎncepeți prin a configura sursele canalelor care au fost deja instalate. Sau căutați în Magazinul Google Play mai multe aplicații care oferă canale live."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Înregistrări și programări"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minute"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 de minute"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 oră"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ore"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Recente"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programată"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriale"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Altele"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Canalul nu poate fi înregistrat."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Programul nu poate fi înregistrat."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> a fost programat pentru înregistrare"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Se înregistrează <xliff:g id="PROGRAMNAME">%1$s</xliff:g> de acum până la <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Programul complet"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="few">Următoarele %1$d zile</item>
+ <item quantity="other">Următoarele %1$d de zile</item>
+ <item quantity="one">Următoarea %1$d zi</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="few">%1$d minute</item>
+ <item quantity="other">%1$d de minute</item>
+ <item quantity="one">%1$d minut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="few">%1$d înregistrări noi</item>
+ <item quantity="other">%1$d de înregistrări noi</item>
+ <item quantity="one">%1$d înregistrare nouă</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="few">%1$d înregistrări</item>
+ <item quantity="other">%1$d de înregistrări</item>
+ <item quantity="one">%1$d înregistrare</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="few">%1$d înregistrări programate</item>
+ <item quantity="other">%1$d de înregistrări programate</item>
+ <item quantity="one">%1$d înregistrare programată</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Vizionați"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Redați de la început"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Reluați redarea"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Ștergeți"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Ștergeți înregistrările"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Reluați"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Sezonul <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Vedeți programul"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Aflați mai multe"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Ștergeți înregistrările"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Selectați episoadele pe care doriți să le ștergeți. Acestea nu pot fi recuperate după ce sunt șterse."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Nu există nicio înregistrare de șters."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Selectați episoadele vizionate"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Selectați toate episoadele"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Deselectați toate episoadele"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> din <xliff:g id="DURATION">%2$d</xliff:g> minute vizionate"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> din <xliff:g id="DURATION">%2$d</xliff:g> secunde vizionate"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Niciodată vizionate"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="few">Ați șters %1$d din %2$d episoade</item>
+ <item quantity="other">Ați șters %1$d din %2$d de episoade</item>
+ <item quantity="one">Ați șters %1$d din %2$d episod</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritate"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Cea mai mare"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Cea mai mică"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Numărul <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Canale"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Oricare"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Alegeți prioritatea"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Când există prea multe programe de înregistrat în același timp, vor fi înregistrate numai cele cu priorități mai mari."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Salvați"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Înregistrările unice au cea mai mare prioritate"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Anulați"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Anulați"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Eliminați"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Opriți"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Vedeți programul de înregistrare"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Numai acest program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"acum – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Întreaga serie…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Programați oricum"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Înregistrați acest program"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Anulați această înregistrare"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Vedeți acum"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Se poate înregistra"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Înregistrare programată"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Conflict privind înregistrarea"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Se înregistrează"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Nu s-a înregistrat"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Se citesc programele pentru crearea programărilor de înregistrare"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Se citesc programele"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR are nevoie de mai mult spațiu de stocare"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Veți putea înregistra programe folosind DVR. Cu toate acestea, momentan, pe dispozitiv nu există suficient spațiu de stocare ca să funcționeze DVR-ul. Conectați o unitate externă de cel puțin <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB și urmați pașii pentru a o formata ca stocare pe dispozitiv."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Stocare lipsă"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"O parte din stocarea folosită de DVR lipsește. Pentru a reactiva DVR, conectați unitatea externă folosită anterior. Dacă stocarea externă nu mai este disponibilă, puteți să o eliminați."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Eliminați stocarea?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tot conținutul înregistrat și toate programările vor fi șterse."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Opriți înregistrarea?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Conținutul înregistrat va fi salvat."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Înregistrarea a fost programată, dar există conflicte"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Înregistrarea a început, dar există conflicte"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> va fi înregistrat."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Se înregistrează <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Unele părți din <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> nu vor fi înregistrate."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Unele părți din <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> și din <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> nu vor fi înregistrate."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Unele părți din <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> și din încă un program nu vor fi înregistrate."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="few">Unele părți din <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> și din încă %3$d programe nu vor fi înregistrate.</item>
+ <item quantity="other">Unele părți din <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> și din încă %3$d de programe nu vor fi înregistrate.</item>
+ <item quantity="one">Unele părți din <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> și din încă %3$d program nu vor fi înregistrate.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ce doriți să înregistrați?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Cât timp doriți să înregistrați?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Programat deja"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Același program a fost programat deja pentru înregistrare la <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Înregistrat deja"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Acest program a fost înregistrat deja. Este disponibil în biblioteca DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Programul înregistrat nu a fost găsit."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Înregistrări conexe"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Nicio descriere de program)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="few">%1$d înregistrări</item>
+ <item quantity="other">%1$d de înregistrări</item>
+ <item quantity="one">%1$d înregistrare</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Din programul de înregistrare s-a eliminat <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Din cauza unor probleme de tuner, va fi înregistrat parțial."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Din cauza unor probleme de tuner, nu va fi înregistrat."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Nu există înregistrări programate încă.\nPuteți programa înregistrări din ghidul de programe."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="few">%1$d conflicte privind înregistrarea</item>
+ <item quantity="other">%1$d de conflicte privind înregistrarea</item>
+ <item quantity="one">%1$d conflict privind înregistrarea</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Setările seriei"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Începeți înregistrarea seriei"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Opriți înregistrarea seriei"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Opriți înregistrarea seriei?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Episoadele înregistrate vor rămâne disponibile în biblioteca DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Opriți"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nu există episoade disponibile.\nAcestea vor fi înregistrate de îndată ce vor fi disponibile."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="few">(%1$d minute)</item>
+ <item quantity="other">(%1$d de minute)</item>
+ <item quantity="one">(%1$d minut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Astăzi"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Mâine"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Ieri"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, astăzi"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g>, mâine"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Scor"</string>
</resources>
diff --git a/res/values-ru/arrays.xml b/res/values-ru/arrays.xml
index 549e0309..db7788bb 100644
--- a/res/values-ru/arrays.xml
+++ b/res/values-ru/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Панорамный"</item>
<item msgid="8568284598210500589">"Увеличение"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Все каналы"</item>
- <item msgid="6897460857821394118">"Для всей семьи"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Покупки"</item>
- <item msgid="3296058637230163031">"Фильмы"</item>
- <item msgid="1054540282883891201">"Комедии"</item>
- <item msgid="7900158429062595471">"Путешествия"</item>
- <item msgid="3768998587825611787">"Драмы"</item>
- <item msgid="8340620094959282881">"Образование"</item>
- <item msgid="7396447839483867269">"Природа и животные"</item>
- <item msgid="4738043455148062673">"Новости"</item>
- <item msgid="7405041316051047427">"Игры"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Все каналы"</item>
- <item msgid="7909003973960375395">"Для всей семьи"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Покупки"</item>
- <item msgid="6083795019290250078">"Фильмы"</item>
- <item msgid="8302638329222449550">"Комедии"</item>
- <item msgid="3803709976021475052">"Путешествия"</item>
- <item msgid="8116747365234169059">"Драмы"</item>
- <item msgid="7356447541595315913">"Образование"</item>
- <item msgid="7511135485827589547">"Природа и животные"</item>
- <item msgid="6961248112238009967">"Новости"</item>
- <item msgid="6484685553679698447">"Игры"</item>
- <item msgid="2737158328243183190">"Искусство"</item>
- <item msgid="6577176952650166615">"Развлечения"</item>
- <item msgid="7886693831871777617">"Стиль жизни"</item>
- <item msgid="8145832312485577062">"Музыка"</item>
- <item msgid="1345789204804308580">"Новинки"</item>
- <item msgid="2736680312770771994">"Наука и техника"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Все каналы"</item>
+ <item msgid="928298872841713530">"Для всей семьи"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Покупки"</item>
+ <item msgid="167201149441442173">"Фильмы"</item>
+ <item msgid="525966731464264290">"Юмор"</item>
+ <item msgid="6096710741527327836">"Путешествия"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Образование"</item>
+ <item msgid="7221999662426308394">"Природа и животные"</item>
+ <item msgid="375300513250925001">"Новости"</item>
+ <item msgid="7746320336582330410">"Компьютерные игры"</item>
+ <item msgid="1255741860568329178">"Искусство"</item>
+ <item msgid="7603949681065702867">"Развлечения"</item>
+ <item msgid="4453821994746804366">"Стиль жизни"</item>
+ <item msgid="3488534597567932843">"Музыка"</item>
+ <item msgid="7452153120614274095">"Новинки"</item>
+ <item msgid="8215762047341133299">"Наука и техника"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Каналы Live"</item>
diff --git a/res/values-ru/rating_system_strings.xml b/res/values-ru/rating_system_strings.xml
index e88eba47..a5832f29 100644
--- a/res/values-ru/rating_system_strings.xml
+++ b/res/values-ru/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index d7ac09e2..61bef1f6 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Предыдущий"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Телегид"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Доступны новые каналы"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ссылка не найдена"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Открыть приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Субтитры"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Режим"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Доп. ограничения"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Введите PIN-код, чтобы посмотреть этот канал"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Введите PIN-код, чтобы посмотреть эту программу"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Возрастное ограничение для этой программы: <xliff:g id="RATING">%1$s</xliff:g>. Чтобы посмотреть ее, введите PIN-код."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Введите PIN-код"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Чтобы установить родительский контроль, создайте PIN-код"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Введите новый PIN-код"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Лицензии открытого ПО"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Лицензии открытого ПО"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Версия"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Не помогать улучшить \"Прямой эфир\""</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Разрешите отправку анонимных отчетов об использовании и данных диагностики в Google, чтобы мы могли улучшить работу Телеканалов и устранить сбои и зависания."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Чтобы смотреть этот канал, нажмите стрелку вправо и введите PIN-код."</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Чтобы смотреть эту программу, нажмите стрелку вправо и введите PIN-код."</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Возрастное ограничение этой программы: <xliff:g id="RATING">%1$s</xliff:g>.\nЧтобы посмотреть ее, нажмите на стрелку вправо и введите PIN-код."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Только аудио"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Слабый сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Нет доступа к Интернету"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Невозможно включить этот канал до <xliff:g id="END_TIME_1">%1$s</xliff:g>, поскольку тюнер используется для записи других каналов. \n\nЧтобы изменить расписание записи, нажмите стрелку вправо.</item>
+ <item quantity="few">Невозможно включить этот канал до <xliff:g id="END_TIME_1">%1$s</xliff:g>, поскольку тюнер используется для записи других каналов. \n\nЧтобы изменить расписание записи, нажмите стрелку вправо.</item>
+ <item quantity="many">Невозможно включить этот канал до <xliff:g id="END_TIME_1">%1$s</xliff:g>, поскольку тюнер используется для записи других каналов. \n\nЧтобы изменить расписание записи, нажмите стрелку вправо.</item>
+ <item quantity="other">Невозможно включить этот канал до <xliff:g id="END_TIME_1">%1$s</xliff:g>, поскольку тюнер используется для записи других каналов. \n\nЧтобы изменить расписание записи, нажмите стрелку вправо.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Без названия"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Канал заблокирован"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Новые"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Каналы недоступны"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Новое"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Не настроенные"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Другие источники"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Находите приложения, позволяющие смотреть телеканалы в прямом эфире"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Другие источники"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Искать приложения, позволяющие смотреть телеканалы в прямом эфире"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Новые источники каналов"</string>
<string name="new_sources_description" msgid="749649005588426813">"Доступны новые источники каналов.\nИх можно настроить сейчас или позже (через меню настроек)."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Настроить"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Все каналы скрыты.\nВыберите хотя бы один."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Видео недоступно из-за непредвиденной ошибки"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Кнопка \"Назад\" управляет подключенным устройством. Чтобы выйти, нажмите \"Главный экран\"."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Прямой эфир не поддерживается на этом устройстве с Android 5.0."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Требуется разрешение для чтения телепрограмм."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Настройте источники каналов"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Каналы Live – это сочетание обычных телеканалов и потоковых видеотрансляций, идущих через установленные приложения.\n\nНачните с настройки уже имеющихся источников контента или найдите в Play Маркете другие медиаприложения."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Записи и расписание"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 мин."</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 мин."</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ч."</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ч."</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Недавние"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"По расписанию"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Сериалы"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Другие"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Не удается записать канал"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Не удается записать программу"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Программа \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" будет записана"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Запись программы \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" с данного момента до <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Полное расписание"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <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="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <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="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <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="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <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="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <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="dvr_detail_watch" msgid="7085694764364338215">"Смотреть"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Смотреть с начала"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Продолжить просмотр"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Удалить"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Удалить записи"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Продолжить"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Расписание"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Подробнее"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Удаление записей"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Выберите серии, которые нужно удалить. Их нельзя будет восстановить."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Нет записей, которые можно удалить"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Выбрать просмотренные серии"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Выбрать все серии"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Отменить выбор всех серий"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Просмотрено: <xliff:g id="WATCHED">%1$d</xliff:g> из <xliff:g id="DURATION">%2$d</xliff:g> мин."</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Просмотрено: <xliff:g id="WATCHED">%1$d</xliff:g> из <xliff:g id="DURATION">%2$d</xliff:g> сек."</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Непросмотренные"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">Удалено серий: %1$d из %2$d</item>
+ <item quantity="few">Удалено серий: %1$d из %2$d</item>
+ <item quantity="many">Удалено серий: %1$d из %2$d</item>
+ <item quantity="other">Удалено серий: %1$d из %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Приоритет"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Самый высокий"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Самый низкий"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Нет (<xliff:g id="RANK">%1$d</xliff:g>)"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Каналы"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Любой"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Выберите приоритет"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Если вы выберете слишком много программ для одновременной записи, будут записываться только те, у которых наивысший приоритет."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Сохранить"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Однократная запись имеет самый высокий приоритет"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Отмена"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Отмена"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Удалить"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Остановить"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Смотреть расписание записи"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Только эту серию"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"Начало: сейчас; окончание: <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Все серии…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Все равно записать"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Записать эту программу"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Отменить эту запись"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Смотреть"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Можно записать"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Таймер записи установлен"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Конфликт таймера записи"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Идет запись"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Ошибка записи видео"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Выполняется чтение программ. Будет создано расписание записи."</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Выполняется чтение программ…"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Недостаточно места на устройстве"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Вы сможете записывать программы на DVR, однако в настоящее время на вашем устройстве недостаточно места. Подключите внешний накопитель объемом не менее <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> ГБ и отформатируйте его как память устройства."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Хранилище отсутствует"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Хранилище не найдено. Подсоедините внешний диск, прежде чем снова включить видеомагнитофон, либо удалите хранилище, если оно недоступно."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Удалить хранилище?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Все созданные и запланированные записи будут стерты."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Остановить запись?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Записанный контент будет сохранен."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Возник конфликт в расписании записи"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Возник конфликт в расписании записи"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Программа \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" будет записана."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Видео с канала \"<xliff:g id="CHANNELNAME">%1$s</xliff:g>\" записывается"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Программа \"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>\" запишется лишь частично."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Программы \"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\" и \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" запишутся лишь частично."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"\"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" и ещё одна программа запишутся лишь частично."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">\"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" и ещё %3$d программа запишутся лишь частично.</item>
+ <item quantity="few">\"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" и ещё %3$d программы запишутся лишь частично.</item>
+ <item quantity="many">\"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" и ещё %3$d программ запишутся лишь частично.</item>
+ <item quantity="other">\"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" и ещё %3$d программы запишутся лишь частично.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Что записать?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Как долго нужно записывать?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Запись уже запланирована"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Запись этой программы уже запланирована на <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Программа уже записана"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Эта программа сохранена в библиотеке видеорекордера."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Записанная программа не найдена."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Похожие записи"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(без описания)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <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="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Удалено из расписания записи: <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Будет записана только часть: отсутствует тюнер."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Невозможно сделать запись: отсутствует тюнер."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"В расписании пока пусто.\nВы можете запланировать запись из телегида."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <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="dvr_series_schedules_settings" msgid="4868501926847903985">"Настроить запись серий"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Начать запись"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Остановить запись"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Остановить запись?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Записанные серии будут сохранены в библиотеке видеорекордера."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Остановить"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Серий пока нет.\nОни будут записаны, как только выйдут в эфир."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <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="dvr_date_today" msgid="7691050705354303471">"Cегодня"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Завтра"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Вчера"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Сегодня, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Завтра, <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Оценка"</string>
</resources>
diff --git a/res/values-si-rLK/arrays.xml b/res/values-si-rLK/arrays.xml
index 363153c5..657fb91d 100644
--- a/res/values-si-rLK/arrays.xml
+++ b/res/values-si-rLK/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"පූර්ණ"</item>
<item msgid="8568284598210500589">"විශාලනය කරන්න"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"සියලු නාලිකා"</item>
- <item msgid="6897460857821394118">"පවුල/ළමයින්"</item>
- <item msgid="551257741825778215">"ක්‍රීඩා"</item>
- <item msgid="452133796804325879">"සාප්පු යාම"</item>
- <item msgid="3296058637230163031">"චිත්‍රපට"</item>
- <item msgid="1054540282883891201">"විකට"</item>
- <item msgid="7900158429062595471">"සංචාර"</item>
- <item msgid="3768998587825611787">"නාට්‍ය"</item>
- <item msgid="8340620094959282881">"අධ්‍යාපනය"</item>
- <item msgid="7396447839483867269">"සතුන්/වනසතුන්"</item>
- <item msgid="4738043455148062673">"ප්‍රවෘත්ති"</item>
- <item msgid="7405041316051047427">"ක්‍රීඩා"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"සියලු නාලිකා"</item>
- <item msgid="7909003973960375395">"පවුල/ළමයින්"</item>
- <item msgid="3185279732911635789">"ක්‍රීඩා"</item>
- <item msgid="4704858492065325964">"සාප්පු යාම"</item>
- <item msgid="6083795019290250078">"චිත්‍රපට"</item>
- <item msgid="8302638329222449550">"විකට"</item>
- <item msgid="3803709976021475052">"සංචාර"</item>
- <item msgid="8116747365234169059">"නාට්‍ය"</item>
- <item msgid="7356447541595315913">"අධ්‍යාපනය"</item>
- <item msgid="7511135485827589547">"සතුන්/වනසතුන්"</item>
- <item msgid="6961248112238009967">"ප්‍රවෘත්ති"</item>
- <item msgid="6484685553679698447">"ක්‍රීඩා"</item>
- <item msgid="2737158328243183190">"කලාව"</item>
- <item msgid="6577176952650166615">"විනෝදාස්වාදය"</item>
- <item msgid="7886693831871777617">"ජීවන රටාව"</item>
- <item msgid="8145832312485577062">"සංගීතය"</item>
- <item msgid="1345789204804308580">"ප්‍රිමියර්"</item>
- <item msgid="2736680312770771994">"තාක්ෂණය/විද්‍යාව"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"සියළුම නාලිකා"</item>
+ <item msgid="928298872841713530">"පවුල/ළමයින්"</item>
+ <item msgid="2751606947569857164">"ක්‍රීඩා"</item>
+ <item msgid="7345749789651321496">"සාප්පුයාම"</item>
+ <item msgid="167201149441442173">"චිත්‍රපට"</item>
+ <item msgid="525966731464264290">"විකට"</item>
+ <item msgid="6096710741527327836">"සංචාර"</item>
+ <item msgid="2851882187117833883">"නාට්‍ය"</item>
+ <item msgid="78492781188719038">"අධ්‍යාපනය"</item>
+ <item msgid="7221999662426308394">"සතුන්/වනසතුන්"</item>
+ <item msgid="375300513250925001">"ප්‍රවෘත්ති"</item>
+ <item msgid="7746320336582330410">"වීඩියෝ ක්‍රීඩා"</item>
+ <item msgid="1255741860568329178">"කලාව"</item>
+ <item msgid="7603949681065702867">"විනෝදාස්වාදය"</item>
+ <item msgid="4453821994746804366">"ජීවන රටාව"</item>
+ <item msgid="3488534597567932843">"සංගීත"</item>
+ <item msgid="7452153120614274095">"ප්‍රමුඛ"</item>
+ <item msgid="8215762047341133299">"තාක්ෂණය/විද්‍යාව"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"සජීවී නාලිකා"</item>
diff --git a/res/values-si-rLK/rating_system_strings.xml b/res/values-si-rLK/rating_system_strings.xml
index ebb26549..f22044ba 100644
--- a/res/values-si-rLK/rating_system_strings.xml
+++ b/res/values-si-rLK/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-si-rLK/strings.xml b/res/values-si-rLK/strings.xml
index 47b69c8e..eab8c336 100644
--- a/res/values-si-rLK/strings.xml
+++ b/res/values-si-rLK/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"පෙර"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"වැඩසටහන් නියාමකය"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"නව නාලිකා දැන් තිබේ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"සබැඳිය ලබාගත නොහැක"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> විවෘත කරන්න"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"වසන ලද ශිර්ෂ"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"දර්ශන ආකාරය"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"උප-ඇගයීම්"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"මෙම නාලිකාව නැරඹිමට ඔබගේ PIN එක ඇතුළු කරන්න"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"මෙම වැඩසටහන නැරඹිමට ඔබගේ PIN එක ඇතුළු කරන්න"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"මෙම වැඩසටහන <xliff:g id="RATING">%1$s</xliff:g> ඇගයුම ලබා ඇත. මෙම වැඩසටහන නැරඹිමට ඔබගේ PIN එක ඇතුළු කරන්න"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"ඔබගේ PIN එක ඇතුළු කරන්න"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"මව්පිය පාලකයක් සකසන්න, PIN එකක් සාදන්න"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"අලුත් PIN එක ඇතුළු කරන්න"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"විවෘත මූලාශ්‍ර බලපත්‍ර"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"විවෘත මූලාශ්‍ර වරපත්"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"අනුවාදය"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"සජීවි නාලිකා වැඩි දියුණු කිරීමට උදව් කරන්න"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Google සමග නිර්නාමික භාවිත සහ දෝෂ නිර්ණ දත්ත බෙදා ගන්න, එවිට අපට සජීවී නාලිකා වඩාත් යහපත් කිරීමට සහ බිඳ වැටීම් සහ සිරවීම් වැනි ගැටලු වැළැක්වීමට හැකිය."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"මෙම නාලිකාව නැරඹිමට දකුණ ඔබා PIN එක ඇතුළු කරන්න"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"මෙම වැඩසටහන නැරඹිමට දකුණ ඔබා PIN එක ඇතුළු කරන්න"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"මෙම වැඩසටහන <xliff:g id="RATING">%1$s</xliff:g> අගයන ලදි.\nමෙම වැඩසටහන නැරඹීමට දකුණ ඔබා ඔබගේ PIN එක ඇතුළු කරන්න."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ශ්‍රව්‍ය පමණයි"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"දුර්වල සංඥාව"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"අන්තර්ජාල සබැඳුමක් නැත"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">වෙනත් නාලිකා පටිගත වෙමින් ඇති නිසා මෙම නාලිකාව <xliff:g id="END_TIME_1">%1$s</xliff:g> වනතෙක් ධාවනය කළ නොහැකිය. \n\nපටිගත කිරීමේ කාල සටහන සීරුමාරු කිරීමට දකුණ ඔබන්න.</item>
+ <item quantity="other">වෙනත් නාලිකා පටිගත වෙමින් ඇති නිසා මෙම නාලිකාව <xliff:g id="END_TIME_1">%1$s</xliff:g> වනතෙක් ධාවනය කළ නොහැකිය. \n\nපටිගත කිරීමේ කාල සටහන සීරුමාරු කිරීමට දකුණ ඔබන්න.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"මාතෘකාවක් නොමැත"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"නාලිකාව අවහිර කරන ලදි"</string>
<string name="setup_category_new" msgid="2899355289563443627">"නව"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ලබා ගත හැකි නාලිකා නැත"</string>
<string name="setup_input_new" msgid="3337725672277046798">"නව"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"සකසා නැත"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"තවත් මූලාශ්‍ර ලබා ගන්න"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"සජීවී නාලිකා පිරිනමන යෙදුම් බ්‍රවුස් කරන්න"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"තවත් මූලාශ්‍ර ලබා ගන්න"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"සජීව නාලිකා පිරිනමන යෙදුම් බ්‍රවුස් කරන්න"</string>
<string name="new_sources_title" msgid="3878933676500061895">"නව නාලිකා මූලාශ්‍ර ලබා ගත හැකිය"</string>
<string name="new_sources_description" msgid="749649005588426813">"නව නාලිකා මූලාශ්‍රවලට පිරිනැමීමට නාලිකා ඇත.\nඒවා දැන් පිහිටුවන්න, නැතහොත් මෙය පසුව නාලිකා මූලාශ්‍ර සැකසීම තුළ සිදු කරන්න."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"දැන් පිහිටුවන්න"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"සියලුම මූල නාලිකා සඟවන ලදි.\nනැරඹීමට අඩුම තරමේ එක නාලිකාවක් වත් තෝරන්න."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"වීඩියෝව බලාපොරොත්තු නොවූ ලෙස නොතිබේ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"සම්බන්ධිත උපාංගය සඳහා BACK යතුර. පිටවීමට Home බොත්තම ඔබන්න."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop සමගින් සජීවී නාලිකා මෙම උපාංගය මත සහාය නොදක්වයි."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"සජීවී නාලිකාවලට TV ලැයිස්තුගත කිරීම් කියවීමට අවසරය අවශ්‍යයි."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"ඔබගේ මූලාශ්‍ර පිහිටුවන්න"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"සජීවී නාලිකා සම්ප්‍රදායික TV නාලිකාවල අත්දැකීම යෙදුම්වලින් සපයන ප්‍රවාහ කිරීමේ නාලිකා සමග ඒකාබද්ධ කරයි. \n\nදැනටමත් ස්ථාපනය කර ඇති නාලිකා මූලාශ්‍ර පිහිටුවීමෙන් ආරම්භ කරන්න. නැතහොත් සජීවී නාලිකා පිරිනමන තවත් යෙදුම් සඳහා Google Play Store බ්‍රවුස් කරන්න."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"පටිගත කිරීම් සහ කාලසටහන්"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"මිනිත්තු 10"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"මිනිත්තු 30"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"පැය 1"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"පැය 3"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"මෑත"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"නියමිත"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"මාලා"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"වෙනත්"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"නාලිකාව පටිගත කළ නොහැකිය."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"වැඩසටහන පටිගත කළ නොහැකිය."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> පටිගත කිරීමට කාල සටහන්ගත කර ඇත"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> දැන් සිට <xliff:g id="ENDTIME">%2$s</xliff:g> දක්වා පටිගත කරමින්"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"සම්පූර්ණ කාල සටහන"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">ඊළඟ දින %1$d</item>
+ <item quantity="other">ඊළඟ දින %1$d</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">මිනිත්තු %1$d</item>
+ <item quantity="other">මිනිත්තු %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">නව පටිගත කිරීම් %1$d</item>
+ <item quantity="other">නව පටිගත කිරීම් %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">පටිගත කිරීම් %1$d</item>
+ <item quantity="other">පටිගත කිරීම් %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">පටිගත කිරීම් %1$dක් කාලසටහන්ගත කර ඇත</item>
+ <item quantity="other">පටිගත කිරීම් %1$dක් කාලසටහන්ගත කර ඇත</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ඔරලෝසුව"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"මුල සිට ධාවනය කරන්න"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ධාවනය නැවත පටන් ගැනීම"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"මකන්න"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"පටිගත කිරීම් මකන්න"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"නැවත පටන්ගන්න"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"වෙළුම <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"කාල සටහන බලන්න"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"තව කියවන්න"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"පටිගත කිරීම් මකන්න"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"ඔබ මැකීමට කැමති කථාංග තෝරන්න. වරක් මැකූ පසු ඒවා ප්‍රතිසාධනය කළ නොහැකිය."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"මැකීමට පටිගත කිරීම් නැත."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"නැරඹූ කථාංග තෝරන්න"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"සියලු කථාංග තෝරන්න"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"සියලු කථාංග තේරීම ඉවත් කරන්න"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"මිනිත්තු <xliff:g id="DURATION">%2$d</xliff:g>කින් <xliff:g id="WATCHED">%1$d</xliff:g>ක් නරඹන ලදී"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"තත්පර <xliff:g id="DURATION">%2$d</xliff:g>කින් <xliff:g id="WATCHED">%1$d</xliff:g>ක් නරඹන ලදී"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"කිසිදා නරඹා නැත"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">කථාංග %2$dකින් %1$dක් මකා ඇත</item>
+ <item quantity="other">කථාංග %2$dකින් %1$dක් මකා ඇත</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ප්‍රමුඛතාව"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"වැඩිම"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"අඩුම"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"නැත. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"නාලිකා"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ඕනෑම"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ප්‍රමුඛතාව තේරීම"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"එකම අවස්ථාවේදී පටිගත කිරීමට ප්‍රමාණයට වඩා වැඩි වැඩසටහන් ගණන් ඇති විට, වඩා ඉහළ ප්‍රමුඛතා සහිත ඒවා පමණක් පටිගත කරනු ඇත."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"සුරකින්න"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"එක්-වරක පටිගත කිරීම්වලට වැඩිම ප්‍රමුඛතාව ඇත"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"අවලංගු කර."</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"අවලංගු කරන්න"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"අමතක කරන්න"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"නතර කරන්න"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"පටිගත කිරීමේ කාල සටහන බලන්න"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"මෙම තනි වැඩසටහන"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"දැන් - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"මුළු මාලාව…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"කෙසේ වෙතත් කාල සටහන්ගත කරන්න"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"ඒ වෙනුවට මෙය පටිගත කරන්න"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"මෙම පටිගත කිරීම අවලංගු කරන්න"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"දැන් නරඹන්න"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"පටිගත කළ හැකි"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"පටිගත කිරීම කාල සටහන්ගතයි"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"පටිගත කිරීමේ ගැටුම"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"පටිගත කරමින්"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"පටිගත කිරීම අසාර්ථක විය"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"පටිගත කිරීමේ කාලසටහන් සෑදීමට වැඩසටහන් කියවමින්"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"කියවීමේ වැඩසටහන්"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR සඳහා වැඩිපුර ගබඩාව අවශ්‍යයි"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"ඔබට DVR සමගින් වැඩසටහන් පටිගත කිරීමට හැකි වනු ඇත. කෙසේ වෙතත් දැන් DVR ක්‍රියා කිරීම සඳහා ඔබේ උපාංගයේ ප්‍රමාණවත් තරම් ගබඩාව නැත. කරුණාකර <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB හෝ ඊට වඩා විශාල බාහිර ධාවකයක් සම්බන්ධ කර එය උපාංග ගබඩාව ලෙස ෆෝමැට් කිරීමට පහත පියවර අනුගමනය කරන්න."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"අස්ථානගත ගබඩාව"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR මගින් භාවිත කළ ගබඩා සමහරක් අස්ථානගතය. කරුණාකර DVR නැවත-සබල කිරීමට ඔබ පෙරදී භාවිත කළ බාහිර drive සම්බන්ධ කරන්න. විකල්පව, එය තවදුරටත් ලබා ගත නොහැකි නම් ඔබට ගබඩාව අමතක කිරීමට තේරිය හැකිය."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ගබඩාව අමතකද?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"ඔබේ පටිගත කළ සියලු අන්තර්ගත සහ කාල සටහන් අහිමි වනු ඇත."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"පටිගත කිරීම නවත්වන්නද?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"පටිගත කළ අන්තර්ගතය සුරැකෙනු ඇත."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"පටිගත කිරීම කාල සටහන්ගත කර ඇති නමුත් ගැටුම් ඇත"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"පටිගත කිරීම ආරම්භ කර ඇති නමුත් ගැටුම් ඇත"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> පටිගත කරනු ඇත."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> වාර්තා කරමින් පවතී."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> හි සමහර කොටස් පටිගත නොකරනු ඇත."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> සහ <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> හි සමහර කොටස් පටිගත නොකරනු ඇත."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> හි සමහර කොටස් සහ තවත් එක් කාලසටහනක් පටිගත නොකරනු ඇත."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> හි සමහර කොටස් සහ තව කාල සටහන් %3$dක් පටිගත නොකරනු ඇත.</item>
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> හි සමහර කොටස් සහ තව කාල සටහන් %3$dක් පටිගත නොකරනු ඇත.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"ඔබ පටිගත කිරීමට කැමති කුමක්ද?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"ඔබ කොපමණ කාලයක් පටිගත කිරීමට කැමතිද?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"දැනටමත් කාලසටහන්ගත කර ඇත"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"එම වැඩසටහනම <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>ට පටිගත කිරීමට කාල සටහන්ගත කර ඇත."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"දැනටමත් පටිගත කර ඇත"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"මෙම වැඩසටහන දැනටමත් පටිගත කර ඇත. එය DVR පුස්තකාලය තුළදී ලබා ගත හැකිය."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"පටිගත කළ වැඩසටහන හමු නොවීය."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"අදාළ පටිගත කිරීම්"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(වැඩසටහන් විස්තරය නැත)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">පටිගත කිරීම් %1$d</item>
+ <item quantity="other">පටිගත කිරීම් %1$d</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"පටිගත කිරීමේ කාල සටහනින් <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ඉවත් කරන ලදී"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"සුසරක ගැටුම් නිසා අර්ධ වශයෙන් පටිගත කරනු ඇත."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"සුසරක ගැටුම් නිසා පටිගත නොකරනු ඇත."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"තවම කාල සටහනෙහි පටිගත කිරීම් නැත.\nඔබට වැඩසටහන් මාර්ගෝපදේශය වෙතින් පටිගත කිරීම කාලසටහන්ගත කළ හැකිය."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">පටිගත කිරීමේ ගැටුම් %1$d</item>
+ <item quantity="other">පටිගත කිරීමේ ගැටුම් %1$d</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"මාලා සැකසීම්"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"මාලා පටිගත කිරීම අරඹන්න"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"මාලා පටිගත කිරීම නවත්වන්න"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"මාලා පටිගත කිරීම නවත්වන්නද?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"පටිගත කළ කථාංග DVR පුස්තකාලය තුළ ලබා ගත හැකිව පවතිනු ඇත."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"නවත්වන්න"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ලබා ගත හැකි කථාංග නැත.\nඒවා ලබා ගත හැකි වූ විට පටිගත කරනු ඇත."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(මිනිත්තු %1$d)</item>
+ <item quantity="other">(මිනිත්තු %1$d)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"අද"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"හෙට"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"ඊයේ"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"අද <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"හෙට <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ලකුණු"</string>
</resources>
diff --git a/res/values-sk/arrays.xml b/res/values-sk/arrays.xml
index b71197c9..7c6b4d49 100644
--- a/res/values-sk/arrays.xml
+++ b/res/values-sk/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Úplné"</item>
<item msgid="8568284598210500589">"Priblíženie"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Všetky kanály"</item>
- <item msgid="6897460857821394118">"Rodina a deti"</item>
- <item msgid="551257741825778215">"Šport"</item>
- <item msgid="452133796804325879">"Nákupy"</item>
- <item msgid="3296058637230163031">"Filmy"</item>
- <item msgid="1054540282883891201">"Komédie"</item>
- <item msgid="7900158429062595471">"Cestovanie"</item>
- <item msgid="3768998587825611787">"Drámy"</item>
- <item msgid="8340620094959282881">"Vzdelávanie"</item>
- <item msgid="7396447839483867269">"Zvieratá a príroda"</item>
- <item msgid="4738043455148062673">"Spravodajstvo"</item>
- <item msgid="7405041316051047427">"Hry"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Všetky kanály"</item>
- <item msgid="7909003973960375395">"Rodina a deti"</item>
- <item msgid="3185279732911635789">"Šport"</item>
- <item msgid="4704858492065325964">"Nákupy"</item>
- <item msgid="6083795019290250078">"Filmy"</item>
- <item msgid="8302638329222449550">"Komédie"</item>
- <item msgid="3803709976021475052">"Cestovanie"</item>
- <item msgid="8116747365234169059">"Drámy"</item>
- <item msgid="7356447541595315913">"Vzdelávanie"</item>
- <item msgid="7511135485827589547">"Zvieratá a príroda"</item>
- <item msgid="6961248112238009967">"Spravodajstvo"</item>
- <item msgid="6484685553679698447">"Hry"</item>
- <item msgid="2737158328243183190">"Kultúra"</item>
- <item msgid="6577176952650166615">"Zábava"</item>
- <item msgid="7886693831871777617">"Životný štýl"</item>
- <item msgid="8145832312485577062">"Hudba"</item>
- <item msgid="1345789204804308580">"Premiéra"</item>
- <item msgid="2736680312770771994">"Veda a technika"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Všetky kanály"</item>
+ <item msgid="928298872841713530">"Rodina a deti"</item>
+ <item msgid="2751606947569857164">"Šport"</item>
+ <item msgid="7345749789651321496">"Nákupy"</item>
+ <item msgid="167201149441442173">"Filmy"</item>
+ <item msgid="525966731464264290">"Komédie"</item>
+ <item msgid="6096710741527327836">"Cestovanie"</item>
+ <item msgid="2851882187117833883">"Dráma"</item>
+ <item msgid="78492781188719038">"Vzdelávanie"</item>
+ <item msgid="7221999662426308394">"Zvieratá a príroda"</item>
+ <item msgid="375300513250925001">"Spravodajstvo"</item>
+ <item msgid="7746320336582330410">"Hranie hier"</item>
+ <item msgid="1255741860568329178">"Umenie"</item>
+ <item msgid="7603949681065702867">"Zábava"</item>
+ <item msgid="4453821994746804366">"Životný štýl"</item>
+ <item msgid="3488534597567932843">"Hudba"</item>
+ <item msgid="7452153120614274095">"Premiéra"</item>
+ <item msgid="8215762047341133299">"Veda a technika"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Televízia online"</item>
diff --git a/res/values-sk/rating_system_strings.xml b/res/values-sk/rating_system_strings.xml
index 2f6e8d7e..52461fd6 100644
--- a/res/values-sk/rating_system_strings.xml
+++ b/res/values-sk/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index bc02f2f9..78d94c7f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Naspäť"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Program. sprievodca"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Dostupné sú nové kanály"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Odkaz nie je dostupný"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Spustiť aplikáciu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Skryté titulky"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Režim zobrazenia"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Čiastkové hodnotenia"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Zadanie kódu PIN na pozeranie tohto kanála"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Zadanie kódu PIN na pozeranie tohto programu"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Tento program má hodnotenie <xliff:g id="RATING">%1$s</xliff:g>. Ak ho chcete pozerať, zadajte kód PIN."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Zadanie kódu PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ak chcete nastaviť rodičovskú kontrolu, vytvorte kód PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Zadajte nový kód PIN"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licencie open source"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Licencie open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Verzia"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Pomáhať s vylepšovaním aktívnych kanálov"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Zdieľať s Googlom anonymné štatistiky o používaní a diagnostické údaje, aby sme mohli Televíziu online zlepšiť a zabrániť problémom, ako sú zlyhania a zamŕzania."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Ak chcete sledovať tento kanál, stlačte šípku vpravo a zadajte kód PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Ak chcete sledovať tento program, stlačte šípku doprava a zadajte kód PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Hodnotenie tohto programu je <xliff:g id="RATING">%1$s</xliff:g>.\nAk chcete sledovať tento program, stlačte šípku doprava a zadajte kód PIN."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Iba zvuk"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Slabý signál"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Žiadne pripojenie k internetu"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="few">Tento kanál bude možné prehrať až o <xliff:g id="END_TIME_1">%1$s</xliff:g>, pretože sa nahrávajú iné kanály. \n\nPlán nahrávania upravíte stlačením šípky vpravo.</item>
+ <item quantity="many">Tento kanál bude možné prehrať až o <xliff:g id="END_TIME_1">%1$s</xliff:g>, pretože sa nahrávajú iné kanály. \n\nPlán nahrávania upravíte stlačením šípky vpravo.</item>
+ <item quantity="other">Tento kanál bude možné prehrať až o <xliff:g id="END_TIME_1">%1$s</xliff:g>, pretože sa nahrávajú iné kanály. \n\nPlán nahrávania upravíte stlačením šípky vpravo.</item>
+ <item quantity="one">Tento kanál bude možné prehrať až o <xliff:g id="END_TIME_0">%1$s</xliff:g>, pretože sa nahráva iný kanál. \n\nPlán nahrávania upravíte stlačením šípky vpravo.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Bez názvu"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanál bol zablokovaný"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nové"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Nie sú k dispozícii žiadne kanály"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nové"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Nenastavené"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Získať ďalšie zdroje"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Prehliadajte aplikácie, ktoré ponúkajú televíziu online"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Získať ďalšie zdroje"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Prehliadajte aplikácie, ktoré ponúkajú televíziu online"</string>
<string name="new_sources_title" msgid="3878933676500061895">"K dispozícii sú nové zdroje kanálov"</string>
<string name="new_sources_description" msgid="749649005588426813">"K dispozícii sú nové zdroje s ďalšími kanálmi.\nMôžete ich nastaviť hneď alebo neskôr v nastavení zdrojov kanálov."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Nastaviť"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Všetky zdrojové kanály sú skryté.\nVyberte aspoň jeden kanál, ktorý chcete sledovať."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video neočakávane prestalo byť dostupné"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Kláves Späť je určený pre pripojené zariadenie. Aplikáciu ukončite stlačením tlačidla Domov."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"V tomto zariadení so systémom Android Lollipop nie sú aktívne kanály podporované."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Aktívne kanály potrebujú povolenie na čítanie televíznych programov."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Nastavte si zdroje"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Televízia online spája zážitok z tradičných televíznych kanálov so streamovaním kanálov z aplikácií. \n\nZačnite nastavením zdrojov kanálov, ktoré už máte nainštalované. Prípadne si prehliadnite Obchod Google Play a získajte ďalšie aplikácie, ktoré poskytujú televíziu online."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Nahrávanie a plány"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minút"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minút"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 hodina"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 hodiny"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nedávne"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Naplánované"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriál"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Ostatné"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Tento kanál nie je možné nahrávať."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Tento program nie je možné nahrávať."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Nahrávanie programu <xliff:g id="PROGRAMNAME">%1$s</xliff:g> bolo naplánované"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Zaznamenáva sa program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> odteraz do <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Úplný plán"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="few">Ďalšie %1$d dni</item>
+ <item quantity="many">Ďalšieho %1$d dňa</item>
+ <item quantity="other">Ďalších %1$d dní</item>
+ <item quantity="one">Ďalší %1$d deň</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="few">%1$d minúty</item>
+ <item quantity="many">%1$d minúty</item>
+ <item quantity="other">%1$d minút</item>
+ <item quantity="one">%1$d minúta</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="few">%1$d nové záznamy</item>
+ <item quantity="many">%1$d nového záznamu</item>
+ <item quantity="other">%1$d nových záznamov</item>
+ <item quantity="one">%1$d nový záznam</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="few">%1$d záznamy</item>
+ <item quantity="many">%1$d záznamu</item>
+ <item quantity="other">%1$d záznamov</item>
+ <item quantity="one">%1$d záznam</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="few">%1$d plánované záznamy</item>
+ <item quantity="many">%1$d plánovaného záznamu</item>
+ <item quantity="other">%1$d plánovaných záznamov</item>
+ <item quantity="one">%1$d plánovaný záznam</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Prehrať"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Prehrať od začiatku"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Obnoviť prehrávanie"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Odstrániť"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Odstrániť nahratý obsah"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Pokračovať"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Séria <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Zobraziť rozvrh"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Ďalšie informácie"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Odstrániť záznamy"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Vyberte epizódy, ktoré chcete odstrániť. Po odstránení sa už nebudú dať obnoviť."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Žiadne záznamy na odstránenie."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Vybrať pozreté epizódy"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Vybrať všetky epizódy"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Zrušiť výber všetkých epizód"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Počet pozretých minút: <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Počet pozretých sekúnd: <xliff:g id="WATCHED">%1$d</xliff:g> z <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nikdy nepozreté"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="few">Počet odstránených epizód: %1$d z %2$d</item>
+ <item quantity="many">Počet odstránených epizód: %1$d z %2$d</item>
+ <item quantity="other">Počet odstránených epizód: %1$d z %2$d</item>
+ <item quantity="one">Počet odstránených epizód: %1$d z %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priorita"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Najvyššia"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Najnižšia"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Č. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanály"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Akýkoľvek"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Voľba priority"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Keď naplánujete nahrávanie príliš veľa programov súčasne, zaznamenajú sa iba programy s najvyššími prioritami."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Uložiť"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Jednorazové záznamenávania majú najvyššiu prioritu"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Zrušiť"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Zrušiť"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Odstrániť"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Zastaviť"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Zobraziť rozvrh nahrávania"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Iba tento program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"teraz – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Celú sériu…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Naplánovať aj tak"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Zaznamenať radšej tento program"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Zrušiť tento záznam"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Pozrieť"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Je možné nahrať"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Nahrávanie je naplánované"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Konflikt nahrávania"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Nahráva sa"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Nahrávanie zlyhalo"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Čítajú sa programy s cieľom vytvoriť plány zaznamenávania"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Načítavajú sa programy"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR vyžaduje viac miesta v úložisku"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Budete môcť zaznamenávať programy pomocou zariadenia DVR. Teraz však v úložisku vášho zariadenia nie je dostatok miesta na fungovanie zariadenia DVR. Pripojte externý disk s minimálnou kapacitou <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB a podľa uvedených krokov ho naformátujte ako úložisko zariadenia."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Chýba úložisko"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Určitá časť úložiska využitého zariadením DVR chýba. Pred opätovným povolením zariadenia DVR pripojte externý disk, ktorý ste predtým používali. Prípadne môžete úložisko odstrániť, ak už nie je ďalej k dispozícii."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Odstrániť úložisko?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Všetok váš zaznamenaný obsah a plány budú stratené."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Zastaviť nahrávanie?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Nahraný obsah sa uloží."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Nahrávanie je naplánované, ale obsahuje konflikty"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Záznam sa spustil, ale obsahuje konflikty"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Zaznamená sa program <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> sa práve zaznamenáva."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Niektoré časti programu <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> nebudú zaznamenané."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> a <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> nebudú zaznamenané."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> a 1 ďalšieho naplánovaného programu nebudú zaznamenané."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="few">Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d ďalšie naplánované programy nebudú zaznamenané.</item>
+ <item quantity="many">Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d ďalšieho naplánovaného programu nebudú zaznamenané.</item>
+ <item quantity="other">Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> a %3$d ďalších naplánovaných programov nebudú zaznamenané.</item>
+ <item quantity="one">Niektoré časti programov <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> a %3$d ďalšieho naplánovaného programu nebudú zaznamenané.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Čo chcete nahrať?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Ako dlho chcete zaznamenávať?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Už je naplánované"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Zaznamenanie rovnakého programu už bolo naplánované na <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Už je zaznamenané"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Tento program je už zaznamenaný. Nájdete ho v knižnici zariadenia DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Zaznamenaný program sa nenašiel."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Súvisiace nahrávky"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Žiadny popis programu)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="few">%1$d záznamy</item>
+ <item quantity="many">%1$d záznamu</item>
+ <item quantity="other">%1$d záznamov</item>
+ <item quantity="one">%1$d záznam</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Program <xliff:g id="PROGRAMNAME">%1$s</xliff:g> bol odstránený z rozvrhu nahrávania"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Z dôvodu konfliktu tunerov bude nahratá iba časť obsahu."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Z dôvodu konfliktu tunerov obsah nebude nahratý."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Nemáte naplánované žiadne záznamy.\nZaznamenávanie môžete naplánovať z televízneho programu."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="few">%1$d konflikty nahrávania</item>
+ <item quantity="many">%1$d konfliktu nahrávania</item>
+ <item quantity="other">%1$d konfliktov nahrávania</item>
+ <item quantity="one">%1$d konflikt nahrávania</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Nastavenia série"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Spustiť nahrávanie série"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Zastaviť nahrávanie série"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Zastaviť nahrávanie série?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Nahrané epizódy zostanú k dispozícii v knižnici DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Zastaviť"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Nie sú k dispozícii žiadne epizódy.\nZaznamenajú sa, keď budú dostupné."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="few">(%1$d minúty)</item>
+ <item quantity="many">(%1$d minúty)</item>
+ <item quantity="other">(%1$d minút)</item>
+ <item quantity="one">(%1$d minúta) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Dnes"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Zajtra"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Včera"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Dnes: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Zajtra: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Skóre"</string>
</resources>
diff --git a/res/values-sl/arrays.xml b/res/values-sl/arrays.xml
index 5c1ef578..3867c26a 100644
--- a/res/values-sl/arrays.xml
+++ b/res/values-sl/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"V celoti"</item>
<item msgid="8568284598210500589">"Povečava"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Vsi kanali"</item>
- <item msgid="6897460857821394118">"Družina/otroci"</item>
- <item msgid="551257741825778215">"Šport"</item>
- <item msgid="452133796804325879">"Nakupovanje"</item>
- <item msgid="3296058637230163031">"Filmi"</item>
- <item msgid="1054540282883891201">"Komedija"</item>
- <item msgid="7900158429062595471">"Potovanja"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Izobraževanje"</item>
- <item msgid="7396447839483867269">"Živalski svet"</item>
- <item msgid="4738043455148062673">"Novice"</item>
- <item msgid="7405041316051047427">"Igre"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Vsi kanali"</item>
- <item msgid="7909003973960375395">"Družina/otroci"</item>
- <item msgid="3185279732911635789">"Šport"</item>
- <item msgid="4704858492065325964">"Nakupovanje"</item>
- <item msgid="6083795019290250078">"Filmi"</item>
- <item msgid="8302638329222449550">"Komedija"</item>
- <item msgid="3803709976021475052">"Potovanja"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Izobraževanje"</item>
- <item msgid="7511135485827589547">"Živalski svet"</item>
- <item msgid="6961248112238009967">"Novice"</item>
- <item msgid="6484685553679698447">"Igre"</item>
- <item msgid="2737158328243183190">"Umetnost"</item>
- <item msgid="6577176952650166615">"Zabava"</item>
- <item msgid="7886693831871777617">"Življenjski slog"</item>
- <item msgid="8145832312485577062">"Glasba"</item>
- <item msgid="1345789204804308580">"Premiera"</item>
- <item msgid="2736680312770771994">"Tehnika/znanost"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Vsi kanali"</item>
+ <item msgid="928298872841713530">"Družina/otroci"</item>
+ <item msgid="2751606947569857164">"Šport"</item>
+ <item msgid="7345749789651321496">"Nakupovanje"</item>
+ <item msgid="167201149441442173">"Filmi"</item>
+ <item msgid="525966731464264290">"Komedija"</item>
+ <item msgid="6096710741527327836">"Potovanja"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Izobraževanje"</item>
+ <item msgid="7221999662426308394">"Živalski svet"</item>
+ <item msgid="375300513250925001">"Novice"</item>
+ <item msgid="7746320336582330410">"Igre"</item>
+ <item msgid="1255741860568329178">"Umetnost"</item>
+ <item msgid="7603949681065702867">"Razvedrilo"</item>
+ <item msgid="4453821994746804366">"Življenjski slog"</item>
+ <item msgid="3488534597567932843">"Glasba"</item>
+ <item msgid="7452153120614274095">"Premiera"</item>
+ <item msgid="8215762047341133299">"Tehnika/znanost"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Kanali v živo"</item>
diff --git a/res/values-sl/rating_system_strings.xml b/res/values-sl/rating_system_strings.xml
index 0db964ba..c0e777b9 100644
--- a/res/values-sl/rating_system_strings.xml
+++ b/res/values-sl/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 962e9a29..6e79cacc 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Nazaj"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programski vodnik"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Na voljo so novi kanali"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Ni povezav"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Odpri <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Podnapisi"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Način prikaza"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Podocene"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Vnesite kodo PIN, če želite gledati ta kanal"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Vnesite kodo PIN, če želite gledati to oddajo"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Ta oddaja ima kategorijo vsebine <xliff:g id="RATING">%1$s</xliff:g>. Vnesite kodo PIN, če si želite ogledati to oddajo."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Vnos kode PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Če želite nastaviti starševski nadzor, ustvarite kodo PIN."</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Vnesite novo kodo PIN"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Odprtokodne licence"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Odprtokodne licence"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Različica"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Pomoč pri izboljšanju kanalov v živo"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Deljenje anonimnih podatkov o uporabi in diagnostičnih podatkov z Googlom zaradi izboljšanja Televizije v živo in preprečevanja težav, kot so zrušitve in zmrzovanje."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Če želite gledati ta kanal, pritisnite v desno in vnesite kodo PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Če želite gledati ta program, pritisnite v desno in vnesite kodo PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ta program ima kategorijo vsebine <xliff:g id="RATING">%1$s</xliff:g>.\nČe ga želite gledati, pritisnite v desno in vnesite kodo PIN."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Samo zvok"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Šibek signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Ni internetne povezave"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Tega kanala ni mogoče predvajati do <xliff:g id="END_TIME_1">%1$s</xliff:g>, ker se snemajo drugi kanali. \n\nPritisnite gumb za desno, da prilagodite razpored snemanja.</item>
+ <item quantity="two">Tega kanala ni mogoče predvajati do <xliff:g id="END_TIME_1">%1$s</xliff:g>, ker se snemajo drugi kanali. \n\nPritisnite gumb za desno, da prilagodite razpored snemanja.</item>
+ <item quantity="few">Tega kanala ni mogoče predvajati do <xliff:g id="END_TIME_1">%1$s</xliff:g>, ker se snemajo drugi kanali. \n\nPritisnite gumb za desno, da prilagodite razpored snemanja.</item>
+ <item quantity="other">Tega kanala ni mogoče predvajati do <xliff:g id="END_TIME_1">%1$s</xliff:g>, ker se snemajo drugi kanali. \n\nPritisnite gumb za desno, da prilagodite razpored snemanja.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Brez naslova"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal je blokiran"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Novo"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Ni kanalov"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Novo"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Ni nastavljeno"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Več virov"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Brskanje po aplikacijah, ki ponujajo kanale v živo"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Več virov"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Brskanje po aplikacijah, ki ponujajo kanale v živo"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Na voljo so novi viri kanalov"</string>
<string name="new_sources_description" msgid="749649005588426813">"Novi viri kanalov imajo na voljo nove kanale.\nNastavite jih ali to storite pozneje v nastavitvi za vire kanalov."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Nastavite zdaj"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Vsi kanali vira so skriti.\nIzberite vsaj en kanal za gledanje."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video nepričakovano ni na voljo"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Tipka NAZAJ je za priključena naprave. Pritisnite DOMOV za izhod."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Kanali v živo niso podprti v tej napravi s sistemom Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Kanali v živo potrebujejo dovoljenje za branje televizijskih sporedov."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Nastavitev virov"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Kanali v živo združujejo izkušnjo običajnih TV-kanalov in pretočno predvajanje kanalov, ki ga omogočajo aplikacije. \n\nZačnite tako, da nastavite vire kanalov, ki so že nameščeni. V Trgovini Google Play lahko tudi poiščete druge aplikacije, ki omogočajo kanale v živo."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Posnetki in razporedi"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 min"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 min"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 h"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 h"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Nedavno"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Načrtovano"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Nanizanka"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Drugo"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanala ni mogoče posneti."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Oddaje ni mogoče posneti."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Snemanje oddaje <xliff:g id="PROGRAMNAME">%1$s</xliff:g> je nastavljeno"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Snemanje oddaje <xliff:g id="PROGRAMNAME">%1$s</xliff:g> od zdaj do <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Celoten razpored"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Naslednji %1$d dan</item>
+ <item quantity="two">Naslednja %1$d dneva</item>
+ <item quantity="few">Naslednje %1$d dni</item>
+ <item quantity="other">Naslednjh %1$d dni</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minuta</item>
+ <item quantity="two">%1$d minuti</item>
+ <item quantity="few">%1$d minute</item>
+ <item quantity="other">%1$d minut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d nov posnetek</item>
+ <item quantity="two">%1$d nova posnetka</item>
+ <item quantity="few">%1$d novi posnetki</item>
+ <item quantity="other">%1$d novih posnetkov</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d posnetek</item>
+ <item quantity="two">%1$d posnetka</item>
+ <item quantity="few">%1$d posnetki</item>
+ <item quantity="other">%1$d posnetkov</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d načrtovan posnetek</item>
+ <item quantity="two">%1$d načrtovana posnetka</item>
+ <item quantity="few">%1$d načrtovani posnetki</item>
+ <item quantity="other">%1$d načrtovan. posnetkov</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Gledanje"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Predvajaj od začetka"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Nadaljuj predvajanje"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Izbriši"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Izbris posnetkov"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Nadaljuj"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. sezona"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Pokaži razpored"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Več o tem"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Izbris posnetkov"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Izberite epizode, ki jih želite izbrisati. Po izbrisu jih ni mogoče več obnoviti."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Ni posnetkov za izbris."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Izberi ogledane epizode"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Izberi vse epizode"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Prekliči izbor vse epizod"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Ogledano: <xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> min"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Ogledano: <xliff:g id="WATCHED">%1$d</xliff:g>/<xliff:g id="DURATION">%2$d</xliff:g> s"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Nikoli ogledano"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d od %2$d epizode je izbrisana</item>
+ <item quantity="two">%1$d od %2$d epizod sta izbrisani</item>
+ <item quantity="few">%1$d od %2$d epizod so izbrisane</item>
+ <item quantity="other">%1$d od %2$d epizod je izbrisanih</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prednost"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Najvišja"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Najnižja"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Št. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanali"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Kateri koli"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Izbira prednosti"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Če je nastavljeno snemanje preveč oddaj ob istem času, bodo posnete samo oddaje z višjo prednostjo."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Shrani"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Enkratna snemanja imajo najvišjo prednost"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Prekliči"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Prekliči"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Pozabi"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Ustavi"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Ogled razporeda snemanja"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Samo to oddajo"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"zdaj–<xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Celotno sezono …"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Nastavitev snemanja kljub težavi"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Snemanje tega namesto drugega"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Preklic tega snemanja"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Ogled"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Omogoča snemanje"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Čas snemanja nastavljen"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Posnetek v sporu"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Snemanje"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Snemanje ni uspelo"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Branje oddaj za ustvarjanje razporedov snemanja"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Branje oddaj"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Digitalni videorekorder potrebuje več shrambe"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Z digitalnim videorekorderjem boste lahko snemali oddaje, vendar v napravi ni dovolj shrambe, potrebne za njegovo delovanje. Priključite zunanji pogon velikosti <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB ali več in upoštevajte navodila, da ga formatirate kot shrambo naprave."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Manjkajoča shramba"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Del shrambe, ki jo uporablja digitalni videorekorder, manjka. Povežite zunanji pogon, ki ste ga že uporabljali, če želite znova omogočiti digitalni videorekorder. Če shramba ni več na voljo, jo lahko tudi pozabite."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Želite pozabiti shrambo?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Posneta vsebina in razporedi bodo izgubljeni."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Želite ustaviti snemanje?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Posneta vsebina bo shranjena."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Snemanje je nastavljeno, ampak obstajajo spori"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Snemanje se je začelo, vendar so spori"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Oddaja <xliff:g id="PROGRAMNAME">%1$s</xliff:g> bo posneta."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> se snema."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Nekateri deli oddaje <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ne bodo posneti."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ne bodo posneti."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ter še enega razporeda ne bodo posneti."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ter še %3$d razporeda ne bodo posneti.</item>
+ <item quantity="two">Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ter še %3$d razporedov ne bodo posneti.</item>
+ <item quantity="few">Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ter še %3$d razporedov ne bodo posneti.</item>
+ <item quantity="other">Nekateri deli oddaj <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> in <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ter še %3$d razporedov ne bodo posneti.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Kaj želite posneti?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Kako dolgo želite snemati?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Že nastavljeno"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Snemanje iste oddaje je že nastavljeno za ob <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Že posneto"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Ta oddaja je že posneta. Na voljo je v knjižnici digitalnega videorekorderja."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Posnetega programa ni bilo mogoče najti."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Sorodni posnetki"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ni opisa programa)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d posnetek</item>
+ <item quantity="two">%1$d posnetka</item>
+ <item quantity="few">%1$d posnetki</item>
+ <item quantity="other">%1$d posnetkov</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Oddaja <xliff:g id="PROGRAMNAME">%1$s</xliff:g> odstranjena iz razporeda snemanj"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Posneto bo delno, ker sprejemnik ni na voljo"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ne bo posneto, ker sprejemnik ni na voljo"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Trenutno ni nastavljeno še nobeno snemanje.\nSnemanje lahko nastavitev v programskem vodniku."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d spor glede snemanja</item>
+ <item quantity="two">%1$d spora glede snemanja</item>
+ <item quantity="few">%1$d spori glede snemanja</item>
+ <item quantity="other">%1$d sporov glede snemanja</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Nastavitev serije"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Začni snemanje serije"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Ustavi snemanje serije"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Ustavitev snemanja serije?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Posnete epizode bodo na voljo v knjižnici digitalnega videorekorderja."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Ustavi"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Na voljo ni nobena epizoda.\nPosnete bodo, ko bodo na voljo."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minuta)</item>
+ <item quantity="two">(%1$d minuti)</item>
+ <item quantity="few">(%1$d minute)</item>
+ <item quantity="other">(%1$d minut)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Danes"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Jutri"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Včeraj"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Danes: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Jutri: <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Ocena"</string>
</resources>
diff --git a/res/values-sr/arrays.xml b/res/values-sr/arrays.xml
index 63b952ff..3a96baf4 100644
--- a/res/values-sr/arrays.xml
+++ b/res/values-sr/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Пун"</item>
<item msgid="8568284598210500589">"Зумиран"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Сви канали"</item>
- <item msgid="6897460857821394118">"Породица/деца"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Куповина"</item>
- <item msgid="3296058637230163031">"Филмови"</item>
- <item msgid="1054540282883891201">"Комедија"</item>
- <item msgid="7900158429062595471">"Путовања"</item>
- <item msgid="3768998587825611787">"Драма"</item>
- <item msgid="8340620094959282881">"Образовање"</item>
- <item msgid="7396447839483867269">"Животиње/дивљи свет"</item>
- <item msgid="4738043455148062673">"Вести"</item>
- <item msgid="7405041316051047427">"Видео игре"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Сви канали"</item>
- <item msgid="7909003973960375395">"Породица/деца"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Куповина"</item>
- <item msgid="6083795019290250078">"Филмови"</item>
- <item msgid="8302638329222449550">"Комедија"</item>
- <item msgid="3803709976021475052">"Путовања"</item>
- <item msgid="8116747365234169059">"Драма"</item>
- <item msgid="7356447541595315913">"Образовање"</item>
- <item msgid="7511135485827589547">"Животиње/дивљи свет"</item>
- <item msgid="6961248112238009967">"Вести"</item>
- <item msgid="6484685553679698447">"Видео игре"</item>
- <item msgid="2737158328243183190">"Уметност"</item>
- <item msgid="6577176952650166615">"Забава"</item>
- <item msgid="7886693831871777617">"Стил живота"</item>
- <item msgid="8145832312485577062">"Музика"</item>
- <item msgid="1345789204804308580">"Премијер"</item>
- <item msgid="2736680312770771994">"Технологија/наука"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Сви канали"</item>
+ <item msgid="928298872841713530">"Породица/деца"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Куповина"</item>
+ <item msgid="167201149441442173">"Филмови"</item>
+ <item msgid="525966731464264290">"Комедија"</item>
+ <item msgid="6096710741527327836">"Путовања"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Образовање"</item>
+ <item msgid="7221999662426308394">"Животиње/дивљи свет"</item>
+ <item msgid="375300513250925001">"Вести"</item>
+ <item msgid="7746320336582330410">"Видео игре"</item>
+ <item msgid="1255741860568329178">"Уметност"</item>
+ <item msgid="7603949681065702867">"Забава"</item>
+ <item msgid="4453821994746804366">"Животни стил"</item>
+ <item msgid="3488534597567932843">"Музика"</item>
+ <item msgid="7452153120614274095">"Премијер"</item>
+ <item msgid="8215762047341133299">"Технологија/наука"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Канали уживо"</item>
diff --git a/res/values-sr/rating_system_strings.xml b/res/values-sr/rating_system_strings.xml
index d4285959..1e6b109e 100644
--- a/res/values-sr/rating_system_strings.xml
+++ b/res/values-sr/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index ccba3012..0b4c2f3c 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Претходнo"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Водич за програм"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Доступни су нови канали"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Линк није доступан"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Отвори <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Титлови"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Режим приказа"</string>
@@ -125,18 +124,19 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Подоцене"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Унесите PIN да бисте гледали овај канал"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Унесите PIN да бисте гледали овај програм"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Овај програм има оцену <xliff:g id="RATING">%1$s</xliff:g>. Унесите PIN да бисте гледали овај програм"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Унесите PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Да бисте подесили родитељску контролу, направите PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Унесите нови PIN"</string>
<string name="pin_enter_again" msgid="2618999754723090427">"Потврдите PIN"</string>
<string name="pin_enter_old_pin" msgid="4588282612931041919">"Унесите актуелни PIN"</string>
<plurals name="pin_enter_countdown" formatted="false" msgid="3415233538538544309">
- <item quantity="one">Унели сте погрешан PIN 5 пута.\nПокушајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунду.</item>
- <item quantity="few">Унели сте погрешан PIN 5 пута.\nПокушајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунде.</item>
- <item quantity="other">Унели сте погрешан PIN 5 пута.\nПокушајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунди.</item>
+ <item quantity="one">Унели сте погрешан PIN 5 пута.\nПробајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунду.</item>
+ <item quantity="few">Унели сте погрешан PIN 5 пута.\nПробајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунде.</item>
+ <item quantity="other">Унели сте погрешан PIN 5 пута.\nПробајте поново за <xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> секунди.</item>
</plurals>
- <string name="pin_toast_wrong" msgid="2126295626095048746">"Тај PIN је погрешан. Покушајте поново."</string>
- <string name="pin_toast_not_match" msgid="4283624338659521768">"Покушајте поново, PIN се не подудара"</string>
+ <string name="pin_toast_wrong" msgid="2126295626095048746">"Тај PIN је погрешан. Пробајте поново."</string>
+ <string name="pin_toast_not_match" msgid="4283624338659521768">"Пробајте поново, PIN се не подудара"</string>
<string name="side_panel_title_settings" msgid="8244327316510918755">"Подешавања"</string>
<string name="settings_channel_source_item_customize_channels" msgid="6115770679732624593">"Прилагоди листу канала"</string>
<string name="settings_channel_source_item_customize_channels_description" msgid="8966243790328235580">"Изаберите канале за водич за програме"</string>
@@ -146,8 +146,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Лиценце отвореног кода"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Лиценце отвореног кода"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Верзија"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Шаљи податке ради побољшања Live TV-а"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Делите анонимне податке о коришћењу и дијагностици са Google-ом да бисмо побољшали Канале уживо и спречили проблемe, попут отказивања и неодазивања."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Да бисте гледали овај канал, притисните дугме Десно и унесите PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Да бисте гледали овај програм, притисните дугме Десно и унесите PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Овај програм има оцену <xliff:g id="RATING">%1$s</xliff:g>.\nДа бисте гледали овај програм, притисните дугме Десно и унесите PIN."</string>
@@ -159,6 +157,11 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Само аудио"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Слаб сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Нема интернет везе"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Овај канал не може да се пусти до <xliff:g id="END_TIME_1">%1$s</xliff:g> јер се снимају други канали. \n\nПритисните тастер за десно да бисте прилагодили распоред снимања.</item>
+ <item quantity="few">Овај канал не може да се пусти до <xliff:g id="END_TIME_1">%1$s</xliff:g> јер се снимају други канали. \n\nПритисните тастер за десно да бисте прилагодили распоред снимања.</item>
+ <item quantity="other">Овај канал не може да се пусти до <xliff:g id="END_TIME_1">%1$s</xliff:g> јер се снимају други канали. \n\nПритисните тастер за десно да бисте прилагодили распоред снимања.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Нема наслова"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Канал је блокиран"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Ново"</string>
@@ -171,8 +174,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Није доступан ниједан канал"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Ново"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Није подешен"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Набави још извора"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Прегледајте апликације које нуде канале уживо"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Набави још извора"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Прегледајте апликације које нуде канале уживо"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Доступни су нови извори канала"</string>
<string name="new_sources_description" msgid="749649005588426813">"Нови извори канала нуде канале.\nПодесите их одмах или обавите ово касније у подешавању извора канала."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Подеси одмах"</string>
@@ -190,8 +193,172 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Сви изворни канали су сакривени.\nИзаберите бар један канал који хоћете да гледате."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Видео је неочекивано недоступан"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Тастер за НАЗАД је за повезане уређаје. Притисните дугме ПОЧЕТНА да бисте изашли."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Канали уживо нису подржани на овом уређају који користи Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Каналима уживо треба дозвола за читање листе TV канала."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Подесите изворе канала"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Канали уживо комбинују доживљај традиционалних ТВ канала са каналима за стримовање које пружају апликације. \n\nЗапочните тако што ћете подесити изворе канала који су већ инсталирани. Или потражите још апликација које нуде канале уживо у Google Play продавници."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Снимци и распореди"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 минута"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 минута"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 сат"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 сата"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Недавно"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Заказано"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Серија"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Друго"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Није могуће снимити канал."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Није могуће снимити програм."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Заказано је снимање програма <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> се снима од сада до <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Комплетан распоред"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Следећи %1$d дан</item>
+ <item quantity="few">Следећа %1$d дана</item>
+ <item quantity="other">Следећих %1$d дана</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d минут</item>
+ <item quantity="few">%1$d минута</item>
+ <item quantity="other">%1$d минута</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d нови снимак</item>
+ <item quantity="few">%1$d нова снимка</item>
+ <item quantity="other">%1$d нових снимака</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d снимак</item>
+ <item quantity="few">%1$d снимка</item>
+ <item quantity="other">%1$d снимака</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d снимање је заказано</item>
+ <item quantity="few">%1$d снимања су заказана</item>
+ <item quantity="other">%1$d снимања је заказано</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Пусти"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Пусти од почетка"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Настави репродукцију"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Избриши"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Избриши снимке"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Настави"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. серијал"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Распоред"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Прочитајте више"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Избриши снимке"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Изаберите епизоде које желите да избришете. Када их избришете, нећете моћи да их вратите."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Нема снимака за брисање."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Изабери гледане епизоде"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Изабери све епизоде"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Опозови избор свих епизода"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Одгледали сте <xliff:g id="WATCHED">%1$d</xliff:g> од <xliff:g id="DURATION">%2$d</xliff:g> минута"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Одгледали сте <xliff:g id="WATCHED">%1$d</xliff:g> од <xliff:g id="DURATION">%2$d</xliff:g> секунде(и)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Није гледано"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">Избрисали сте %1$d од %2$d епизоде</item>
+ <item quantity="few">Избрисали сте %1$d од %2$d епизоде</item>
+ <item quantity="other">Избрисали сте %1$d од %2$d епизода</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Приоритет"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Највиши"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Најнижи"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Не. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Канали"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Било који"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Изаберите приоритет"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Када истовремено има превише програма за снимање, снимаће се само програми са вишим приоритетом."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Сачувај"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Једнократни снимци имају највиши приоритет"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Откажи"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Откажи"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Заборави"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Заустави"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Прикажи распоред за снимање"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Само ова епизода"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"сада – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Цела серија…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Ипак закажи"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Сними овај програм уместо њега"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Откажи ово снимање"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Пусти одмах"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Подржава снимање"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Снимање је заказано"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Неусаглашеност при снимању"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Снимање"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Снимање није успело"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Читамо програме да бисмо направили распореде"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Читамо програме"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR-у треба више меморијског простора"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Моћи ћете да снимате програме помоћу DVR-а. Међутим, тренутно на уређају нема довољно меморијског простора да би DVR функционисао. Повежите спољни диск који има <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB или више и пратите кораке да бисте га форматирали као меморијски простор уређаја."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Меморијски простор недостаје"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Недостаје део меморијског простора који DVR користи. Повежите спољни диск који сте раније користили да бисте поново омогућили DVR. Уместо тога можете да заборавите меморијски простор ако више није доступан."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Желите ли да заборавите меморијски простор?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Сав снимљени садржај и распореди ће бити изгубљени."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Зауставити снимање?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Снимљени садржај ће се сачувати."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Снимање је заказано, али постоје неусаглашености"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Снимање је почело али има неусаглашености"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Програм <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ће бити снимљен."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> се снима."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> неће бити снимљени."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> неће бити снимљени."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> и још један распоред неће бити снимљени."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> и још %3$d распоред неће бити снимљени.</item>
+ <item quantity="few">Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> и још %3$d распореда неће бити снимљени.</item>
+ <item quantity="other">Неки делови програма <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g> и <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> и још %3$d распореда неће бити снимљени.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Шта желите да снимите?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Колико дуго желите да снимате?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Већ је заказано"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Снимање истог програма је већ заказано за <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Већ је снимљено"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Овај програм је већ снимљен. Доступан је у DVR филмотеци."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Снимљени програм није пронађен."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Сродни снимци"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Нема описа програма)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d снимак</item>
+ <item quantity="few">%1$d снимка</item>
+ <item quantity="other">%1$d снимака</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Програм <xliff:g id="PROGRAMNAME">%1$s</xliff:g> је уклоњен са распореда за снимање"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Биће делимично снимљено јер нема тјунера."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Неће бити снимљено јер нема тјунера."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Још увек није заказано ниједно снимање.\nСнимање можете да закажете из водича за програме."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d неусаглашеност при снимању</item>
+ <item quantity="few">%1$d неусаглашености при снимању</item>
+ <item quantity="other">%1$d неусаглашености при снимању</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Подешавања серија"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Започни снимање серије"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Заустави снимање серије"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Зауставити снимање серије?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Снимљене епизоде ће остати доступне у DVR библиотеци."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Заустави"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Нема доступних епизода.\nБиће снимљене када постану доступне."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d минут)</item>
+ <item quantity="few">(%1$d минута)</item>
+ <item quantity="other">(%1$d минута)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Данас"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Сутра"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Јуче"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Данас <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Сутра <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Оцена"</string>
</resources>
diff --git a/res/values-sv/arrays.xml b/res/values-sv/arrays.xml
index 983c165b..46fde2cf 100644
--- a/res/values-sv/arrays.xml
+++ b/res/values-sv/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Helskärm"</item>
<item msgid="8568284598210500589">"Zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Alla kanaler"</item>
- <item msgid="6897460857821394118">"Familj/barn"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Shopping"</item>
- <item msgid="3296058637230163031">"Filmer"</item>
- <item msgid="1054540282883891201">"Komedi"</item>
- <item msgid="7900158429062595471">"Resor"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Utbildning"</item>
- <item msgid="7396447839483867269">"Djur/natur"</item>
- <item msgid="4738043455148062673">"Nyheter"</item>
- <item msgid="7405041316051047427">"Spel"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Alla kanaler"</item>
- <item msgid="7909003973960375395">"Familj/barn"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Shopping"</item>
- <item msgid="6083795019290250078">"Filmer"</item>
- <item msgid="8302638329222449550">"Komedi"</item>
- <item msgid="3803709976021475052">"Resor"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Utbildning"</item>
- <item msgid="7511135485827589547">"Djur/natur"</item>
- <item msgid="6961248112238009967">"Nyheter"</item>
- <item msgid="6484685553679698447">"Spel"</item>
- <item msgid="2737158328243183190">"Konst"</item>
- <item msgid="6577176952650166615">"Underhållning"</item>
- <item msgid="7886693831871777617">"Livsstil"</item>
- <item msgid="8145832312485577062">"Musik"</item>
- <item msgid="1345789204804308580">"Premiär"</item>
- <item msgid="2736680312770771994">"Teknik/vetenskap"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Alla kanaler"</item>
+ <item msgid="928298872841713530">"Familj/barn"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Shopping"</item>
+ <item msgid="167201149441442173">"Filmer"</item>
+ <item msgid="525966731464264290">"Komedi"</item>
+ <item msgid="6096710741527327836">"Resor"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Utbildning"</item>
+ <item msgid="7221999662426308394">"Djur/natur"</item>
+ <item msgid="375300513250925001">"Nyheter"</item>
+ <item msgid="7746320336582330410">"Spel"</item>
+ <item msgid="1255741860568329178">"Konst"</item>
+ <item msgid="7603949681065702867">"Underhållning"</item>
+ <item msgid="4453821994746804366">"Livsstil"</item>
+ <item msgid="3488534597567932843">"Musik"</item>
+ <item msgid="7452153120614274095">"Premiär"</item>
+ <item msgid="8215762047341133299">"Teknik/vetenskap"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Livekanaler"</item>
diff --git a/res/values-sv/rating_system_strings.xml b/res/values-sv/rating_system_strings.xml
index a02461a5..46db02b7 100644
--- a/res/values-sv/rating_system_strings.xml
+++ b/res/values-sv/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 4627c52d..212fd957 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Föregående"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Programguide"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Det finns nya kanaler"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Det finns ingen länk"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Öppna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Textning"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Visningsläge"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Underklassificering"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Ange pinkoden om du vill titta på den här kanalen"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Ange pinkoden om du vill titta på det här programmet"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Programmet har klassificerats som <xliff:g id="RATING">%1$s</xliff:g>. Ange pinkoden om du vill titta på programmet"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Ange din pinkod"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Skapa en pinkod om du vill konfigurera barnfiltret"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Ange en ny pinkod"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Licenser för öppen källkod"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Öppen källkod"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Version"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Hjälp till att förbättra Livekanaler"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Dela anonym information om användning och diagnostik med Google så att vi kan förbättra Livekanaler och förhindra problem som att appen fastnar eller kraschar."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Tryck till höger och ange pinkoden om du vill titta på den här kanalen"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Tryck till höger och ange pinkoden om du vill titta på det här programmet"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Det här programmet har kategoriserats som <xliff:g id="RATING">%1$s</xliff:g>\nTryck till höger och ange pinkoden om du vill titta på det här programmet."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Endast ljud"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Svag signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Ingen internetanslutning"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Kanalen kan inte spelas upp förrän <xliff:g id="END_TIME_1">%1$s</xliff:g> eftersom andra kanaler spelas in. \n\nTryck på Höger om du vill ändra inspelningsschemat.</item>
+ <item quantity="one">Kanalen kan inte spelas upp förrän <xliff:g id="END_TIME_0">%1$s</xliff:g> eftersom en annan kanal spelas in. \n\nTryck på Höger om du vill ändra inspelningsschemat.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Ingen titel"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanalen har blockerats"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Nytt"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Inga kanaler är tillgängliga"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Nytt"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Har inte konfigurerats"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Hämta fler källor"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Sök efter appar med livekanaler"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Hämta fler källor"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Sök efter appar med livekanaler"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Det finns nya kanalkällor"</string>
<string name="new_sources_description" msgid="749649005588426813">"Det finns nya kanalkällor med kanaler.\nKonfigurera dem nu eller gör det senare i inställningarna för kanalkällor."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Konfigurera nu"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Alla källkanaler är dolda.\nVälj minst en kanal som du vill titta på."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Videon är inte tillgänglig"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Knappen BACK (bakåt) gäller en ansluten enhet. Avsluta genom att trycka på knappen HOME (start)."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Livekanaler stöds inte på enheter med Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Livekanaler behöver behörighet att läsa TV-tablåer."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Konfigurera dina källor"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Livekanaler kombinerar det bästa från traditionella TV-kanaler med strömmande kanaler från appar. \n\nKom igång genom att konfigurera de kanalkällor som redan är installerade eller kolla in Google Play Butik för fler appar som erbjuder livekanaler."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Inspelningar och scheman"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuter"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuter"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"En timme"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 timmar"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Senaste"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Planerat"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Serie"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Övrigt"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Det går inte att spela in från kanalen."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Det går inte att spela in programmet."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> har schemalagts för inspelning"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> spelas in från och med nu till kl. <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Hela schemat"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d dagar till</item>
+ <item quantity="one">%1$d dag till</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d minuter</item>
+ <item quantity="one">%1$d minut</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d nya inspelningar</item>
+ <item quantity="one">%1$d ny inspelning</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d inspelningar</item>
+ <item quantity="one">%1$d inspelning</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d schemalagda inspelningar</item>
+ <item quantity="one">%1$d schemalagd inspelning</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Klocka"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Spela upp från början"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Fortsätt spela upp"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Ta bort"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Radera inspelningar"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Återuppta"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Säsong <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Visa schema"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Läs mer"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Radera inspelningar"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Markera de avsnitt du vill radera. Det går inte att återställa avsnitten när de har raderats."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Det finns inga inspelningar att radera."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Markera spelade avsnitt"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Markera alla avsnitt"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Avmarkera alla avsnitt"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> av <xliff:g id="DURATION">%2$d</xliff:g> minuter har spelats upp"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> av <xliff:g id="DURATION">%2$d</xliff:g> sekunder har spelats upp"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Ospelade"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d av %2$d avsnitt har raderats</item>
+ <item quantity="one">%1$d av %2$d avsnitt har raderats</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Prioritet"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Högsta"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Lägsta"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nej. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanaler"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Alla"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Välj prioritet"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"När det finns för många program för att de ska kunna spelas in samtidigt spelas endast de med högst prioritet in."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Spara"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Engångsinspelningar har högsta prioritet"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Avbryt"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Avbryt"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Glöm"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Stoppa"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Visa inspelningsschema"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Bara det här programmet"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"fr.o.m. nu till <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Hela serien …"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Schemalägg ändå"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Spela in detta i stället"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Avbryt den här inspelningen"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Titta nu"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kan spelas in"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Inspelningen har schemalagts"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Inspelningskonflikt"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Inspelning"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Inspelningen misslyckades"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Läser in program för att inspelningsscheman"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Läser in program"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Mer lagringsutrymme krävs för hårddiskinspelning"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Du kan använda hårddiskinspelning för att spela in program, men just nu finns det inte tillräckligt mycket ledigt lagringsutrymme på enheten för hårddiskinspelning. Anslut en extern enhet på minst <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB och följ anvisningarna för att formatera den som enhetslagring."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Lagringsutrymmet är inte tillgängligt"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"En del av lagringsutrymmet som används av DVR saknas. Anslut den externa hårddisken du använde innan DVR återaktiverades. Du kan också att välja att glömma bort lagringsutrymmet om det inte längre är tillgängligt."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Ska lagringsutrymmet glömmas bort?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Allt rekommenderat innehåll och alla inspelningsscheman försvinner."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Vill du sluta spela in?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Det inspelade innehållet sparas."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Inspelningen har schemalagts men innehåller konflikter"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Inspelningen har startat men innehåller konflikter"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> spelas in."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> spelas in."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Delar av <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> spelas inte in."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Delar av <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> och <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> spelas inte in."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Delar av <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> och ett annat schemalagt program spelas inte in."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Delar av <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> och %3$d andra schemalagda program spelas inte in.</item>
+ <item quantity="one">Delar av <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> och %4$d annat schemalagt program spelas inte in.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Vad vill du spela in?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Hur länge vill du spela in?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Redan schemalagt"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Samma program har schemalagts för inspelning kl. <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Redan inspelat"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Programmet har redan spelats in. Det finns i DVR-biblioteket."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Det gick inte att hitta det inspelade programmet."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Relaterade inspelningar"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Programbeskrivning saknas)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d inspelningar</item>
+ <item quantity="one">%1$d inspelning</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> har tagits bort från inspelningsschemat"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Bara delar av schemat spelas in p.g.a. mottagarkonflikter."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Schemat spelas inte in på grund av mottagarkonflikter."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Det finns inga schemalagda inspelningar ännu.\nDu schemalägger inspelningar i programguiden."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d inspelningskrockar</item>
+ <item quantity="one">%1$d inspelningskrock</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Serieinställningar"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Starta serieinspelning"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Stoppa serieinspelning"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Vill du stoppa serieinspelning?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Inspelade avsnitt finns kvar i DVR-biblioteket"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Stoppa"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Det finns inga tillgängliga avsnitt.\nDe spelas in när de är tillgängliga."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d minuter)</item>
+ <item quantity="one">(%1$d minut) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"I dag"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"I morgon"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"I går"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i dag"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> i morgon"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Betyg"</string>
</resources>
diff --git a/res/values-sw/arrays.xml b/res/values-sw/arrays.xml
index 081ecc8b..72fdf8ee 100644
--- a/res/values-sw/arrays.xml
+++ b/res/values-sw/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Kamili"</item>
<item msgid="8568284598210500589">"Kuza"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Vituo vyote"</item>
- <item msgid="6897460857821394118">"Familia/Watoto"</item>
- <item msgid="551257741825778215">"Spoti"</item>
- <item msgid="452133796804325879">"Ununuzi"</item>
- <item msgid="3296058637230163031">"Filamu"</item>
- <item msgid="1054540282883891201">"Vichekesho"</item>
- <item msgid="7900158429062595471">"Usafiri"</item>
- <item msgid="3768998587825611787">"Uigizaji"</item>
- <item msgid="8340620094959282881">"Elimu"</item>
- <item msgid="7396447839483867269">"Wanyama/Wanyamapori"</item>
- <item msgid="4738043455148062673">"Habari"</item>
- <item msgid="7405041316051047427">"Michezo ya video"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Vituo vyote"</item>
- <item msgid="7909003973960375395">"Familia/Watoto"</item>
- <item msgid="3185279732911635789">"Spoti"</item>
- <item msgid="4704858492065325964">"Ununuzi"</item>
- <item msgid="6083795019290250078">"Filamu"</item>
- <item msgid="8302638329222449550">"Vichekesho"</item>
- <item msgid="3803709976021475052">"Usafiri"</item>
- <item msgid="8116747365234169059">"Uigizaji"</item>
- <item msgid="7356447541595315913">"Elimu"</item>
- <item msgid="7511135485827589547">"Wanyama/Wanyamapori"</item>
- <item msgid="6961248112238009967">"Habari"</item>
- <item msgid="6484685553679698447">"Michezo ya video"</item>
- <item msgid="2737158328243183190">"Sanaa"</item>
- <item msgid="6577176952650166615">"Burudani"</item>
- <item msgid="7886693831871777617">"Mitindo ya maisha"</item>
- <item msgid="8145832312485577062">"Muziki"</item>
- <item msgid="1345789204804308580">"Zinazoongoza"</item>
- <item msgid="2736680312770771994">"Teknolojia/Sayansi"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Vituo vyote"</item>
+ <item msgid="928298872841713530">"Familia/Watoto"</item>
+ <item msgid="2751606947569857164">"Michezo"</item>
+ <item msgid="7345749789651321496">"Ununuzi"</item>
+ <item msgid="167201149441442173">"Filamu"</item>
+ <item msgid="525966731464264290">"Vichekesho"</item>
+ <item msgid="6096710741527327836">"Usafiri"</item>
+ <item msgid="2851882187117833883">"Uigizaji"</item>
+ <item msgid="78492781188719038">"Elimu"</item>
+ <item msgid="7221999662426308394">"Wanyama/Wanyamapori"</item>
+ <item msgid="375300513250925001">"Habari"</item>
+ <item msgid="7746320336582330410">"Kamari"</item>
+ <item msgid="1255741860568329178">"Sanaa"</item>
+ <item msgid="7603949681065702867">"Burudani"</item>
+ <item msgid="4453821994746804366">"Mitindo ya maisha"</item>
+ <item msgid="3488534597567932843">"Muziki"</item>
+ <item msgid="7452153120614274095">"Zinazoongoza"</item>
+ <item msgid="8215762047341133299">"Teknolojia/Sayansi"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Televisheni Mtandaoni"</item>
diff --git a/res/values-sw/rating_system_strings.xml b/res/values-sw/rating_system_strings.xml
index ff3b0b2c..1605b696 100644
--- a/res/values-sw/rating_system_strings.xml
+++ b/res/values-sw/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 146202f6..00038ff4 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Iliyotangulia"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Mwongozo wa programu"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Vituo vipya vinapatikana"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Hakuna kiungo"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Fungua <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Manukuu"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Hali ya onyesho"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Ukadiriaji mdogo"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Weka PIN yako ili uangalie kituo hiki"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Weka PIN yako ili uangalie kipindi hiki"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Kipindi hiki kimepewa ukadiriaji wa <xliff:g id="RATING">%1$s</xliff:g>. Weka PIN yako ili ukitazame"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Weka PIN yako"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ili uweke udhibiti wa wazazi, unda PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Weka PIN mpya"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Leseni za programu huria"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Leseni za programu huria"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Toleo"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Saidia kuboresha Vituo vya Moja kwa moja"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Shiriki data isiyokutambulisha ya matumizi na uchanganuzi wa matatizo kwa Google ili tuweze kuboresha programu ya Televisheni Mtandaoni na kuzuia matatizo ya kuacha kufanya kazi na kukwama."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Ili uangalie kituo hiki, bonyeza Kulia na uweke PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Ili uangalie kipindi hiki, bonyeza Kulia na uweke PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Kipindi hiki kimekadiriwa <xliff:g id="RATING">%1$s</xliff:g>.\nIli utazame kipindi hiki, bonyeza Kulia na uweke PIN yako"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Sauti pekee"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Mawimbi dhaifu"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Hakuna muunganisho wa Intaneti"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Huwezi kucheza kituo hiki hadi <xliff:g id="END_TIME_1">%1$s</xliff:g> kwa sababu vituo vingine vinarekodiwa. \n\nBonyeza Kulia ili ubadilishe ratiba ya kurekodi.</item>
+ <item quantity="one">Huwezi kucheza kituo hiki hadi <xliff:g id="END_TIME_0">%1$s</xliff:g> kwa sababu kituo kingine kinarekodiwa. \n\nBonyeza Kulia ili ubadilishe ratiba ya kurekodi.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Kichwa hakijaongezwa"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kituo kimezuiwa"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Vipya"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Hakuna kituo kinachopatikana"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Mpya"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Mipangilio haijawekwa"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Pata vyanzo zaidi"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Kagua programu zinazotoa vituo vya moja kwa moja"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Pata vyanzo zaidi"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Kagua programu zinazotoa vituo vya moja kwa moja"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Vyanzo vipya vya vituo vinavyopatikana"</string>
<string name="new_sources_description" msgid="749649005588426813">"Kuna vituo katika vyanzo vipya vya vituo. \nWeka vituo hivyo sasa au baadaye katika mipangilio ya vyanzo vya vituo."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Weka mipangilio sasa"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Vituo chanzo vyote vimefichwa.\nChagua angalau kituo kimoja utazame."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Jambo lisilotarajiwa limetokea, video haipatikani"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Kitufe cha NYUMA ni kwa ajili ya kifaa kilichounganishwa. Bonyeza kitufe cha MWANZO ili uondoe."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Kipengele cha Vituo vya Moja kwa Moja hakiwezi kutumiwa kwenye kifaa hiki kwa kutumia Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Kipengele cha Vituo vya Moja kwa Moja kinahitaji idhini ili kione orodha ya vipindi vya televisheni."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Weka mipangilio ya vyanzo vyako"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Televisheni mtandaoni hujumuisha hali ya matumizi ya vituo vya TV ya kawaida na vituo vya utiririshaji vinavyotolewa na programu. \n\nAnza kutumia kwa kuweka mipangilio ya vyanzo vya vituo ambavyo tayari vimesakinishwa. Au kagua Duka la Google Play ili upate programu zaidi zinazotoa huduma za televisheni mtandaoni."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Rekodi na ratiba"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"Dakika 10"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"Dakika 30"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"Saa 1"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"Saa 3"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Za hivi karibuni"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Imeratibiwa"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Mfululizo"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Nyinginezo"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Haiwezi kurekodi kituo hiki."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Haiwezi kurekodi kipindi hiki."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> imeratibiwa kurekodiwa"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Inarekodi <xliff:g id="PROGRAMNAME">%1$s</xliff:g> kuanzia sasa hadi <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Ratiba kamili"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Siku %1$d zinazofuata</item>
+ <item quantity="one">Siku 1$d inayofuata</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">Dakika %1$d</item>
+ <item quantity="one">Dakika %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">Rekodi %1$d mpya</item>
+ <item quantity="one">Rekodi %1$d mpya</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">Rekodi %1$d</item>
+ <item quantity="one">Rekodi %1$d</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">Rekodi %1$d zimeratibiwa</item>
+ <item quantity="one">Rekodi %1$d imeratibiwa</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Saa"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Cheza kutoka mwanzo"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Endelea kucheza"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Futa"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Futa rekodi"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Endelea"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Msimu wa <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Tazama ratiba"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Endelea kusoma"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Futa rekodi"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Chagua vipindi ambavyo ungependa kufuta. Huwezi kurejesha vipindi ulivyofuta."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Hakuna rekodi za kufuta."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Chagua vipindi ulivyotazama"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Chagua vipindi vyote"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Futa vipindi vyote"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Umetazama kwa dakika <xliff:g id="WATCHED">%1$d</xliff:g> kati ya <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Umetazama kwa sekunde <xliff:g id="WATCHED">%1$d</xliff:g> kati ya <xliff:g id="DURATION">%2$d</xliff:g>"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Hujawahi kutazama"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">Imefuta vipindi %1$d kati ya %2$d</item>
+ <item quantity="one">Imefuta kipindi %1$d kati ya %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Kipaumbele"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Juu kabisa"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Chini kabisa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Nambari <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Vituo"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Chochote"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Chagua kipaumbele"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Wakati kuna vipindi vingi vya kurekodi kwa wakati mmoja, tutarekodi vipindi vilivyopewa kipaumbele pekee."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Hifadhi"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Rekodi za mara moja hupewa kipaumbele"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Ghairi"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Ghairi"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Sahau"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Komesha"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Angalia ratiba ya kurekodi"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Mpango huu mmoja"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"sasa - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Mfululizo wote..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Endelea kuratibu"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Rekodi hii badala yake"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Ghairi rekodi hii"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Angalia sasa"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Inaweza kurekodiwa"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Kurekodi kumeratibiwa"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Hitilafu ya kurekodi"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Inarekodi"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Imeshindwa kurekodi"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Inasoma maelezo ya programu ili kuunda ratiba"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Inasoma programu"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR inahitaji nafasi zaidi ya hifadhi"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Utaweza kurekodi vipindi kwa kutumia DVR. Hata hivyo, kwa sasa hakuna hifadhi ya kutosha kwenye kifaa chako ili kuwezesha DVR kufanya kazi. Tafadhali unganisha hifadhi ya nje isiyopungua GB <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> na ufuate hatua za kuiumbiza kuwa hifadhi ya kifaa."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Hifadhi haipo"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Baadhi ya hifadhi inayotumiwa na DVR haipo. Tafadhali unganisha hifadhi ya nje uliyotumia awali ili uwashe upya DVR yako. Vinginevyo, unaweza kuchagua kusahau hifadhi ikiwa haipatikani tena."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Ungependa kusahau hifadhi?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Hatua hii itaondoa maudhui na ratiba zote ulizohifadhi."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Ungependa kuacha kurekodi?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Itahifadhi maudhui uliyorekodi."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Rekodi zimeratibiwa lakini zinakinzana"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Inaendelea kurekodi japo kuna ukinzani"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> itarekodiwa."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> inarekodiwa."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Baadhi ya sehemu za <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> hazitarekodiwa."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Baadhi ya sehemu za <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> na <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> hazitarekodiwa."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Baadhi ya sehemu za <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> na ratiba moja zaidi hazitarekodiwa."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Baadhi ya sehemu za <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> and %3$d na ratiba nyingine %3$d hazitarekodiwa.</item>
+ <item quantity="one">Baadhi ya sehemu za <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> na ratiba nyingine %3$d hazitarekodiwa.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ungependa kurekodi nini?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Ungependa kurekodi kwa muda gani?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Tayari kimeratibiwa"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Tayari umeratibu kurekodi kipindi hiki saa <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Tayari kimerekodiwa"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Tayari umerekodi kipindi hiki. Kinapatikana katika maktaba ya DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Haikupata programu iliyorekodiwa."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Rekodi zinazohusiana"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Hakuna maelezo ya programu)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">Rekodi %1$d</item>
+ <item quantity="one">Rekodi %1$d</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> imeondolewa kwenye ratiba ya kurekodi"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Haitarekodiwa yote kufuatia kukinzana kwa kitafuta vituo."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Haitarekodiwa kufuatia kukinzana kwa kitafuta vituo."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Bado hujaratibu kurekodi kipindi chochote.\nUnaweza kuratibu kutoka orodha ya vipindi."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">Itaonyesha orodha ya rekodi siku %1$d</item>
+ <item quantity="one">Itaonyesha orodha ya rekodi siku 1$d</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Mipangilio ya mfululizo"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Anza kurekodi mfululizo"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Komesha kurekodi mfululizo"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Ungependa kukomesha kurekodi mfululizo?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Vipindi vilivyorekodiwa vitaendelea kupatikana katika maktaba ya DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Komesha"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Hakuna vipindi vinavyopatikana.\nVitarekodiwa pindi vitakapopatikana."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(Dakika %1$d)</item>
+ <item quantity="one">(Dakika %1$d) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Leo"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Kesho"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Jana"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Leo <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Kesho <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Alama"</string>
</resources>
diff --git a/res/values-ta-rIN/arrays.xml b/res/values-ta-rIN/arrays.xml
index f824f4d9..9d2c1f24 100644
--- a/res/values-ta-rIN/arrays.xml
+++ b/res/values-ta-rIN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"முழு"</item>
<item msgid="8568284598210500589">"பெரிதாக்கு"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"எல்லா சேனல்களும்"</item>
- <item msgid="6897460857821394118">"குடும்பம்/குழந்தைகள்"</item>
- <item msgid="551257741825778215">"விளையாட்டு"</item>
- <item msgid="452133796804325879">"ஷாப்பிங்"</item>
- <item msgid="3296058637230163031">"திரைப்படங்கள்"</item>
- <item msgid="1054540282883891201">"நகைச்சுவை"</item>
- <item msgid="7900158429062595471">"பயணம்"</item>
- <item msgid="3768998587825611787">"நாடகம்"</item>
- <item msgid="8340620094959282881">"கல்வி"</item>
- <item msgid="7396447839483867269">"விலங்குகள்"</item>
- <item msgid="4738043455148062673">"செய்திகள்"</item>
- <item msgid="7405041316051047427">"கேமிங்"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"எல்லா சேனல்களும்"</item>
- <item msgid="7909003973960375395">"குடும்பம்/குழந்தைகள்"</item>
- <item msgid="3185279732911635789">"விளையாட்டு"</item>
- <item msgid="4704858492065325964">"ஷாப்பிங்"</item>
- <item msgid="6083795019290250078">"திரைப்படங்கள்"</item>
- <item msgid="8302638329222449550">"நகைச்சுவை"</item>
- <item msgid="3803709976021475052">"பயணம்"</item>
- <item msgid="8116747365234169059">"நாடகம்"</item>
- <item msgid="7356447541595315913">"கல்வி"</item>
- <item msgid="7511135485827589547">"விலங்குகள்"</item>
- <item msgid="6961248112238009967">"செய்திகள்"</item>
- <item msgid="6484685553679698447">"கேமிங்"</item>
- <item msgid="2737158328243183190">"கலைகள்"</item>
- <item msgid="6577176952650166615">"பொழுதுபோக்கு"</item>
- <item msgid="7886693831871777617">"வாழ்க்கை முறை"</item>
- <item msgid="8145832312485577062">"இசை"</item>
- <item msgid="1345789204804308580">"பிரீமியர்"</item>
- <item msgid="2736680312770771994">"தொழில்நுட்பம்/அறிவியல்"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"எல்லா சேனல்களும்"</item>
+ <item msgid="928298872841713530">"குடும்பம்/சிறுவர்கள்"</item>
+ <item msgid="2751606947569857164">"விளையாட்டு"</item>
+ <item msgid="7345749789651321496">"ஷாப்பிங்"</item>
+ <item msgid="167201149441442173">"மூவிகள்"</item>
+ <item msgid="525966731464264290">"நகைச்சுவை"</item>
+ <item msgid="6096710741527327836">"பயணம்"</item>
+ <item msgid="2851882187117833883">"நாடகம்"</item>
+ <item msgid="78492781188719038">"கல்வி"</item>
+ <item msgid="7221999662426308394">"விலங்குகள்"</item>
+ <item msgid="375300513250925001">"செய்திகள்"</item>
+ <item msgid="7746320336582330410">"கேமிங்"</item>
+ <item msgid="1255741860568329178">"கலைகள்"</item>
+ <item msgid="7603949681065702867">"பொழுதுபோக்கு"</item>
+ <item msgid="4453821994746804366">"வாழ்க்கை முறை"</item>
+ <item msgid="3488534597567932843">"இசை"</item>
+ <item msgid="7452153120614274095">"ப்ரீமியர்"</item>
+ <item msgid="8215762047341133299">"தொழில்நுட்பம்/அறிவியல்"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"நேரலைச் சேனல்கள்"</item>
diff --git a/res/values-ta-rIN/rating_system_strings.xml b/res/values-ta-rIN/rating_system_strings.xml
index 1d554f06..ae80dee6 100644
--- a/res/values-ta-rIN/rating_system_strings.xml
+++ b/res/values-ta-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ta-rIN/strings.xml b/res/values-ta-rIN/strings.xml
index c2585bcc..7d13e3cf 100644
--- a/res/values-ta-rIN/strings.xml
+++ b/res/values-ta-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"முந்தையது"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"நிகழ்ச்சிக் கையேடு"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"புதிய சேனல்கள் உள்ளன"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"இணைப்பு இல்லை"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>ஐத் திற"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"விரிவான வசனங்கள்"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"காட்சிப் பயன்முறை"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"துணை மதிப்பிடல்கள்"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"இந்தச் சேனலைப் பார்க்க பின்னை உள்ளிடவும்"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"இந்த நிகழ்ச்சியைப் பார்க்க பின்னை உள்ளிடவும்"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"இந்த நிகழ்ச்சி <xliff:g id="RATING">%1$s</xliff:g> என மதிப்பிடப்பட்டுள்ளது. நிகழ்ச்சியைப் பார்க்க, உங்கள் பின்னை உள்ளிடவும்"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"பின்னை உள்ளிடவும்"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"பெற்றோர் கட்டுப்பாடுகளை அமைக்க, PINஐ உருவாக்கவும்"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"புதிய PINஐ உள்ளிடவும்"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ஓப்பன் சோர்ஸ் உரிமங்கள்"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ஓப்பன் சோர்ஸ் உரிமங்கள்"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"பதிப்பு"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"நேரலைச் சேனல்களை மேம்படுத்த உதவு"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"உபயோகம் மற்றும் பிழை ஆய்வுகள் தரவை அநாமதேயமாக Google உடன் பகிரும், இதன் மூலம் எங்களால் நேரலை சேனல்களை மேலும் சிறப்பாக்க முடியும் மற்றும் சிதைவு, செயல்படாமல் இருத்தல் போன்ற சிக்கல்களைத் தடுக்க முடியும்."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"இந்தச் சேனலைப் பார்க்க, வலது பக்கம் அழுத்தி, உங்கள் PINஐ உள்ளிடவும்"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"இந்த நிகழ்ச்சியைப் பார்க்க, வலது பக்கம் அழுத்தி PINஐ உள்ளிடவும்"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"இந்த நிகழ்ச்சி <xliff:g id="RATING">%1$s</xliff:g> என மதிப்பிடப்பட்டுள்ளது.\nஅதைப் பார்க்க, வலது பக்கம் அழுத்தி, பின்னை உள்ளிடவும்."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ஆடியோ மட்டும்"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"வலுவற்ற சிக்னல்"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"இணைய இணைப்பு இல்லை"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">மற்ற சேனல்கள் ரெக்கார்டு செய்யப்படுவதால், <xliff:g id="END_TIME_1">%1$s</xliff:g> வரை இந்தச் சேனலை இயக்க முடியாது. \n\nரெக்கார்டு செய்வதற்கான திட்ட அட்டவணையில் மாற்றம் செய்ய, \"Right\" என்பதை அழுத்தவும்.</item>
+ <item quantity="one">மற்றொரு சேனல் ரெக்கார்டு செய்யப்படுவதால், <xliff:g id="END_TIME_0">%1$s</xliff:g> வரை இந்தச் சேனலை இயக்க முடியாது. \n\nரெக்கார்டு செய்வதற்கான திட்ட அட்டவணையில் மாற்றம் செய்ய, \"Right\" என்பதை அழுத்தவும்.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"தலைப்பு இல்லை"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"சேனல் தடுக்கப்பட்டது"</string>
<string name="setup_category_new" msgid="2899355289563443627">"புதியவை"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"சேனல்கள் எதுவுமில்லை"</string>
<string name="setup_input_new" msgid="3337725672277046798">"புதியவை"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"அமைக்கப்படவில்லை"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"கூடுதல் மூலங்களைப் பெறுக"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"நேரலை சேனல்களை வழங்கும் பயன்பாடுகளைத் தேடுக"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"கூடுதல் ஆதாரங்களைப் பெறுக"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"நேரலை சேனல்களை வழங்கும் பயன்பாடுகளைத் தேடலாம்"</string>
<string name="new_sources_title" msgid="3878933676500061895">"புதிய சேனல் மூலங்கள் உள்ளன"</string>
<string name="new_sources_description" msgid="749649005588426813">"புதிய சேனல் மூலங்களில் பல சேனல்களைப் பெறலாம்.\nஅவற்றை இப்போதே அமைக்கவும் அல்லது சேனல் மூலங்கள் அமைப்பில் பிறகு அமைக்கவும்."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"இப்போது அமை"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"எல்லா சேனல்களும் மறைக்கப்பட்டுள்ளன.\nபார்க்க, ஒரு சேனலையாவது தேர்ந்தெடுக்கவும்."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"வீடியோ கிடைக்கவில்லை"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Back விசை இணைத்த சாதனத்திற்கானது. வெளியேற, Home பட்டனை அழுத்துக."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop இல் இயங்கும் இந்தச் சாதனத்தில் நேரலைச் சேனல்களுக்கு ஆதரவில்லை."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"டிவி பட்டியல்களைப் படிக்க, நேரலைச் சேனல்களுக்கு அனுமதி தேவை."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"மூலங்களை அமைக்கவும்"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"நேரலைச் சேனல்களானது பயன்பாடுகள் வழங்கும் ஸ்ட்ரீமிங் சேனல்களுடன் பாரம்பரிய டிவி சேனல்களின் அனுபவத்தை ஒன்றிணைக்கிறது. \n\nஏற்கனவே நிறுவிய சேனல் மூலங்களை அமைப்பதன் மூலம் தொடங்கவும் அல்லது நேரலைச் சேனல்களை வழங்கும் கூடுதல் பயன்பாடுகளைப் பெற, Google Play ஸ்டோரில் தேடவும்."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ரெக்கார்டிங்குகள் &amp; திட்ட அட்டவணைகள்"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 நிமிடங்கள்"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 நிமிடங்கள்"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 மணிநேரம்"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 மணிநேரம்"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"சமீபத்தியவை"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"திட்டமிடப்பட்டது"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"தொடர்"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"மற்றவை"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"இந்தச் சேனலை ரெக்கார்டு செய்ய முடியாது."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"இந்த நிகழ்ச்சியை ரெக்கார்டு செய்ய முடியாது."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ரெக்கார்டு செய்வதற்காகத் திட்டமிடப்பட்டது"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"இப்போதிலிருந்து <xliff:g id="ENDTIME">%2$s</xliff:g> வரை <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ரெக்கார்டு செய்யப்படுகிறது"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"முழுத் திட்ட அட்டவணை"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">அடுத்த %1$d நாட்கள்</item>
+ <item quantity="one">அடுத்த %1$d நாள்</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d நிமிடங்கள்</item>
+ <item quantity="one">%1$d நிமிடம்</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d புதிய ரெக்கார்டிங்குகள்</item>
+ <item quantity="one">%1$d புதிய ரெக்கார்டிங்</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d ரெக்கார்டிங்குகள்</item>
+ <item quantity="one">%1$d ரெக்கார்டிங்</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d ரெக்கார்டிங்குகள் திட்டமிடப்பட்டன</item>
+ <item quantity="one">%1$d ரெக்கார்டிங் திட்டமிடப்பட்டது</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"இயக்கு"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"முதலிலிருந்து இயக்கு"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"மீண்டும் தொடங்கு"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"நீக்கு"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ரெக்கார்டிங்குகளை நீக்கு"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"மீண்டும்தொடங்கு"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"சீசன் <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"ஷெட்யூலை காட்டு"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"மேலும் படிக்க"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ரெக்கார்டிங்குகளை நீக்கு"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"நீக்க விரும்பும் எபிசோடுகளைத் தேர்ந்தெடுக்கவும். ஒருமுறை நீக்கிவிட்டால், அவற்றை மீட்டெடுக்க முடியாது."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"நீக்குவதற்கான ரெக்கார்டிங்குகள் இல்லை."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"பார்த்த எபிசோடுகளை தேர்ந்தெடு"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"எல்லாம் தேர்ந்தெடு"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"எல்லாம் தேர்வு நீக்கு"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> இல் <xliff:g id="WATCHED">%1$d</xliff:g> நிமிடங்கள் பார்த்துள்ளீர்கள்"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> இல் <xliff:g id="WATCHED">%1$d</xliff:g> வினாடிகள் பார்த்துள்ளீர்கள்"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"இதுவரை பார்க்காதவை"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d இல் %1$d எபிசோடுகள் நீக்கப்பட்டன</item>
+ <item quantity="one">%2$d இல் %1$d எபிசோடு நீக்கப்பட்டது</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"முன்னுரிமை"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"மிக அதிக முன்னுரிமை"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"மிகக்குறைந்த முன்னுரிமை"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"முன்னுரிமை: <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"சேனல்கள்"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"எந்தச் சேனலும்"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"முன்னுரிமையைத் தேர்வுசெய்க"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"ஒரே நேரத்தில் பல நிகழ்ச்சிகளை ரெக்கார்டு செய்ய வேண்டியிருந்தால், அதிக முன்னுரிமைகளைக் கொண்ட நிகழ்ச்சிகள் மட்டுமே ரெக்கார்டு செய்யப்படும்."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"சேமி"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ஒரே முறை ரெக்கார்டு செய்யக்கூடியவற்றுக்கு மிக அதிக முன்னுரிமை வழங்கு"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"ரத்துசெய்"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"ரத்துசெய்"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"நீக்கு"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"நிறுத்து"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ரெக்கார்டிங் ஷெட்யூலைக் காட்டு"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"இந்த நிகழ்ச்சியை மட்டும்"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"இப்போதிலிருந்து <xliff:g id="ENDTIME">%1$s</xliff:g> வரை"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"தொடர் முழுவதும்…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"பரவாயில்லை, திட்டமிடு"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"பதிலாக, இதை ரெக்கார்டு செய்"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"இந்த ரெக்கார்டிங்கை ரத்துசெய்"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"இப்போது காட்டு"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"ரெக்கார்டு செய்யக்கூடியது"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ரெக்கார்டிங் திட்டமிடப்பட்டது"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ரெக்கார்டிங்கில் முரண்பாடு"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ரெக்கார்ட் செய்யப்படுகிறது"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ரெக்கார்டு செய்ய முடியவில்லை"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"ரெக்கார்டிங் ஷெட்யூல்களை உருவாக்க, நிகழ்ச்சிகளைப் படிக்கிறது"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"நிகழ்ச்சிகளைப் படிக்கிறது"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVRக்கு அதிகச் சேமிப்பிடம் தேவை"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"நீங்கள் DVR மூலம் நிகழ்ச்சிகளைப் பதிவுசெய்ய முடியும். எனினும், DVR சரியாக வேலை செய்வதற்குத் தேவைப்படும் போதுமான சேமிப்பகம் இப்போது சாதனத்தில் இல்லை. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>ஜி.பை. அல்லது அதற்கும் அதிகமான அளவில் உள்ள வெளிப்புற இயக்ககத்தை இணைக்கவும். பின் அதைச் சாதனச் சேமிப்பகமாகப் பயன்படுத்த, இந்தப் படிகளைப் பின்பற்றவும்."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"சேமிப்பகம் இல்லை"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR பயன்படுத்தும் சேமிப்பகம் இல்லை. DVRஐ மீண்டும் இயக்கும் முன், நீங்கள் பயன்படுத்தும் வெளிப்புற டிரைவை இணைக்கவும். மாற்றுவழியாக, சேமிப்பகத்தை இனி பயன்படுத்த மாட்டீர்கள் எனில், அதை நீக்கும்படியும் தேர்ந்தெடுக்கலாம்."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"சேமிப்பகத்தை நீக்கவா?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"பதிவுசெய்த உள்ளடக்கத்தையும் திட்ட அட்டவணைகளையும் இழப்பீர்கள்."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ரெக்கார்டு செய்வதை நிறுத்தவா?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ரெக்கார்டு செய்த உள்ளடக்கம் சேமிக்கப்படும்."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ரெக்கார்டிங் திட்டமிடப்பட்டது, ஆனால் முரண்பாடுகள் உள்ளன"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ரெக்கார்டு செய்வது தொடங்கப்பட்டது, ஆனால் முரண்பாடுகள் உள்ளன"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ரெக்கார்டு செய்யப்படும்."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> ரெக்கார்டு செய்யப்படுகிறது."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> இன் சில பகுதிகள் ரெக்கார்டு செய்யப்படாது."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ஆகியவற்றின் சில பகுதிகள் ரெக்கார்டு செய்யப்படாது."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> இன் சில பகுதிகளும், ரெக்கார்டு செய்யத் திட்டமிட்டிருந்த மேலும் ஒரு நிகழ்ச்சியும் ரெக்கார்டு செய்யப்படாது."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ஆகியவற்றின் சில பகுதிகளும், ரெக்கார்டு செய்யத் திட்டமிட்டிருந்த மேலும் %3$d நிகழ்ச்சிகளும் ரெக்கார்டு செய்யப்படாது.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ஆகியவற்றின் சில பகுதிகளும், ரெக்கார்டு செய்யத் திட்டமிட்டிருந்த மேலும் %3$d நிகழ்ச்சியும் ரெக்கார்டு செய்யப்படாது.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"எதை ரெக்கார்டு செய்ய விரும்புகிறீர்கள்?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"எவ்வளவு நேரம் ரெக்கார்டு செய்ய விரும்புகிறீர்கள்?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ஏற்கனவே திட்டமிடப்பட்டுள்ளது"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>க்கு ரெக்கார்டு செய்வதற்காக இந்த நிகழ்ச்சி ஏற்கனவே திட்டமிடப்பட்டுள்ளது."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ஏற்கனவே ரெக்கார்டு செய்யப்பட்டது"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"இந்த நிகழ்ச்சி ஏற்கனவே ரெக்கார்டு செய்யப்பட்டது. மேலும் DVR நூலகத்தில் கிடைக்கும்."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ரெக்கார்டு செய்த நிகழ்ச்சி இல்லை."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"தொடர்புடைய ரெக்கார்டிங்குகள்"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(நிகழ்ச்சி விளக்கம் இல்லை)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d ரெக்கார்டிங்குகள்</item>
+ <item quantity="one">%1$d ரெக்கார்டிங்</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"ரெக்கார்டிங் திட்ட அட்டவணையிலிருந்து <xliff:g id="PROGRAMNAME">%1$s</xliff:g> அகற்றப்பட்டது"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ட்யூனர் இல்லாததால், பகுதியளவு ரெக்கார்டு செய்யப்படும்."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ட்யூனர் இல்லாததால், ரெக்கார்டு செய்யப்படாது."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ரெக்கார்டு செய்வதற்காக எதுவும் திட்டமிடப்படவில்லை.\nநிகழ்ச்சி வழிகாட்டிக்குச் சென்று, ரெக்கார்டிங்கைத் திட்டமிடலாம்."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d ரெக்கார்டிங் முரண்பாடுகள்</item>
+ <item quantity="one">%1$d ரெக்கார்டிங் முரண்பாடு</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"தொடர் அமைப்புகள்"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"தொடர் ரெக்கார்டிங்கைத் தொடங்கு"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"தொடர் ரெக்கார்டிங்கை நிறுத்து"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"தொடர் ரெக்கார்டிங்கை நிறுத்தவா?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ரெக்கார்டு செய்யப்பட எபிசோடுகள் தொடர்ந்து DVR நூலகத்தில் இருக்கும்."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"நிறுத்து"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"எபிசோடுகள் இல்லை.\nஅவை கிடைக்கும் போது ரெக்கார்டு செய்யப்படும்."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d நிமிடங்கள்)</item>
+ <item quantity="one">(%1$d நிமிடம்) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"இன்று"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"நாளை"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"நேற்று"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"இன்று <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"நாளை <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"ஸ்கோர்"</string>
</resources>
diff --git a/res/values-te-rIN/arrays.xml b/res/values-te-rIN/arrays.xml
index b09bfa4a..de6abf32 100644
--- a/res/values-te-rIN/arrays.xml
+++ b/res/values-te-rIN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"పూర్తిగా"</item>
<item msgid="8568284598210500589">"జూమ్"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"అన్ని ఛానెల్‌లు"</item>
- <item msgid="6897460857821394118">"కుటుంబం/పిల్లలు"</item>
- <item msgid="551257741825778215">"క్రీడలు"</item>
- <item msgid="452133796804325879">"షాపింగ్"</item>
- <item msgid="3296058637230163031">"చలనచిత్రాలు"</item>
- <item msgid="1054540282883891201">"హాస్యం"</item>
- <item msgid="7900158429062595471">"ప్రయాణం"</item>
- <item msgid="3768998587825611787">"నాటకం"</item>
- <item msgid="8340620094959282881">"విద్య"</item>
- <item msgid="7396447839483867269">"జంతువు/వన్యప్రాణులు"</item>
- <item msgid="4738043455148062673">"వార్తలు"</item>
- <item msgid="7405041316051047427">"గేమ్‌లు ఆడటం"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"అన్ని ఛానెల్‌లు"</item>
- <item msgid="7909003973960375395">"కుటుంబం/పిల్లలు"</item>
- <item msgid="3185279732911635789">"క్రీడలు"</item>
- <item msgid="4704858492065325964">"షాపింగ్"</item>
- <item msgid="6083795019290250078">"చలనచిత్రాలు"</item>
- <item msgid="8302638329222449550">"హాస్యం"</item>
- <item msgid="3803709976021475052">"ప్రయాణం"</item>
- <item msgid="8116747365234169059">"నాటకం"</item>
- <item msgid="7356447541595315913">"విద్య"</item>
- <item msgid="7511135485827589547">"జంతువు/వన్యప్రాణులు"</item>
- <item msgid="6961248112238009967">"వార్తలు"</item>
- <item msgid="6484685553679698447">"గేమ్‌లు ఆడటం"</item>
- <item msgid="2737158328243183190">"కళలు"</item>
- <item msgid="6577176952650166615">"వినోదం"</item>
- <item msgid="7886693831871777617">"జీవనశైలి"</item>
- <item msgid="8145832312485577062">"సంగీతం"</item>
- <item msgid="1345789204804308580">"ప్రీమియర్"</item>
- <item msgid="2736680312770771994">"సాంకేతికం/శాస్త్రం"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"అన్ని ఛానెల్‌లు"</item>
+ <item msgid="928298872841713530">"కుటుంబం/పిల్లలు"</item>
+ <item msgid="2751606947569857164">"క్రీడలు"</item>
+ <item msgid="7345749789651321496">"షాపింగ్"</item>
+ <item msgid="167201149441442173">"చలనచిత్రాలు"</item>
+ <item msgid="525966731464264290">"హాస్యం"</item>
+ <item msgid="6096710741527327836">"ప్రయాణం"</item>
+ <item msgid="2851882187117833883">"నాటకం"</item>
+ <item msgid="78492781188719038">"విద్య"</item>
+ <item msgid="7221999662426308394">"జంతువు/వన్యప్రాణులు"</item>
+ <item msgid="375300513250925001">"వార్తలు"</item>
+ <item msgid="7746320336582330410">"గేమింగ్"</item>
+ <item msgid="1255741860568329178">"కళలు"</item>
+ <item msgid="7603949681065702867">"వినోదం"</item>
+ <item msgid="4453821994746804366">"జీవన శైలి"</item>
+ <item msgid="3488534597567932843">"సంగీతం"</item>
+ <item msgid="7452153120614274095">"ప్రీమియర్"</item>
+ <item msgid="8215762047341133299">"సాంకేతికం/శాస్త్రం"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"ప్రత్యక్ష ప్రసార ఛానెల్‌లు"</item>
diff --git a/res/values-te-rIN/rating_system_strings.xml b/res/values-te-rIN/rating_system_strings.xml
index eed71aab..6179802b 100644
--- a/res/values-te-rIN/rating_system_strings.xml
+++ b/res/values-te-rIN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-te-rIN/strings.xml b/res/values-te-rIN/strings.xml
index 0bc83633..274be2ce 100644
--- a/res/values-te-rIN/strings.xml
+++ b/res/values-te-rIN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"మునుపటి"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"ప్రోగ్రామ్ గైడ్"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"కొత్త ఛానె. ఉన్నప్పుడు"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"లింక్ అందుబాటులో లేదు"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g>ని తెరువు"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"సంవృత శీర్షికలు"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ప్రదర్శన మోడ్"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"సబ్-రేటింగ్‌లు"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ఈ ఛానెల్‌ని చూడటానికి మీ పిన్‌ని నమోదు చేయండి"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ఈ కార్యక్రమాన్ని చూడటానికి మీ పిన్‌ని నమోదు చేయండి"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"ఈ కార్యక్రమానికి <xliff:g id="RATING">%1$s</xliff:g> అని రేట్ చేయబడింది. ఈ కార్యక్రమాన్ని చూడటానికి మీ PINని నమోదు చేయండి"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"మీ పిన్‌ని నమోదు చేయండి"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"తల్లిదండ్రుల నియంత్రణలను సెట్ చేయడానికి, పిన్‌ని సృష్టించండి"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"కొత్త పిన్‌ని నమోదు చేయండి"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ఓపెన్ సోర్స్ లైసెన్స్‌లు"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ఓపెన్ సోర్స్ లైసెన్స్‌లు"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"సంస్కరణ"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ప్రత్యక్ష ప్రసార ఛానెల్‌లను మెరుగుపరచడంలో సహాయపడండి"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"అనామక వినియోగ మరియు విశ్లేషణల డేటాను Googleతో భాగస్వామ్యం చేయండి, తద్వారా మేము లైవ్ ఛానెల్‌లను మెరుగ్గా చేయగలము అలాగే క్రాష్ కావడం మరియు స్తంభించడం వంటి సమస్యలను నిరోధించగలము."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"ఈ ఛానెల్‌ను చూడటానికి, కుడివైపు బటన్ నొక్కి, మీ పిన్‌ని నమోదు చేయండి"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"ఈ ప్రోగ్రామ్‌ని చూడటానికి, కుడివైపు బటన్ నొక్కి, మీ పిన్‌ని నమోదు చేయండి"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"ఈ కార్యక్రమం <xliff:g id="RATING">%1$s</xliff:g> అని రేట్ చేయబడింది.\nఈ కార్యక్రమాన్ని చూడటానికి, కుడివైపు బటన్ నొక్కి, మీ PINని నమోదు చేయండి."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"ఆడియో మాత్రమే"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"సిగ్నల్ బలహీనంగా ఉంది"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ఇంటర్నెట్ కనెక్షన్ లేదు"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">ఇతర ఛానెల్‌లు రికార్డ్ అవుతున్నందున ఈ ఛానెల్‌ని <xliff:g id="END_TIME_1">%1$s</xliff:g> వరకు ప్లే చేయలేరు. \n\nరికార్డింగ్ షెడ్యూల్‌ను సర్దుబాటు చేయడానికి కుడివైపు నొక్కండి.</item>
+ <item quantity="one">మరొక ఛానెల్ రికార్డ్ అవుతున్నందున ఈ ఛానెల్‌ని <xliff:g id="END_TIME_0">%1$s</xliff:g> వరకు ప్లే చేయలేరు. \n\nరికార్డింగ్ షెడ్యూల్‌ను సర్దుబాటు చేయడానికి కుడివైపు నొక్కండి.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"శీర్షిక లేదు"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"ఛానెల్ బ్లాక్ చేయబడింది"</string>
<string name="setup_category_new" msgid="2899355289563443627">"కొత్తవి"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ఛానెల్‌లు ఏవీ అందుబాటులో లేవు"</string>
<string name="setup_input_new" msgid="3337725672277046798">"కొత్తవి"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"సెటప్ చేయలేదు"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"మరిన్ని మూలాలను పొందండి"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"ప్రత్యక్ష ప్రసార ఛానెల్‌లను అందించే అనువర్తనాలను బ్రౌజ్ చేయండి"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"మరిన్ని మూలాధారాలను పొందండి"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"ప్రత్యక్ష ప్రసార ఛానెల్‌లను అందించే అనువర్తనాలను బ్రౌజ్ చేయండి"</string>
<string name="new_sources_title" msgid="3878933676500061895">"కొత్త ఛానెల్ మూలాలు అందుబాటులో ఉన్నాయి"</string>
<string name="new_sources_description" msgid="749649005588426813">"కొత్త ఛానెల్ మూలాలు అందించడానికి ఛానెల్‌లను కలిగి ఉన్నాయి.\nవాటిని ఇప్పుడే సెటప్ చేయండి లేదా ఛానెల్ మూలాల సెట్టింగ్‌లో దీన్ని తర్వాత చేయండి."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ఇప్పుడే సెటప్ చేయి"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"అన్ని మూల ఛానెల్‌లు దాచబడ్డాయి.\nచూడటానికి కనీసం ఒక ఛానెల్‌ను ఎంచుకోండి."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"వీడియో ఊహించని విధంగా అందుబాటులో లేకుండా పోయింది"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"BACK కీ కనెక్ట్ చేయబడిన పరికరం కోసం ఉద్దేశించినది. నిష్క్రమించడానికి HOME బటన్‌ను నొక్కండి."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Android Lollipop అమలులో ఉన్న ఈ పరికరంలో ప్రత్యక్ష ప్రసార ఛానెల్‌లకు మద్దతు లేదు."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"టీవీ జాబితాలను చదవడానికి ప్రత్యక్ష ప్రసార ఛానెల్‌లకు అనుమతి అవసరం."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"మీ మూలాధారాలను సెటప్ చేయండి"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"ప్రత్యక్ష ప్రసార ఛానెల్‌లు అనువర్తనాల ద్వారా అందించబడే ప్రసార ఛానెల్‌ల్లో సాంప్రదాయక టీవీ ఛానెల్‌ల అనుభూతి కలగలిపి అందించబడతాయి. \n\nఇప్పటికే ఇన్‌స్టాల్ చేసుకున్న ఛానెల్ మూలాధారాలను సెటప్ చేయడం ద్వారా ప్రారంభించండి. లేదా ప్రత్యక్ష ప్రసార ఛానెల్‌లను ఆఫర్ చేసే మరిన్ని అనువర్తనాల కోసం Google Play స్టోర్‌లో బ్రౌజ్ చేయండి."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"రికార్డింగ్‌లు &amp; షెడ్యూల్‌లు"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 నిమిషాలు"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 నిమిషాలు"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 గంట"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 గంటలు"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ఇటీవలివి"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"షెడ్యూల్ చేసినవి"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"సిరీస్"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"ఇతరం"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ఛానెల్‌ను రికార్డ్ చేయడం సాధ్యపడదు."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"కార్యక్రమాన్ని రికార్డ్ చేయడం సాధ్యపడదు."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> రికార్డ్ చేయడం కోసం షెడ్యూల్ చేయబడింది"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"ఇప్పటి నుండి <xliff:g id="ENDTIME">%2$s</xliff:g> వరకు <xliff:g id="PROGRAMNAME">%1$s</xliff:g> రికార్డ్ చేస్తుంది"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"పూర్తి షెడ్యూల్"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">తదుపరి %1$d రోజులు</item>
+ <item quantity="one">తదుపరి %1$d రోజు</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d నిమిషాలు</item>
+ <item quantity="one">%1$d నిమిషం</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d కొత్త రికార్డింగ్‌లు</item>
+ <item quantity="one">%1$d కొత్త రికార్డింగ్</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d రికార్డింగ్‌లు</item>
+ <item quantity="one">%1$d రికార్డింగ్</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d రికార్డింగ్‌లు చేయాలి</item>
+ <item quantity="one">%1$d రికార్డింగ్ చేయాలి</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"చూడండి"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"మొదటి నుండి ప్లే చేయి"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"ప్లే చేయడం కొనసాగించు"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"తొలగించు"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"రికార్డింగ్‌లను తొలగించు"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"పునఃప్రారంభించు"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"సీజన్ <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"షెడ్యూల్ చూడండి"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"మరింత చదవండి"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"రికార్డింగ్‌లు తొలగించు"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"మీరు తొలగించాలనుకునే ఎపిసోడ్‌లను ఎంచుకోండి. వీటిని ఒకసారి తొలగించాక తిరిగి పునరుద్ధరించలేరు."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"తొలగించడానికి రికార్డింగ్‌లు ఏవీ లేవు."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"చూసిన ఎపిసోడ్‌లను ఎంచుకోండి"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"అన్ని ఎపిసోడ్‌లను ఎంచుకోండి"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"అన్ని ఎపిసోడ్‌ల ఎంపిక తీసివేయి"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> నిమిషాల్లో <xliff:g id="WATCHED">%1$d</xliff:g> సమయం చూసారు"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> సెకన్లలో <xliff:g id="WATCHED">%1$d</xliff:g> సమయం చూసారు"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"ఎప్పుడూ చూడలేదు"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$dలో %1$d ఎపిసోడ్‌లు తొలగించబడ్డాయి</item>
+ <item quantity="one">%2$dలో %1$d ఎపిసోడ్ తొలగించబడింది</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ప్రాధాన్యత"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"అత్యధికం"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"అతి తక్కువ"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"వద్దు. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ఛానెల్‌లు"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ఏదైనా"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ప్రాధాన్యతను ఎంచుకోండి"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"ఒకే సమయంలో చాలా ఎక్కువ కార్యక్రమాలు రికార్డ్ చేయాల్సినప్పుడు, అధిక ప్రాధాన్యతలు గలవి మాత్రమే రికార్డ్ చేయబడతాయి."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"సేవ్ చేయి"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"ఒక పర్యాయ రికార్డింగ్‌లు అత్యధిక ప్రాధాన్యతను కలిగి ఉంటాయి"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"రద్దు చేయి"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"రద్దు చేయి"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"విస్మరించు"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"ఆపివేయి"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"రికార్డింగ్ షెడ్యూల్ చూడండి"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"ఈ ఒక్క కార్యక్రమం"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ఇప్పటి నుండి - <xliff:g id="ENDTIME">%1$s</xliff:g> వరకు"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"మొత్తం సిరీస్…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"ఏదేమైనా షెడ్యూల్ చేయి"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"బదులుగా దీన్ని రికార్డ్ చేయి"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ఈ రికార్డింగ్‌ను రద్దు చేయి"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ఇప్పుడే చూడండి"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"రికార్డ్ చేయవచ్చు"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"రికార్డింగ్ షెడ్యూల్ చేయబడింది"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"రికార్డింగ్ వైరుధ్యం"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"రికార్డ్ అవుతోంది"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"రికార్డింగ్ విఫలమైంది"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"రికార్డింగ్ షెడ్యూళ్లను రూపొందించడానికి కార్యక్రమాలను చదువుతోంది"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"కార్యక్రమాలను చదువుతోంది"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVRకు మరింత నిల్వ అవసరం"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"మీరు DVRతో కార్యక్రమాలను రికార్డ్ చేయగలుగుతారు. అయితే, ప్రస్తుతం DVR పని చేయడానికి మీ పరికరంలో తగినంత నిల్వ ఖాళీ లేదు. దయచేసి <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB లేదా అంతకంటే ఎక్కువ ఖాళీ స్థలం గల బయటి డ్రైవ్‌ను కనెక్ట్ చేసి, ఆపై దాన్ని పరికర నిల్వగా ఫార్మాట్ చేయడానికి సూచనలను అనుసరించండి."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"నిల్వ కనిపించడం లేదు"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR ద్వారా ఉపయోగించబడిన కొంత నిల్వ కనిపించడం లేదు. దయచేసి DVRని పునఃప్రారంభించడానికి మీరు ఇంతకుముందు ఉపయోగించిన బయటి డిస్క్‌ను కనెక్ట్ చేయండి. లేదంటే, అది అందుబాటులో లేని పక్షంలో మీరు ఆ నిల్వను విస్మరించమని ఎంచుకోవచ్చు."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"నిల్వను విస్మరించాలా?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"మీ మొత్తం రికార్డ్ చేసిన కంటెంట్‌ను మరియు షెడ్యూల్‌లను కోల్పోతారు."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"రికార్డింగ్ ఆపివేయాలా?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"రికార్డ్ అయిన కంటెంట్ సేవ్ చేయబడుతుంది."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"రికార్డింగ్ షెడ్యూల్ చేయబడింది కానీ మిగిలిన వాటితో వైరుధ్యాలను కలిగి ఉంది"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"రికార్డింగ్ ప్రారంభమైంది, కానీ వైరుధ్యాలను కలిగి ఉంది"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> రికార్డ్ చేయబడుతుంది."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> రికార్డ్ అవుతోంది."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>లో కొన్ని భాగాలు రికార్డ్ చేయబడవు."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> మరియు <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>లో కొన్ని భాగాలు రికార్డ్ చేయబడవు."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>లో కొన్ని భాగాలు మరియు మరొక షెడ్యూల్ రికార్డ్ చేయబడవు."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>లో కొన్ని భాగాలు మరియు మరో %3$d షెడ్యూల్‌లు రికార్డ్ చేయబడవు.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>లో కొన్ని భాగాలు మరియు మరో %3$d షెడ్యూల్ రికార్డ్ చేయబడవు.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"మీరు ఏమి రికార్డ్ చేయాలనుకుంటున్నారు?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"మీరు ఎంత సమయం రికార్డ్ చేయాలనుకుంటున్నారు?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"ఇప్పటికే షెడ్యూల్ చేయబడింది"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"ఇదే కార్యక్రమం ఇప్పటికే <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>కి రికార్డ్ చేయడానికి షెడ్యూల్ చేయబడింది."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"ఇప్పటికే రికార్డ్ అయింది"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"ఈ ప్రోగ్రామ్ ఇప్పటికే రికార్డ్ అయింది. ఇది DVR లైబ్రరీలో అందుబాటులో ఉంది."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"రికార్డ్ చేసిన కార్యక్రమం కనుగొనబడలేదు."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"సంబంధిత రికార్డింగ్‌లు"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(కార్యక్రమం వివరణ లేదు)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d రికార్డింగ్‌లు</item>
+ <item quantity="one">%1$d రికార్డింగ్</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> రికార్డింగ్ షెడ్యూల్ నుండి తీసివేయబడింది"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ట్యూనర్ వైరుధ్యాల కారణంగా పాక్షికంగా రికార్డ్ చేయబడుతుంది."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ట్యూనర్ వైరుధ్యాల కారణంగా రికార్డ్ చేయబడదు."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ఇంకా షెడ్యూల్ చేసిన రికార్డింగ్‌లు ఏవీ లేవు.\nమీరు కార్యక్రమాల గైడ్ నుండి రికార్డింగ్‌ను షెడ్యూల్ చేయవచ్చు."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d రికార్డింగ్ వైరుధ్యాలు ఉన్నాయి</item>
+ <item quantity="one">%1$d రికార్డింగ్ వైరుధ్యం ఉంది</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"సిరీస్ సెట్టింగ్‌లు"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"సిరీస్ రికార్డింగ్ ఆరంభించు"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"సిరీస్ రికార్డింగ్ ఆపివేయి"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"సిరీస్ రికార్డింగ్‌ను ఆపివేయాలా?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"రికార్డ్ అయిన ఎపిసోడ్‌లు DVR లైబ్రరీలో అలాగే అందుబాటులో ఉంటాయి."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"ఆపివేయి"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ఎపిసోడ్‌లు ఏవీ అందుబాటులో లేవు.\nఇవి అందుబాటులోకి వచ్చిన వెంటనే రికార్డ్ చేయబడతాయి."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d నిమిషాలు)</item>
+ <item quantity="one">(%1$d నిమిషం) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ఈ రోజు"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"రేపు"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"నిన్న"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ఈ రోజు"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> రేపు"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"స్కోర్"</string>
</resources>
diff --git a/res/values-th/arrays.xml b/res/values-th/arrays.xml
index e7e63988..105725f8 100644
--- a/res/values-th/arrays.xml
+++ b/res/values-th/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"เต็มจอ"</item>
<item msgid="8568284598210500589">"ซูม"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"ช่องทั้งหมด"</item>
- <item msgid="6897460857821394118">"ครอบครัว/เด็ก"</item>
- <item msgid="551257741825778215">"กีฬา"</item>
- <item msgid="452133796804325879">"ช็อปปิ้ง"</item>
- <item msgid="3296058637230163031">"ภาพยนตร์"</item>
- <item msgid="1054540282883891201">"ตลก"</item>
- <item msgid="7900158429062595471">"ท่องเที่ยว"</item>
- <item msgid="3768998587825611787">"ดราม่า"</item>
- <item msgid="8340620094959282881">"การศึกษา"</item>
- <item msgid="7396447839483867269">"สัตว์/สัตว์ป่า"</item>
- <item msgid="4738043455148062673">"ข่าวสาร"</item>
- <item msgid="7405041316051047427">"เกม"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"ช่องทั้งหมด"</item>
- <item msgid="7909003973960375395">"ครอบครัว/เด็ก"</item>
- <item msgid="3185279732911635789">"กีฬา"</item>
- <item msgid="4704858492065325964">"ช็อปปิ้ง"</item>
- <item msgid="6083795019290250078">"ภาพยนตร์"</item>
- <item msgid="8302638329222449550">"ตลก"</item>
- <item msgid="3803709976021475052">"ท่องเที่ยว"</item>
- <item msgid="8116747365234169059">"ดราม่า"</item>
- <item msgid="7356447541595315913">"การศึกษา"</item>
- <item msgid="7511135485827589547">"สัตว์/สัตว์ป่า"</item>
- <item msgid="6961248112238009967">"ข่าวสาร"</item>
- <item msgid="6484685553679698447">"เกม"</item>
- <item msgid="2737158328243183190">"ศิลปะ"</item>
- <item msgid="6577176952650166615">"ความบันเทิง"</item>
- <item msgid="7886693831871777617">"ไลฟ์สไตล์"</item>
- <item msgid="8145832312485577062">"เพลง"</item>
- <item msgid="1345789204804308580">"ปฐมทัศน์"</item>
- <item msgid="2736680312770771994">"วิทยาศาสตร์/เทคฯ"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"ช่องทั้งหมด"</item>
+ <item msgid="928298872841713530">"ครอบครัว/เด็ก"</item>
+ <item msgid="2751606947569857164">"กีฬา"</item>
+ <item msgid="7345749789651321496">"ช็อปปิ้ง"</item>
+ <item msgid="167201149441442173">"ภาพยนตร์"</item>
+ <item msgid="525966731464264290">"ตลก"</item>
+ <item msgid="6096710741527327836">"การเดินทาง"</item>
+ <item msgid="2851882187117833883">"ดราม่า"</item>
+ <item msgid="78492781188719038">"การศึกษา"</item>
+ <item msgid="7221999662426308394">"สัตว์/สัตว์ป่า"</item>
+ <item msgid="375300513250925001">"ข่าวสาร"</item>
+ <item msgid="7746320336582330410">"เกม"</item>
+ <item msgid="1255741860568329178">"ศิลปะ"</item>
+ <item msgid="7603949681065702867">"บันเทิง"</item>
+ <item msgid="4453821994746804366">"ไลฟ์สไตล์"</item>
+ <item msgid="3488534597567932843">"เพลง"</item>
+ <item msgid="7452153120614274095">"ปฐมทัศน์"</item>
+ <item msgid="8215762047341133299">"วิทยาศาสตร์/เทคฯ"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"รายการถ่ายทอดสด"</item>
diff --git a/res/values-th/rating_system_strings.xml b/res/values-th/rating_system_strings.xml
index 1e6fd44a..c9942b30 100644
--- a/res/values-th/rating_system_strings.xml
+++ b/res/values-th/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 997d6fcb..8424e9bb 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"ก่อนหน้า"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"คู่มือโปรแกรม"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"มีช่องใหม่ให้บริการ"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"ไม่มีลิงก์"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"เปิด <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"คำบรรยาย"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"โหมดการแสดงผล"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"การจัดประเภทย่อย"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"ป้อน PIN ของคุณเพื่อดูช่องนี้"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"ป้อน PIN ของคุณเพื่อดูโปรแกรมนี้"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"รายการนี้จัดอยู่ในประเภท <xliff:g id="RATING">%1$s</xliff:g> ป้อน PIN เพื่อดูรายการนี้"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"ป้อน PIN ของคุณ"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"หากต้องการตั้งค่าการควบคุมโดยผู้ปกครอง โปรดสร้าง PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"ป้อน PIN ใหม่"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"ใบอนุญาตโอเพนซอร์ส"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"ใบอนุญาตโอเพนซอร์ส"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"เวอร์ชัน"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"ช่วยปรับปรุง Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"แชร์ข้อมูลการใช้งานและการวินิจฉัยที่ไม่ระบุชื่อกับ Google เพื่อให้เราสามารถทำให้รายการถ่ายทอดสดดีขึ้น และป้องกันปัญหาต่างๆ เช่น การขัดข้องและการค้าง"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"หากต้องการดูช่องนี้ ให้กดขวาและป้อน PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"หากต้องการดูโปรแกรมนี้ ให้กดขวาและป้อน PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"โปรแกรมนี้เรต <xliff:g id="RATING">%1$s</xliff:g>\nในการดูโปรแกรมนี้ โปรดกดขวาและป้อน PIN"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"เฉพาะเสียง"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"สัญญาณไม่ดี"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"ไม่มีการเชื่อมต่ออินเทอร์เน็ต"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">ช่องนี้ไม่สามารถเล่นได้จนถึง <xliff:g id="END_TIME_1">%1$s</xliff:g> เพราะกำลังบันทึกช่องอื่นๆ อยู่ \n\nกดขวาเพื่อปรับกำหนดการบันทึก</item>
+ <item quantity="one">ช่องนี้ไม่สามารถเล่นได้จนถึง <xliff:g id="END_TIME_0">%1$s</xliff:g> เพราะกำลังบันทึกอีกช่องอยู่ \n\nกดขวาเพื่อปรับกำหนดการบันทึก</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"ไม่มีชื่อ"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"บล็อกช่องแล้ว"</string>
<string name="setup_category_new" msgid="2899355289563443627">"ใหม่"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"ไม่มีช่องให้บริการ"</string>
<string name="setup_input_new" msgid="3337725672277046798">"ใหม่"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"ไม่ได้ตั้งค่า"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"รับแหล่งที่มาเพิ่มเติม"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"เรียกดูแอปที่เสนอรายการถ่ายทอดสด"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"รับแหล่งที่มาเพิ่มเติม"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"เรียกดูแอปที่เสนอรายการถ่ายทอดสด"</string>
<string name="new_sources_title" msgid="3878933676500061895">"มีแหล่งที่มาของช่องใหม่"</string>
<string name="new_sources_description" msgid="749649005588426813">"แหล่งที่มาของช่องใหม่มีหลายช่องมาให้ใช้งาน\nตั้งค่าช่องเลยตอนนี้ หรือทำในภายหลังในการตั้งค่าแหล่งที่มาของช่อง"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ตั้งค่าเลย"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"ช่องแหล่งที่มาทั้งหมดซ่อนอยู่\nเลือกอย่างน้อย 1 ช่องเพื่อดู"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"วิดีโอไม่พร้อมใช้งานด้วยเหตุบางประการ"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"แป้นกลับมีไว้สำหรับอุปกรณ์ที่เชื่อมต่อ กดปุ่มหน้าแรกเพื่อออก"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Live TV ไม่ได้รับการสนับสนุนบนอุปกรณ์นี้ซึ่งมี Android Lollipop"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Live TV ต้องใช้สิทธิ์ในการอ่านรายการทีวี"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"ตั้งค่าแหล่งที่มา"</string>
- <string name="setup_sources_description" msgid="5695518946225445202">"รายการถ่ายทอดสดมอบประสบการณ์ที่ผสมผสานระหว่างช่องทีวีแบบดั้งเดิมกับช่องแบบสตรีมโดยแอป\n\nเริ่มต้นใช้งานได้โดยตั้งค่าแหล่งที่มาของช่องที่ติดตั้งไว้แล้ว หรือเรียกดู Google Play สโตร์เพื่อค้นหาแอปอื่นๆ ที่เสนอรายการถ่ายทอดสด"</string>
+ <string name="setup_sources_description" msgid="5695518946225445202">"รายการถ่ายทอดสดมอบประสบการณ์ที่ผสมผสานระหว่างช่องทีวีแบบดั้งเดิมกับช่องแบบสตรีมโดยแอป\n\nเริ่มต้นใช้งานได้โดยตั้งค่าแหล่งที่มาของช่องที่ติดตั้งไว้แล้ว หรือเรียกดู Google Play Store เพื่อค้นหาแอปอื่นๆ ที่เสนอรายการถ่ายทอดสด"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"การบันทึกและกำหนดการ"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 นาที"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 นาที"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ชั่วโมง"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 ชั่วโมง"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"ล่าสุด"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"กำหนดเวลาไว้"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"ซีรี่ส์"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"อื่นๆ"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"ไม่สามารถบันทึกช่องได้"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"ไม่สามารถบันทึกรายการได้"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"ตั้งกำหนดการบันทึก <xliff:g id="PROGRAMNAME">%1$s</xliff:g> แล้ว"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"กำลังบันทึก <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ตั้งแต่ตอนนี้ถึง <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"กำหนดการทั้งหมด"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d วันถัดไป</item>
+ <item quantity="one">%1$d วันถัดไป</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d นาที</item>
+ <item quantity="one">%1$d นาที</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">การบันทึกใหม่ %1$d รายการ</item>
+ <item quantity="one">การบันทึกใหม่ %1$d รายการ</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">การบันทึก %1$d รายการ</item>
+ <item quantity="one">การบันทึก %1$d รายการ</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">กำหนดเวลาบันทึกแล้ว %1$d รายการ</item>
+ <item quantity="one">กำหนดเวลาบันทึกแล้ว %1$d รายการ</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"ดู"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"เล่นจากจุดเริ่มต้น"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"เล่นต่อจากที่ค้างไว้"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"ลบ"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ลบการบันทึก"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"เล่นต่อ"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"ซีซัน <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"ดูกำหนดเวลา"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"อ่านเพิ่มเติม"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ลบการบันทึก"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"เลือกตอนที่ต้องการลบ โปรดทราบว่าเมื่อลบแล้วจะกู้คืนไม่ได้"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"ไม่มีการบันทึกที่จะลบ"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"เลือกตอนที่เคยดู"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"เลือกทุกตอน"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"ยกเลิกทุกตอนที่เลือกไว้"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"ดูแล้ว <xliff:g id="WATCHED">%1$d</xliff:g> จาก <xliff:g id="DURATION">%2$d</xliff:g> นาที"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"ดูแล้ว <xliff:g id="WATCHED">%1$d</xliff:g> จาก <xliff:g id="DURATION">%2$d</xliff:g> วินาที"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"ไม่เคยดู"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">ลบแล้ว %1$d จาก %2$d ตอน</item>
+ <item quantity="one">ลบแล้ว %1$d จาก %2$d ตอน</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ความสำคัญ"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"สูงสุด"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"ต่ำสุด"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"อันดับที่ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"ช่อง"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"ทั้งหมด"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"เลือกลำดับความสำคัญ"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"เมื่อต้องบันทึกรายการหลายรายการพร้อมกันมากเกินไป ระบบจะบันทึกเฉพาะรายการที่มีลำดับความสำคัญสูงกว่าเท่านั้น"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"บันทึก"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"การบันทึกครั้งเดียวมีความสำคัญสูงสุด"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"ยกเลิก"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"ยกเลิก"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"ไม่จำ"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"หยุด"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ดูกำหนดการบันทึก"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"โปรแกรมนี้เท่านั้น"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ตอนนี้ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"ทุกตอน…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"กำหนดเวลาต่อไป"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"บันทึกรายการนี้แทน"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"ยกเลิกการบันทึกนี้"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ดูตอนนี้"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"สามารถบันทึกได้"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"กำหนดเวลาบันทึกแล้ว"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ตารางบันทึกชนกัน"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"กำลังบันทึก"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"การบันทึกล้มเหลว"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"กำลังอ่านรายการเพื่อสร้างกำหนดเวลาการบันทึก"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"กำลังอ่านรายการ"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR ต้องการพื้นที่เก็บข้อมูลเพิ่มเติม"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"คุณจะสามารถบันทึกรายการด้วย DVR ได้ อย่างไรก็ตาม ตอนนี้อุปกรณ์ของคุณมีพื้นที่เก็บข้อมูลไม่เพียงพอสำหรับให้ DVR ทำงาน โปรดเชื่อมต่อไดรฟ์ภายนอกที่มีขนาด <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB ขึ้นไป และทำตามขั้นตอนเพื่อฟอร์แมตไดรฟ์ให้เป็นพื้นที่เก็บข้อมูลของอุปกรณ์"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"พื้นที่เก็บข้อมูลหายไป"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"พื้นที่เก็บข้อมูลบางส่วนที่ DVR ใช้หายไป โปรดเชื่อมต่อไดรฟ์ภายนอกที่คุณใช้ก่อนเปิดใช้ DVR อีกครั้ง หรือคุณอาจเลือกไม่จำพื้นที่เก็บข้อมูลหากพื้นที่เก็บข้อมูลไม่พร้อมใช้งานอีกต่อไป"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"ไม่จำพื้นที่เก็บข้อมูลใช่ไหม"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"เนื้อหาและกำหนดการทั้งหมดที่คุณบันทึกไว้จะหายไป"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"หยุดบันทึกใช่ไหม"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ระบบจะเก็บเนื้อหาที่บันทึกไว้"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"กำหนดการบันทึกรายการชนกัน"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"เริ่มบันทึกรายการแล้ว แต่กำหนดการชนกัน"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"ระบบจะบันทึก <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"กำลังบันทึก <xliff:g id="CHANNELNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"บางส่วนของ <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> จะไม่มีการบันทึก"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"บางส่วนของ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> และ <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> จะไม่มีการบันทึก"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"บางส่วนของ <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> และอีก 1 รายการที่กำหนดไว้จะไม่มีการบันทึก"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">บางส่วนของ <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> และอีก %3$d รายการที่กำหนดไว้จะไม่มีการบันทึก</item>
+ <item quantity="one">บางส่วนของ <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> และอีก %3$d รายการที่กำหนดไว้จะไม่มีการบันทึก</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"คุณต้องการบันทึกอะไร"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"คุณต้องการบันทึกนานแค่ไหน"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"กำหนดเวลาไว้แล้ว"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"มีกำหนดบันทึกรายการเดียวกันนี้แล้วเวลา <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"บันทึกไว้แล้ว"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"บันทึกรายการนี้ไว้แล้ว สามารถดูได้ที่ห้องสมุด DVR"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ไม่พบโปรแกรมที่บันทึกไว้"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"การบันทึกที่เกี่ยวข้อง"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(ไม่มีรายละเอียดรายการ)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">การบันทึก %1$d รายการ</item>
+ <item quantity="one">การบันทึก %1$d รายการ</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"นำ <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ออกจากกำหนดการบันทึกแล้ว"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ระบบจะบันทึกไว้บางส่วนเนื่องจากมีข้อขัดแย้งของตัวรับสัญญาณ"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ระบบจะไม่บันทึกเนื่องจากมีข้อขัดแย้งของตัวรับสัญญาณ"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ยังไม่มีการบันทึกในกำหนดการ\nคุณสามารถกำหนดเวลาบันทึกจากคู่มือรายการทีวี"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">ตารางบันทึกชนกัน %1$d รายการ</item>
+ <item quantity="one">ตารางบันทึกชนกัน %1$d รายการ</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"การตั้งค่าซีรีส์"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"เริ่มบันทึกซีรีส์"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"หยุดบันทึกซีรีส์"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"หยุดบันทึกซีรีส์ไหม"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"ตอนที่บันทึกไว้จะยังคงอยู่ในไลบรารี DVR"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"หยุด"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"ไม่มีตอนที่พร้อมรับชม\nระบบจะเริ่มบันทึกเมื่อมีตอนที่พร้อมรับชม"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d นาที)</item>
+ <item quantity="one">(%1$d นาที) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"วันนี้"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"พรุ่งนี้"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"เมื่อวานนี้"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> วันนี้"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> พรุ่งนี้"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"คะแนน"</string>
</resources>
diff --git a/res/values-tl/arrays.xml b/res/values-tl/arrays.xml
index 8b31c423..3c1bf603 100644
--- a/res/values-tl/arrays.xml
+++ b/res/values-tl/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Buo"</item>
<item msgid="8568284598210500589">"Mag-zoom"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Lahat ng channel"</item>
- <item msgid="6897460857821394118">"Pampamilya/Pambata"</item>
- <item msgid="551257741825778215">"Sports"</item>
- <item msgid="452133796804325879">"Pamimili"</item>
- <item msgid="3296058637230163031">"Mga Pelikula"</item>
- <item msgid="1054540282883891201">"Komedya"</item>
- <item msgid="7900158429062595471">"Paglalakbay"</item>
- <item msgid="3768998587825611787">"Drama"</item>
- <item msgid="8340620094959282881">"Edukasyon"</item>
- <item msgid="7396447839483867269">"Hayop/Wildlife"</item>
- <item msgid="4738043455148062673">"Balita"</item>
- <item msgid="7405041316051047427">"Gaming"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Lahat ng channel"</item>
- <item msgid="7909003973960375395">"Pampamilya/Pambata"</item>
- <item msgid="3185279732911635789">"Sports"</item>
- <item msgid="4704858492065325964">"Pamimili"</item>
- <item msgid="6083795019290250078">"Mga Pelikula"</item>
- <item msgid="8302638329222449550">"Komedya"</item>
- <item msgid="3803709976021475052">"Paglalakbay"</item>
- <item msgid="8116747365234169059">"Drama"</item>
- <item msgid="7356447541595315913">"Edukasyon"</item>
- <item msgid="7511135485827589547">"Hayop/Wildlife"</item>
- <item msgid="6961248112238009967">"Balita"</item>
- <item msgid="6484685553679698447">"Gaming"</item>
- <item msgid="2737158328243183190">"Sining"</item>
- <item msgid="6577176952650166615">"Entertainment"</item>
- <item msgid="7886693831871777617">"Lifestyle"</item>
- <item msgid="8145832312485577062">"Musika"</item>
- <item msgid="1345789204804308580">"Premier"</item>
- <item msgid="2736680312770771994">"Teknolohiya/Agham"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Lahat ng channel"</item>
+ <item msgid="928298872841713530">"Pampamilya/Pambata"</item>
+ <item msgid="2751606947569857164">"Sports"</item>
+ <item msgid="7345749789651321496">"Pamimili"</item>
+ <item msgid="167201149441442173">"Mga Pelikula"</item>
+ <item msgid="525966731464264290">"Komedya"</item>
+ <item msgid="6096710741527327836">"Paglalakbay"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Edukasyon"</item>
+ <item msgid="7221999662426308394">"Hayop/Wildlife"</item>
+ <item msgid="375300513250925001">"Balita"</item>
+ <item msgid="7746320336582330410">"Paglalaro"</item>
+ <item msgid="1255741860568329178">"Sining"</item>
+ <item msgid="7603949681065702867">"Entertainment"</item>
+ <item msgid="4453821994746804366">"Estilo ng Pamumuhay"</item>
+ <item msgid="3488534597567932843">"Musika"</item>
+ <item msgid="7452153120614274095">"Premier"</item>
+ <item msgid="8215762047341133299">"Teknolohiya/Agham"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Mga Live na Channel"</item>
diff --git a/res/values-tl/rating_system_strings.xml b/res/values-tl/rating_system_strings.xml
index e1f9f940..cfe190b5 100644
--- a/res/values-tl/rating_system_strings.xml
+++ b/res/values-tl/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index a3645c0f..a925aee6 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Nakaraan"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Gabay sa programa"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"May mga bagong channel"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Walang available link"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Buksan ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Closed captions"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Display mode"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Mga sub-rating"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Ilagay iyong PIN upang mapanood ang channel na ito"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Ilagay iyong PIN upang mapanood ang programang ito"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"May rating na <xliff:g id="RATING">%1$s</xliff:g> ang programang ito. Ilagay ang iyong PIN upang mapanood ang programang ito"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Ilagay ang iyong PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Upang itakda ang mga parental control, gumawa ng PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Ilagay ang bagong PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Mga open source na lisensya"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Mga lisensyang open source"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Bersyon"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Tulungang pahusayin ang Mga Live na Channel"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Magbahagi ng anonymous na data ng paggamit at mga diagnostic sa Google upang mas mapaganda namin ang Mga Live Channel at mapigilan ang mga isyu tulad ng pagka-crash at pagfi-freeze."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Upang mapanood ang channel na ito, pindutin ang Kanan at ilagay ang iyong PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Upang mapanood ang programang ito, pindutin ang Kanan at ilagay ang iyong PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ang programang ito ay na-rate na <xliff:g id="RATING">%1$s</xliff:g>.\nUpang mapanood ang programang ito, pindutin ang Kanan at ilagay ang iyong PIN."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Audio lang"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Mahinang signal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Walang koneksyon sa internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Hindi mape-play ang channel na ito hanggang <xliff:g id="END_TIME_1">%1$s</xliff:g> dahil nagre-record ng iba pang mga channel. \n\nPindutin ang Kanan upang i-adjust ang iskedyul sa pagre-record.</item>
+ <item quantity="other">Hindi mape-play ang channel na ito hanggang <xliff:g id="END_TIME_1">%1$s</xliff:g> dahil nagre-record ng iba pang mga channel. \n\nPindutin ang Kanan upang i-adjust ang iskedyul sa pagre-record.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Walang pamagat"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Naka-block ang channel"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Bago"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Walang mga channel na available"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Bago"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Hindi naka-set up"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Kumuha ng higit pang mga mapagkukunan"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Mag-browse ng mga app na nag-aalok ng mga live channel"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Kumuha ng higit pang mga mapagkukunan"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Mag-browse ng mga app na nag-aalok ng mga live channel"</string>
<string name="new_sources_title" msgid="3878933676500061895">"May mga bagong mapagkukunan ng channel"</string>
<string name="new_sources_description" msgid="749649005588426813">"May mga inaalok na channel ang mga bagong mapagkukunan ng channel.\nI-set up na ang mga ito ngayon, o gawin ito sa ibang pagkakataon sa setting ng mga pinagkukunan ng channel."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"I-set up ngayon"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Nakatago ang lahat ng pinagmumulang channel.\nPumili ng kahit isang channel lang na papanoorin."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Hindi inaasahang hindi available ang video"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Ang BACK key ay para sa nakakonektang device. Pindutin ang HOME button upang lumabas."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Hindi sinusuportahan ang Live TV sa device na ito na may Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Kailangan ng pahintulot ng Live TV upang mabasa ang mga listahan sa TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"I-set up ang iyong mga pinagmulan"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Mapapanood sa mga live channel ang mga ipinapalabas sa mga nakasanayan nang TV channel at sa mga streaming channel na mula sa mga app. \n\nMagsimula sa pamamagitan ng pagse-set up ng mga pinagmulan ng channel na naka-install na. O mag-browse sa Google Play Store para sa higit pang mga app na nag-aalok ng mga live na channel."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Mga recording &amp; iskedyul"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 minuto"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 minuto"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 oras"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 oras"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Kamakailan"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Nakaiskedyul"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Mga Serye"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Iba Pa"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Hindi ma-record ang channel."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Hindi ma-record ang programa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Naiskedyul nang i-record ang <xliff:g id="PROGRAMNAME">%1$s</xliff:g>"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Nire-record ang <xliff:g id="PROGRAMNAME">%1$s</xliff:g> mula ngayon hanggang <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Buong iskedyul"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Susunod na %1$d araw</item>
+ <item quantity="other">Susunod na %1$d na araw</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d minuto</item>
+ <item quantity="other">%1$d na minuto</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d bagong recording</item>
+ <item quantity="other">%1$d na bagong recording</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d recording</item>
+ <item quantity="other">%1$d na recording</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d recording ang nakaiskedyul</item>
+ <item quantity="other">%1$d na recording ang nakaiskedyul</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Panoorin"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"I-play mula sa simula"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Ituloy ang pag-play"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"I-delete"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Mag-delete ng mga recording"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Ituloy"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Season <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Tingnan ang iskedyul"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Magbasa pa"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"I-delete recordings"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Piliin ang mga episode na gusto mong i-delete. Hindi na mababawi ang mga ito sa sandaling ma-delete."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Walang mga recording na ide-delete."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Piliin mga napanood na episode"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Piliin lahat ng episode"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Huwag piliin lahat ng episode"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> sa <xliff:g id="DURATION">%2$d</xliff:g> (na) minuto ang napanood"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> sa <xliff:g id="DURATION">%2$d</xliff:g> (na) segundo ang napanood"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Hindi pa napapanood"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d sa %2$d episode ang na-delete</item>
+ <item quantity="other">%1$d sa %2$d na episode ang na-delete</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Priyoridad"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Pinakamataas"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Pinakamababa"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"No. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Mga Channel"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Kahit ano"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Pumili ng priyoridad"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Kapag masyadong maraming programa ang ire-record nang sabay-sabay, tanging ang may mas mataas na priyoridad lang ang mare-record."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"I-save"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Ang mga isang beses na pagre-record ang may pinakamataas na priyoridad"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Kanselahin"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Kanselahin"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Kalimutan"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Ihinto"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Tingnan, iskedyul ng recording"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Ang isang programang ito"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ngayon - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Buong serye…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Iiskedyul pa rin"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Ito na lang ang i-record"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Kanselahin ang pag-record na ito"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Panoorin ngayon"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Mare-record"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Nakaiskedyul ang recording"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"May conflict sa pagre-record"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Nagre-record"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Hindi na-record"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Nagbabasa ng mga program upang makagawa ng mga iskedyul ng pagre-record"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Binabasa ang mga programa"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Kailangan ng DVR ng higit pang storage"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Makakapag-record ka ng mga program gamit ang DVR. Gayunpaman, walang sapat na storage sa iyong device ngayon upang gumana ang DVR. Mangyaring magkonekta ng external drive na <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB o mas malaki at sundin ang mga hakbang upang i-format ito bilang storage ng device."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Nawawala ang storage"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"May nawawalang bahagi ng storage na ginagamit ng DVR. Pakikonekta ang external na drive na ginamit mo dati upang muling i-enable ang DVR. O kaya, maaari mo ring piliing kalimutan ang storage kung hindi na ito available."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Kalimutan ang storage?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Mawawala ang lahat ng na-record mong content at iskedyul."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Ihinto ang pagre-record?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Mase-save ang na-record na content."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Naiskedyul na ang pagre-record ngunit may mga hindi pagkakatugma"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Nagsimula na ang pagre-record ngunit may mga hindi pagkakatugma"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Mare-record ang <xliff:g id="PROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Nire-record ang <xliff:g id="CHANNELNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Hindi mare-record ang ilang bahagi ng <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Hindi mare-record ang ilang bahagi ng <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> at <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Hindi mare-record ang ilang bahagi ng <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> at isa pang nakaiskedyul."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Hindi mare-record ang ilang bahagi ng <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> at %3$d pang nakaiskedyul.</item>
+ <item quantity="other">Hindi mare-record ang ilang bahagi ng <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> at %3$d pang nakaiskedyul.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ano ang gusto mong i-record?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Gaano katagal mo gustong mag-record?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Nakaiskedyul na"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Naiskedyul na ang parehong programa na ma-record sa <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Na-record na"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Na-record na ang programang ito. Available ito sa DVR library."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Hindi nakita ang na-record na programa."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Mga nauugnay na recording"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Walang paglalarawan ng program)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d recording</item>
+ <item quantity="other">%1$d na recording</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Inalis ang <xliff:g id="PROGRAMNAME">%1$s</xliff:g> sa iskedyul ng pagre-record"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Bahagyang mare-record dahil sa mga problema sa tuner."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Hindi mare-record dahil sa mga problema sa tuner."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Wala pang nakaiskedyul na mga pagre-record.\nMaaari kang mag-iskedyul ng pagre-record sa gabay sa programa."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d kasabay na recording</item>
+ <item quantity="other">%1$d na kasabay na recording</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Mga setting ng mga serye"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Simulan ang pagre-record ng mga serye"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Ihinto ang pagre-record ng mga serye"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Gusto mo bang ihinto ang pagre-record ng mga serye?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Mananatiling available sa library ng DVR ang mga na-record na episode."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Ihinto"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Walang available na mga episode.\nMare-record ang mga ito kapag available na ang mga ito."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d minuto)</item>
+ <item quantity="other">(%1$d na minuto)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Ngayong araw"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Bukas"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Kahapon"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ngayong araw"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> bukas"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Marka"</string>
</resources>
diff --git a/res/values-tr/arrays.xml b/res/values-tr/arrays.xml
index 5ef36030..3dfd8e76 100644
--- a/res/values-tr/arrays.xml
+++ b/res/values-tr/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Tam"</item>
<item msgid="8568284598210500589">"Zum"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Tüm kanallar"</item>
- <item msgid="6897460857821394118">"Aile/Çocuk"</item>
- <item msgid="551257741825778215">"Spor"</item>
- <item msgid="452133796804325879">"Alışveriş"</item>
- <item msgid="3296058637230163031">"Filmler"</item>
- <item msgid="1054540282883891201">"Komedi"</item>
- <item msgid="7900158429062595471">"Seyahat"</item>
- <item msgid="3768998587825611787">"Dram"</item>
- <item msgid="8340620094959282881">"Eğitim"</item>
- <item msgid="7396447839483867269">"Hayvanlar/Vahşi Doğa"</item>
- <item msgid="4738043455148062673">"Haberler"</item>
- <item msgid="7405041316051047427">"Oyun"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Tüm kanallar"</item>
- <item msgid="7909003973960375395">"Aile/Çocuk"</item>
- <item msgid="3185279732911635789">"Spor"</item>
- <item msgid="4704858492065325964">"Alışveriş"</item>
- <item msgid="6083795019290250078">"Filmler"</item>
- <item msgid="8302638329222449550">"Komedi"</item>
- <item msgid="3803709976021475052">"Seyahat"</item>
- <item msgid="8116747365234169059">"Dram"</item>
- <item msgid="7356447541595315913">"Eğitim"</item>
- <item msgid="7511135485827589547">"Hayvanlar/Vahşi Doğa"</item>
- <item msgid="6961248112238009967">"Haberler"</item>
- <item msgid="6484685553679698447">"Oyun"</item>
- <item msgid="2737158328243183190">"Sanat"</item>
- <item msgid="6577176952650166615">"Eğlence"</item>
- <item msgid="7886693831871777617">"Yaşam Tarzı"</item>
- <item msgid="8145832312485577062">"Müzik"</item>
- <item msgid="1345789204804308580">"İlk Gösterim"</item>
- <item msgid="2736680312770771994">"Teknoloji/Bilim"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Tüm kanallar"</item>
+ <item msgid="928298872841713530">"Aile/Çocuk"</item>
+ <item msgid="2751606947569857164">"Spor"</item>
+ <item msgid="7345749789651321496">"Alışveriş"</item>
+ <item msgid="167201149441442173">"Filmler"</item>
+ <item msgid="525966731464264290">"Komedi"</item>
+ <item msgid="6096710741527327836">"Seyahat"</item>
+ <item msgid="2851882187117833883">"Dram"</item>
+ <item msgid="78492781188719038">"Eğitim"</item>
+ <item msgid="7221999662426308394">"Hayvanlar/Vahşi Yaşam"</item>
+ <item msgid="375300513250925001">"Haberler"</item>
+ <item msgid="7746320336582330410">"Oyun"</item>
+ <item msgid="1255741860568329178">"Sanat"</item>
+ <item msgid="7603949681065702867">"Eğlence"</item>
+ <item msgid="4453821994746804366">"Yaşam Tarzı"</item>
+ <item msgid="3488534597567932843">"Müzik"</item>
+ <item msgid="7452153120614274095">"İlk Gösterim"</item>
+ <item msgid="8215762047341133299">"Teknoloji/Bilim"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Canlı Yayın Kanalları"</item>
diff --git a/res/values-tr/rating_system_strings.xml b/res/values-tr/rating_system_strings.xml
index 232be2c8..47046c29 100644
--- a/res/values-tr/rating_system_strings.xml
+++ b/res/values-tr/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 92829fa3..8162fbfa 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Önceki"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Program rehberi"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Yeni kanallar mevcut"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Bağlantı mevcut değil"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını aç"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Altyazılar"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Görüntü modu"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Alt derecelendirme"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Bu kanalı izlemek için PIN\'inizi girin"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Bu programı izlemek için PIN\'inizi girin"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Bu program <xliff:g id="RATING">%1$s</xliff:g> olarak derecelendirildi. Bu programı izlemek için PIN kodunuzu girin."</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN\'inizi girin"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ebeveyn denetimlerini ayarlamak için PIN oluşturun"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Yeni PIN\'i girin"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Açık kaynak lisansları"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Açık kaynak lisansları"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Sürüm"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Live TV\'ı iyileştirmeye yardımcı ol"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Canlı Kanallar\'ı daha iyi hale getirebilmemiz ve kilitlenme, donma gibi sorunları önleyebilmemeiz için anonim kullanım ve teşhis verilerini Google ile paylaşın."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Bu kanalı izlemek için Sağ tuşuna basın ve PIN\'inizi girin"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Bu programı izlemek için Sağ tuşuna basın ve PIN\'inizi girin"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Bu program <xliff:g id="RATING">%1$s</xliff:g> olarak derecelendirilmiştir.\nBu programı izlemek için Sağ tuşuna basın ve PIN\'inizi girin."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Yalnızca ses"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Zayıf sinyal"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"İnternet bağlantısı yok"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Şu anda başka kanallar kaydedildiğinden bu kanal şu saatten önce oynatılamaz: <xliff:g id="END_TIME_1">%1$s</xliff:g>. \n\nKayıt zaman planını düzenlemek için Sağ\'a basın.</item>
+ <item quantity="one">Şu anda başka bir kanal kaydedildiğinden bu kanal şu saatten önce oynatılamaz: <xliff:g id="END_TIME_0">%1$s</xliff:g>. \n\nKayıt zaman planını düzenlemek için Sağ\'a basın.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Başlıksız"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal engellendi"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Yeni"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Kullanılabilir kanal yok"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Yeni"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Yapılandırılmadı"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Daha fazla kaynak al"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Canlı kanallar sunan uygulamalara göz at"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Daha fazla kaynak al"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Canlı kanallar sunan uygulamalara göz atın"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Kullanılabilir yeni kanal kaynakları mevcut"</string>
<string name="new_sources_description" msgid="749649005588426813">"Yeni kanal kaynaklarında sunulan kanallar var.\nBunları şimdi ayarlayın veya daha sonra kanal kaynakları ayarında yapılandırın."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Şimdi ayarla"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Tüm kaynak kanalları gizli.\nİzlemek için en az bir tane kanal seçin."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video beklenmedik şekilde kullanılamıyor"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"GERİ tuşu bağlı cihazlar içindir. Çıkmak için ANA SAYFA düğmesine basın."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Bu cihazda Android Lollipop ile Canlı Kanallar desteklenmemektedir."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Canlı Kanallar\'ın TV kanal listesini okuması için izin gerekiyor."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Kaynaklarınızı ayarlayın"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Canlı kanallar, geleneksel TV kanallarının deneyimini uygulamalar tarafından sağlanan kanal akışlarıyla birleştirir. \n\nHalihazırda yüklü kanal kaynaklarını ayarlayarak başlayın. İsterseniz canlı kanallar sunan diğer uygulamalar için Google Play Store\'a göz atabilirsiniz."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Kayıtlar ve programlar"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 dakika"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 dakika"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 saat"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 saat"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Son kayıtlar"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Programlananlar"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Diziler"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Diğerleri"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Kanal kaydedilemiyor."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Program kaydedilemiyor."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> kaydedilmek üzere programlandı"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> adlı program şu andan itibaren şu saate kadar kaydedilecek: <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Tam program"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Sonraki %1$d gün</item>
+ <item quantity="one">Sonraki %1$d gün</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d dakika</item>
+ <item quantity="one">%1$d dakika</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d yeni kayıt</item>
+ <item quantity="one">%1$d yeni kayıt</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d kayıt</item>
+ <item quantity="one">%1$d kayıt</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d kayıt planlandı</item>
+ <item quantity="one">%1$d kayıt planlandı</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"İzle"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Baştan oynat"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Oynatmaya devam et"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Sil"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Kayıtları sil"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Devam ettir"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>. Sezon"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Programı göster"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Daha fazla okuyun"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Kayıtları silin"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Silmek istediğiniz bölümleri seçin. Bölümler silindikten sonra geri alınamaz."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Silinecek kayıt yok."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"İzlenen bölümleri seç"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Tüm bölümleri seç"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Tüm bölümlerin seçimini kaldır"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> olan toplam sürenin <xliff:g id="WATCHED">%1$d</xliff:g> dakikası izlendi"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> olan toplam sürenin <xliff:g id="WATCHED">%1$d</xliff:g> saniyesi izlendi"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"İzlenmedi"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%2$d bölümün %1$d tanesi silindi</item>
+ <item quantity="one">%2$d bölümün %1$d tanesi silindi</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Öncelik"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"En yüksek"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"En düşük"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Sıra: <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanallar"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Tüm kanallar"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Öncelik seçin"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Aynı anda kaydedilecek çok sayıda program olduğundan, yalnızca yüksek öncelikli programlar kaydedilir."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Kaydet"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Bir kerelik kayıtlar en yüksek önceliğe sahip"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"İptal"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"İptal"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Unut"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Durdur"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Kayıt programını görüntüle"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Yalnızca bu program"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"şimdi - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Dizinin tamamı…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Yine de programla"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Onun yerine bunu kaydet"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Bu kaydı iptal et"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Şimdi izle"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Kaydedilebilir"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Kayıt programlandı"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Kayıt çakışması"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Kaydediliyor"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Kaydedilemedi"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Kayıt planlarını oluşturmak için programlar okunuyor"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Program bilgisi okunuyor"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR için daha fazla depolama alanı gerekiyor"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Programları DVR ile kaydedebileceksiniz. Ancak şu anda cihazınızda DVR\'nin çalışması için yeterli miktarda boş depolama alanı yok. Lütfen <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB veya daha büyük kapasiteye sahip harici sürücü bağlayın ve bu sürücüyü cihaz depolama alanı olarak biçimlendirmek için adımları uygulayın."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Kayıp depolama birimi"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"DVR tarafından kullanılan bazı depolama alanları kayıp. DVR\'yi yeniden etkinleştirmeden önce lütfen kullandığınız harici sürücüyü bağlayın. Ayrıca bu depolama alanı artık kullanılmıyorsa unutulmasını da seçebilirsiniz."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Depolama alanı unutulsun mu?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Kaydedilen tüm içeriğiniz ve programlarınız kaybolacaktır."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Kayıt durudurulsun mu?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Kaydedilen içerik saklanacak."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Kayıt programlandı, ancak çakışmalar var"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Kayıt işlemi başladı, ancak çakışmalar var"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> kaydedilecek."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> kaydediliyor."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> adlı programın bazı bölümleri kaydedilmeyecek."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ve <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> adlı programların bazı bölümleri kaydedilmeyecek."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ve diğer bir programın bazı bölümleri kaydedilmeyecek."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> ve diğer %3$d programın bazı bölümleri kaydedilmeyecek.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> ve diğer %3$d programın bazı bölümleri kaydedilmeyecek.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ne kaydetmek istiyorsunuz?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Ne kadar süre kayıt yapılmasını istiyorsunuz?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Zaten programlandı"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Aynı program şu tarihte ve saatte kaydedilecek şekilde zaten programlandı: <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Zaten kaydedildi"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Bu program zaten kaydedildi. DVR kitaplığında bulabilirsiniz."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Kaydedilen program bulunamadı."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"İlgili kayıtlar"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Program açıklaması yok)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d kayıt</item>
+ <item quantity="one">%1$d kayıt</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>, kayıt programından kaldırıldı"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Kanal ayarlayıcı çakışması nedeniyle tamamı kaydedilmeyecek."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Kanal ayarlayıcı çakışması nedeniyle kaydedilemeyecek."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Henüz programa alınmış bir kayıt yok.\nKayıtları, program rehberinden programlayabilirsiniz."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d kayıt çakışması</item>
+ <item quantity="one">%1$d kayıt çakışması</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Dizi ayarları"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Dizi kaydetmeye başla"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Dizi kaydetmeyi durdur"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Dizinin kaydı durdurulsun mu?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Kaydedilen bölümler DVR kitaplığında kalmaya devam edecektir."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Durdur"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Kaydedilebilecek bir bölüm yok.\nBölümler kullanıma sunulduğunda kaydedilecektir."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d dakika)</item>
+ <item quantity="one">(%1$d dakika) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Bugün"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Yarın"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Dün"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Bugün <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Yarın <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Puanı"</string>
</resources>
diff --git a/res/values-uk/arrays.xml b/res/values-uk/arrays.xml
index 2fa994ef..4dba1d71 100644
--- a/res/values-uk/arrays.xml
+++ b/res/values-uk/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"На весь екран"</item>
<item msgid="8568284598210500589">"Масштабування"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Усі канали"</item>
- <item msgid="6897460857821394118">"Сім’я та діти"</item>
- <item msgid="551257741825778215">"Спорт"</item>
- <item msgid="452133796804325879">"Покупки"</item>
- <item msgid="3296058637230163031">"Фільми"</item>
- <item msgid="1054540282883891201">"Комедії"</item>
- <item msgid="7900158429062595471">"Подорожі"</item>
- <item msgid="3768998587825611787">"Драми"</item>
- <item msgid="8340620094959282881">"Освіта"</item>
- <item msgid="7396447839483867269">"Тварини та природа"</item>
- <item msgid="4738043455148062673">"Новини"</item>
- <item msgid="7405041316051047427">"Ігри"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Усі канали"</item>
- <item msgid="7909003973960375395">"Сім’я та діти"</item>
- <item msgid="3185279732911635789">"Спорт"</item>
- <item msgid="4704858492065325964">"Покупки"</item>
- <item msgid="6083795019290250078">"Фільми"</item>
- <item msgid="8302638329222449550">"Комедії"</item>
- <item msgid="3803709976021475052">"Подорожі"</item>
- <item msgid="8116747365234169059">"Драми"</item>
- <item msgid="7356447541595315913">"Освіта"</item>
- <item msgid="7511135485827589547">"Тварини та природа"</item>
- <item msgid="6961248112238009967">"Новини"</item>
- <item msgid="6484685553679698447">"Ігри"</item>
- <item msgid="2737158328243183190">"Мистецтво"</item>
- <item msgid="6577176952650166615">"Розваги"</item>
- <item msgid="7886693831871777617">"Стиль життя"</item>
- <item msgid="8145832312485577062">"Музика"</item>
- <item msgid="1345789204804308580">"Популярне"</item>
- <item msgid="2736680312770771994">"Наука й техніка"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Усі канали"</item>
+ <item msgid="928298872841713530">"Сім’я та діти"</item>
+ <item msgid="2751606947569857164">"Спорт"</item>
+ <item msgid="7345749789651321496">"Покупки"</item>
+ <item msgid="167201149441442173">"Фільми"</item>
+ <item msgid="525966731464264290">"Комедія"</item>
+ <item msgid="6096710741527327836">"Подорожі"</item>
+ <item msgid="2851882187117833883">"Драма"</item>
+ <item msgid="78492781188719038">"Освіта"</item>
+ <item msgid="7221999662426308394">"Тварини та природа"</item>
+ <item msgid="375300513250925001">"Новини"</item>
+ <item msgid="7746320336582330410">"Ігри"</item>
+ <item msgid="1255741860568329178">"Мистецтво"</item>
+ <item msgid="7603949681065702867">"Розваги"</item>
+ <item msgid="4453821994746804366">"Стиль життя"</item>
+ <item msgid="3488534597567932843">"Музика"</item>
+ <item msgid="7452153120614274095">"Популярне"</item>
+ <item msgid="8215762047341133299">"Наука й техніка"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Телеканали"</item>
diff --git a/res/values-uk/rating_system_strings.xml b/res/values-uk/rating_system_strings.xml
index 27afc388..9962350b 100644
--- a/res/values-uk/rating_system_strings.xml
+++ b/res/values-uk/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 2b4dfddc..b9d91a7a 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Назад"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Програма передач"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Доступні нові канали"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Немає посилання"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Відкрити додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Субтитри"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Режим показу"</string>
@@ -126,6 +125,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Підкатегорії"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Введіть PIN-код, щоб дивитися цей канал"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Введіть PIN-код, щоб дивитися цю телепередачу"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Вікові обмеження для цієї передачі: <xliff:g id="RATING">%1$s</xliff:g>. Щоб дивитися її, введіть PIN-код"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Введіть PIN-код"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Щоб налаштувати батьківський контроль, створіть PIN-код"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Введіть новий PIN-код"</string>
@@ -148,8 +148,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Ліцензії відкритого коду"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Ліцензії ПЗ з відкритим кодом"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Версія"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Допомагати покращити додаток Live TV"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Надсилати в Google анонімні дані про використання та діагностику. Це допоможе нам покращити додаток Телеканали та вирішити такі проблеми, як аварійне завершення роботи й зависання."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Щоб дивитися цей канал, натисніть стрілку праворуч і введіть PIN-код"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Щоб дивитися цю телепередачу, натисніть стрілку праворуч і введіть PIN-код"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Ця телепередача належить до категорії <xliff:g id="RATING">%1$s</xliff:g>.\nЩоб дивитися її, натисніть стрілку праворуч і введіть PIN-код."</string>
@@ -161,6 +159,12 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Лише аудіо"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Слабкий сигнал"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Немає з’єднання з Інтернетом"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Вміст цього каналу не відтворюватиметься до <xliff:g id="END_TIME_1">%1$s</xliff:g>, оскільки записуються інші канали. \n\nНатисніть стрілку \"Управо\", щоб змінити графік запису.</item>
+ <item quantity="few">Вміст цього каналу не відтворюватиметься до <xliff:g id="END_TIME_1">%1$s</xliff:g>, оскільки записуються інші канали. \n\nНатисніть стрілку \"Управо\", щоб змінити графік запису.</item>
+ <item quantity="many">Вміст цього каналу не відтворюватиметься до <xliff:g id="END_TIME_1">%1$s</xliff:g>, оскільки записуються інші канали. \n\nНатисніть стрілку \"Управо\", щоб змінити графік запису.</item>
+ <item quantity="other">Вміст цього каналу не відтворюватиметься до <xliff:g id="END_TIME_1">%1$s</xliff:g>, оскільки записуються інші канали. \n\nНатисніть стрілку \"Управо\", щоб змінити графік запису.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Без назви"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Канал заблоковано"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Нові джерела"</string>
@@ -174,8 +178,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Немає доступних каналів"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Нові"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Не налаштовано"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Отримати більше джерел"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Переглянути додатки, які пропонують телеканали"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Отримати більше джерел"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Переглянути додатки, у яких пропонуються канали в прямому ефірі"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Доступні нові джерела каналів"</string>
<string name="new_sources_description" msgid="749649005588426813">"Нові джерела пропонують канали.\nНалаштуйте їх зараз або зробіть це пізніше в налаштуваннях джерел каналів."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Налаштувати"</string>
@@ -193,8 +197,182 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Усі канали джерела сховано.\nВиберіть принаймні один канал для перегляду."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Відео недоступне з невідомої причини"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Клавіша \"НАЗАД\" діє на підключеному пристрої. Натисніть \"ГОЛОВНИЙ ЕКРАН\", щоб вийти."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Додаток Live TV не підтримується на цьому пристрої з ОС Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Додатку Live TV потрібен дозвіл переглядати програму телепередач."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Налаштуйте джерела"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"У телеканалах поєднуються зручність традиційних каналів і трансляція каналів із додатків. \n\nЩоб почати, налаштуйте вже встановлені джерела каналів. Або пошукайте в магазині Google Play інші додатки з телеканалами."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Записи та графіки"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 хвилин"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 хвилин"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 година"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 години"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Останні"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"За розкладом"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Серіал"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Інші"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Не можна записати канал."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Не можна записати передачу."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"Програму \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" заплановано для запису"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Запис передачі \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" з цього моменту до <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Повний розклад"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <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="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <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="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <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="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <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="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <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="dvr_detail_watch" msgid="7085694764364338215">"Переглянути"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Відтворити з початку"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Відновити відтворення"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Видалити"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Видалити записи"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Відновити"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Сезон <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Розклад"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Докладніше"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Видалити записи"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Виберіть серії, які потрібно видалити. Їх не можна буде відновити."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Немає записів для видалення."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Вибрати переглянуті серії"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Вибрати всі серії"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Не вибирати серій"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Переглянуто <xliff:g id="WATCHED">%1$d</xliff:g> з <xliff:g id="DURATION">%2$d</xliff:g> хв"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Переглянуто <xliff:g id="WATCHED">%1$d</xliff:g> з <xliff:g id="DURATION">%2$d</xliff:g> с"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Непереглянуті"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">Видалено %1$d серію з %2$d</item>
+ <item quantity="few">Видалено %1$d серії з %2$d</item>
+ <item quantity="many">Видалено %1$d серій із %2$d</item>
+ <item quantity="other">Видалено %1$d серії з %2$d</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Пріоритет"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Найвищий"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Найнижчий"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Немає. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Канали"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Будь-який канал"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Виберіть пріоритет"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Якщо є забагато програм для одночасного запису, записуватимуться лише програми з вищим пріоритетом."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Зберегти"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Одноразові записи мають найвищий пріоритет"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Скасувати"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Скасувати"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Забути"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Припинити"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Переглянути розклад запису"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Лише ця передача"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"Зараз – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Весь серіал…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Усе одно запланувати"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Натомість записати цю передачу"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Скасувати цей запис"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Дивитися"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Можна записати"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Запис заплановано"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Конфлікт запису"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Запис"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Не записано"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Читаються назви передач для створення розкладів"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Читання даних програм"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"Пристрою DVR потрібно більше пам’яті"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"За допомогою пристрою DVR можна записувати програми, однак на ньому недостатньо пам’яті. Підключіть зовнішній диск ємністю <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> Гб або більше та дотримуйтеся вказівок, щоб відформатувати його як пам’ять пристрою."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Немає пам’яті"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Немає деякої пам’яті, яку використовує DVR. Щоб знову ввімкнути DVR, під’єднайте зовнішній диск, який ви використовували раніше. Можна також забути пам’ять, якщо вона недоступна."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Забути пам’ять?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Увесь записаний вміст і розклади буде втрачено."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Припинити запис?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Записаний вміст буде збережено."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Запис заплановано, однак є конфлікти"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Запис почався, однак є конфлікти"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"Програму \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" буде записано."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"Записується канал \"<xliff:g id="CHANNELNAME">%1$s</xliff:g>\"."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Деякі частини програми \"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>\" не буде записано."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\" і \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" не буде записано."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>\" і ще однієї не буде записано."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" і ще %3$d не буде записано.</item>
+ <item quantity="few">Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" і ще %3$d не буде записано.</item>
+ <item quantity="many">Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" і ще %3$d не буде записано.</item>
+ <item quantity="other">Деякі частини програм \"<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>\", \"<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>\" і ще %3$d не буде записано.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Що записати?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Як довго записувати?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Уже заплановано"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Цю передачу вже заплановано записати о <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Уже записано"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Цю передачу вже записано. Вона доступна в бібліотеці DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Не вдалося знайти записані програми."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Пов’язані записи"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Немає опису програми)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <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="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Програму \"<xliff:g id="PROGRAMNAME">%1$s</xliff:g>\" видалено з розкладу запису"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Буде частково записано через конфлікти тюнера."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Не буде записано через конфлікти тюнера."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"У розкладі ще немає записів.\nВи можете запланувати запис на основі програми передач."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <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="dvr_series_schedules_settings" msgid="4868501926847903985">"Налаштування серій"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Почати запис серій"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Припинити запис серій"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Припинити запис серій?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Записані серії можна переглянути в бібліотеці DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Припинити"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Немає серій.\nСерії буде записано, щойно вони з’являться."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <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="dvr_date_today" msgid="7691050705354303471">"Сьогодні"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Завтра"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Учора"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Сьогодні о <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Завтра о <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Оцінка"</string>
</resources>
diff --git a/res/values-ur-rPK/arrays.xml b/res/values-ur-rPK/arrays.xml
index 1b581640..f54b4914 100644
--- a/res/values-ur-rPK/arrays.xml
+++ b/res/values-ur-rPK/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"مکمل"</item>
<item msgid="8568284598210500589">"زوم"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"سبھی چینلز"</item>
- <item msgid="6897460857821394118">"خاندان/بچے"</item>
- <item msgid="551257741825778215">"کھیل"</item>
- <item msgid="452133796804325879">"خریداری"</item>
- <item msgid="3296058637230163031">"موویز"</item>
- <item msgid="1054540282883891201">"کامیڈی"</item>
- <item msgid="7900158429062595471">"سفر"</item>
- <item msgid="3768998587825611787">"ڈرامہ"</item>
- <item msgid="8340620094959282881">"تعلیم"</item>
- <item msgid="7396447839483867269">"جانور/وائلڈ لائف"</item>
- <item msgid="4738043455148062673">"خبریں"</item>
- <item msgid="7405041316051047427">"گیمنگ"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"سبھی چینلز"</item>
- <item msgid="7909003973960375395">"خاندان/بچے"</item>
- <item msgid="3185279732911635789">"کھیل"</item>
- <item msgid="4704858492065325964">"خریداری"</item>
- <item msgid="6083795019290250078">"موویز"</item>
- <item msgid="8302638329222449550">"کامیڈی"</item>
- <item msgid="3803709976021475052">"سفر"</item>
- <item msgid="8116747365234169059">"ڈرامہ"</item>
- <item msgid="7356447541595315913">"تعلیم"</item>
- <item msgid="7511135485827589547">"جانور/وائلڈ لائف"</item>
- <item msgid="6961248112238009967">"خبریں"</item>
- <item msgid="6484685553679698447">"گیمنگ"</item>
- <item msgid="2737158328243183190">"فنون"</item>
- <item msgid="6577176952650166615">"تفریح"</item>
- <item msgid="7886693831871777617">"طرز زندگی"</item>
- <item msgid="8145832312485577062">"موسیقی"</item>
- <item msgid="1345789204804308580">"پریمیئر"</item>
- <item msgid="2736680312770771994">"ٹیک/سائنس"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"سبھی چینلز"</item>
+ <item msgid="928298872841713530">"خاندان/بچے"</item>
+ <item msgid="2751606947569857164">"کھیل"</item>
+ <item msgid="7345749789651321496">"خریداری"</item>
+ <item msgid="167201149441442173">"موویز"</item>
+ <item msgid="525966731464264290">"کامیڈی"</item>
+ <item msgid="6096710741527327836">"سفر"</item>
+ <item msgid="2851882187117833883">"ڈراما"</item>
+ <item msgid="78492781188719038">"تعلیم"</item>
+ <item msgid="7221999662426308394">"جانور/وائلڈ لائف"</item>
+ <item msgid="375300513250925001">"خبریں"</item>
+ <item msgid="7746320336582330410">"گیم سازی"</item>
+ <item msgid="1255741860568329178">"فنون"</item>
+ <item msgid="7603949681065702867">"تفریح"</item>
+ <item msgid="4453821994746804366">"طرز زندگی"</item>
+ <item msgid="3488534597567932843">"موسیقی"</item>
+ <item msgid="7452153120614274095">"پریمیئر"</item>
+ <item msgid="8215762047341133299">"ٹیک/سائنس"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"لائیو چینلز"</item>
diff --git a/res/values-ur-rPK/rating_system_strings.xml b/res/values-ur-rPK/rating_system_strings.xml
index f5f48c4f..07f99a99 100644
--- a/res/values-ur-rPK/rating_system_strings.xml
+++ b/res/values-ur-rPK/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-ur-rPK/strings.xml b/res/values-ur-rPK/strings.xml
index 6633f45a..47fcb2ad 100644
--- a/res/values-ur-rPK/strings.xml
+++ b/res/values-ur-rPK/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"پچھلا"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"پروگرام گائیڈ"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"نئے چینلز دستیاب ہیں"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"کوئی لنک دستیاب نہیں ہے"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> کھولیں"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"سب ٹائٹلز"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"ڈسپلے وضع"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"ذیلی درجہ بندیاں"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"‏یہ چینل دیکھنے کیلئے اپنا PIN درج کریں"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"‏یہ پروگرام دیکھنے کیلئے اپنا PIN درج کریں"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"‏اس پروگرام کی درجہ بندی <xliff:g id="RATING">%1$s</xliff:g> ہوئی ہے۔ اس پروگرام کو دیکھنے کیلئے اپنی PIN درج کریں"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"‏اپنا PIN درج کریں"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"‏پیرنٹل کنٹرولز سیٹ کرنے کیلئے، ایک PIN بنائیں"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"‏نیا PIN درج کریں"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"اوپن سورس لائسنسز"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"اوپن سورس لائسنسز"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"ورژن"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"لائیو چینلز بہتر بنانے میں مدد کریں"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"‏Google کے ساتھ گمنام استعمال اور تشخیصاتی ڈیٹا کا اشتراک کریں تاکہ ہم لائیو چینلز بہتر بنا اور کریشنگ اور فریزنگ جیسے مسائل کو روک سکیں۔"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"‏یہ چینل دیکھنے کیلئے Right دبائیں اور اپنا PIN درج کریں"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"‏یہ پروگرام دیکھنے کیلئے Right دبائیں اور اپنا PIN درج کریں"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"‏اس پروگرام کی درجہ بندی <xliff:g id="RATING">%1$s</xliff:g> کی گئی ہے۔\nاس پروگرام کو دیکھنے کیلئے Right دبائیں اور اپنا PIN درج کریں"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"صرف آڈیو"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"کمزور سگنل"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"کوئی انٹرنیٹ کنکشن نہیں ہے"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">یہ چینل <xliff:g id="END_TIME_1">%1$s</xliff:g> تک نہیں چلایا جا سکتا کیونکہ دوسرے چینلز کو ریکارڈ کیا جا رہا ہے۔ \n\nریکارڈنگ کا شیڈول ایڈجسٹ کرنے کیلئے دائیں طرف دبائیں۔</item>
+ <item quantity="one">یہ چینل <xliff:g id="END_TIME_0">%1$s</xliff:g> تک نہیں چلایا جا سکتا کیونکہ ایک اور چینل کو ریکارڈ کیا جا رہا ہے۔ \n\nریکارڈنگ کا شیڈول ایڈجسٹ کرنے کیلئے دائیں طرف دبائیں۔</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"کوئی عنوان نہیں ہے"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"چینل مسدود کر دیا گیا"</string>
<string name="setup_category_new" msgid="2899355289563443627">"نئے"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"کوئی چینلز دستیاب نہیں ہیں"</string>
<string name="setup_input_new" msgid="3337725672277046798">"نئے"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"ترتیب نہیں دیا گیا"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"مزید مآخذ حاصل کریں"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"لائیو چینلز کی پیشکش کرنے والی ایپس براؤز کریں"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"مزید مآخذ حاصل کریں"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"لائیو چینلز کی پیشکش کرنے والی ایپس براؤز کریں"</string>
<string name="new_sources_title" msgid="3878933676500061895">"نئے چینل ماخذین دستیاب ہیں"</string>
<string name="new_sources_description" msgid="749649005588426813">"نئے چینل ماخذین کے پاس پیشکش کیلئے چینل ہیں۔\nانہیں ابھی سیٹ اپ کریں یا چینل ماخذ ترتیب میں بعد میں کریں۔"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"ابھی سیٹ اپ کریں"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"سبھی ماخذ چینلز مخفی ہیں۔ \nدیکھنے کیلئے کم از کم ایک چینل منتخب کریں۔"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"ویڈیو غیر متوقع طور پر دستیاب نہیں ہے"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"‏BACK کلید منسلک آلہ کیلئے ہے۔ باہر نکلنے کیلئے HOME بٹن دبائیں۔"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"‏Android Lollipop والے اس آلے پر لائیو چینلز کی معاونت نہیں ہے۔"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"‏لائیو چینلز کو TV فہرستیں پڑھنے کیلئے اجازت کی ضرورت ہے۔"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"اپنے ذرائع سیٹ اپ کریں"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"‏لائیو چینلز روایتی TV چینلز کے تجربے کو ایپس کی جانب سے فراہم کردہ اسٹریمنگ چینلز سے ملاتے ہیں۔ \n\nپہلے سے انسٹال شدہ چینل ماخذین کو سیٹ اپ کر کے شروع کریں۔ یا لائیو چینلز کی پیشکش کرنے والی مزید ایپس کیلئے Google Play اسٹور براؤز کریں۔"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"ریکارڈنگز اور شیڈولز"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 منٹ"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 منٹ"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 گھنٹہ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 گھنٹے"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"حالیہ"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"شیڈول کردہ"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"سلسلہ"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"دیگر"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"چینل ریکارڈ نہیں ہو سکتا۔"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"پروگرام ریکارڈ نہیں ہو سکتا۔"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> کی ریکارڈنگ کیلئے شیڈول بن گیا ہے"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"اب سے لے کر <xliff:g id="ENDTIME">%2$s</xliff:g> تک <xliff:g id="PROGRAMNAME">%1$s</xliff:g> ریکارڈ ہو رہا ہے"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"پورا شیڈول"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">‏اگلے ‎%1$d دن</item>
+ <item quantity="one">‏اگلا ‎%1$d دن</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">‏%1$d منٹس</item>
+ <item quantity="one">‏%1$d منٹ</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">‏%1$d نئی ریکارڈنگز</item>
+ <item quantity="one">‏%1$d نئی ریکارڈنگ</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">‏%1$d ریکارڈنگز</item>
+ <item quantity="one">‏%1$d ریکارڈنگ</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">‏%1$d ریکارڈنگز کا شیڈول بن گیا</item>
+ <item quantity="one">‏%1$d ریکارڈنگ کا شیڈول بن گيا</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"دیکھیں"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"شروع سے چلائیں"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"چلانا دوبارہ شروع کریں"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"حذف کریں"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"ریکارڈنگز حذف کریں"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"دوبارہ شروع کریں"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"سیزن <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"شیڈول دیکھیں"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"مزید پڑھیں"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"ریکارڈنگز حذف کریں"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"وہ ایپی سوڈز منتخب کریں جو آپ حذف کرنا چاہتے ہیں۔ ایک بار حذف ہونے کے بعد ان کو بازیاب نہیں کیا جا سکتا۔"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"حذف کرنے کیلئے کوئی ریکارڈنگ نہیں ہے۔"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"دیکھی گئی ایپی سوڈز منتخب کریں"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"تمام ایپی سوڈز منتخب کریں"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"تمام ایپی سوڈز غیر منتخب کریں"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="DURATION">%2$d</xliff:g> میں سے <xliff:g id="WATCHED">%1$d</xliff:g> منٹ کی دیکھ لیں"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="DURATION">%2$d</xliff:g> میں سے <xliff:g id="WATCHED">%1$d</xliff:g> سیکنڈ کی دیکھ لیں"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"کبھی نہیں دیکھیں"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">‏%2$d میں سے ‎%1$d ایپی سوڈز حذف ہو گئیں</item>
+ <item quantity="one">‏%2$d میں سے ‎%1$d ایپی سوڈ حذف ہو گئی</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"ترجیح"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"سب سے اعلی"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"سب سے کم"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"نہیں۔ <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"چینلز"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"کوئی بھی"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"ترجیح کا انتخاب کریں"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"جب ایک وقت میں بہت سارے پروگرامز ریکارڈ کرنے ہوں تو صرف اعلی ترجیح والے پروگرامز ریکارڈ کیے جائیں گے۔"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"محفوظ کریں"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"یک وقتی ریکارڈنگز کو سب سے اعلی ترجیح حاصل ہوتی ہے"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"منسوخ کریں"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"منسوخ کریں"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"بھول جائیں"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"روکیں"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"ریکارڈنگ کا شیڈول ملاحظہ کریں"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"یہ واحد پروگرام"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"ابھی - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"پوری سیریز…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"کسی بھی طرح شیڈول بنائیں"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"اس کی بجائے یہ ریکارڈ کریں"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"اس ریکارڈنگ کو منسوخ کریں"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"ابھی دیکھیں"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"قابل ریکارڈ"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"ریکارڈنگ کا شیڈول"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"ریکارڈنگ شیڈول میں تصادم"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"ریکارڈ ہو رہا ہے"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"ریکارڈنگ ناکام ہو گئی"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"ریکارڈنگ کے شیڈولز بنانے کیلئے پروگرام پڑھے جا رہے ہیں"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"پروگرامز پڑھے جا رہے ہیں"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"‏DVR کو مزید اسٹوریج درکار ہے"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"‏آپ DVR کے ساتھ پروگرامز ریکارڈ کر سکیں گے۔ تاہم آپ کے آلہ پر DVR کے کام کرنے کیلئے ابھی کافی اسٹوریج نہیں ہے۔ براہ کرم ایک بیرونی ڈرائیو منسلک کریں جو GB <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> یا اس سے بڑی ہو اور اسے آلہ کی اسٹوریج کے بطور فارمیٹ کرنے کیلئے مراحل کی پیروی کریں۔"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"اسٹوریج غائب ہے"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"‏DVR کی استعمال کردہ کچھ اسٹوریج غائب ہے۔ براہ کرم وہ بیرونی ڈرائیو جو آپ نے پہلے DVR کو دوبارہ فعال کرنے کیلئے استعمال کی تھی، منسلک کریں۔ متبادل طور پر، اگر یہ مزید دستیاب نہ ہو تو آپ اسٹوریج کو بھولنے کا انتخاب کر سکتے ہیں۔"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"اسٹوریج کو بھول جائیں؟"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"آپ کا تمام ریکارڈ کردہ مواد اور شیڈولز ضائع ہو جائیں گے۔"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"ریکارڈنگ روکیں؟"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"ریکارڈ شدہ مواد محفوظ ہو جائے گا۔"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"ریکارڈنگ کا شیڈول لیکن تضادات"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"ریکارڈنگ شروع ہو گئی ہے لیکن اس میں تضادات ہیں"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ریکارڈ ہوجائے گا۔"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> ریکارڈ ہو رہا ہے۔"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> کے کچھ حصے ریکارڈ نہیں ہوں گے۔"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> اور <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> کے کچھ حصے ریکارڈ نہیں ہوں گے۔"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> کے کچھ حصے اور ایک اور شیڈول ریکارڈ نہیں ہوگا۔"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">‏<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> کے کچھ حصے اور ‎%3$d مزید شیڈولز ریکارڈ نہیں ہوں گے۔</item>
+ <item quantity="one">‏<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>، <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> کے کچھ حصے اور ‎%3$d مزید شیڈول ریکارڈ نہیں ہوگا۔</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"آپ کیا ریکارڈ کرنا چاہیں گے؟"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"آپ کتنی دیر تک ریکارڈ کرنا پسند کریں گے؟"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"پہلے سے شیڈول کردہ"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"اسی پروگرام کا پہلے ہی <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> بجے ریکارڈ ہونے کیلئے شیڈول بنا ہوا ہے۔"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"پہلے سے ریکارڈ شدہ"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"‏یہ پروگرام پہلے سے ہی ریکارڈ شدہ ہے۔ یہ DVR لائبریری میں دستیاب ہے۔"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"ریکارڈ شدہ پروگرام نہیں ملا۔"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"متعلقہ ریکارڈنگز"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(پروگرام کی کوئی تفصیل نہیں)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">‏%1$d ریکارڈنگز</item>
+ <item quantity="one">‏%1$d ریکارڈنگ</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> کو ریکارڈنگ شیڈول سے ہٹا دیا گیا"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"ٹیونر تضادات کی وجہ سے جزوی طور پر ریکارڈ ہوگا۔"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"ٹیونر تضادات کی وجہ سے ریکارڈ نہیں ہوگا۔"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"ابھی شیڈول میں کوئی ریکارڈنگز نہیں ہیں۔\nآپ پروگرام گائیڈ سے ریکارڈنگ کا شیڈول بنا سکتے ہیں۔"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">‏%1$d ریکارڈنگ تنازعات</item>
+ <item quantity="one">‏%1$d ریکارڈنگ تنازعہ</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"سیریز کی ترتیبات"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"سیریز کی ریکارڈنگ شروع کریں"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"سیریز کی ریکارڈنگ روکیں"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"سیریز ریکارڈنگ روکیں؟"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"‏ریکارڈ شدہ ایپی سوڈز DVR لائبریری میں دستیاب رہیں گے۔"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"روکیں"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"کوئی ایپی سوڈز دستیاب نہیں۔\nایک بار دستیاب ہوجائے تو ان کو ریکارڈ کیا جائے گا۔"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">‏(%1$d منٹ)</item>
+ <item quantity="one">‏(%1$d منٹ) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"ﺁﺝ"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"آئندہ کل"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"گزشتہ کل"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> آج"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> آئندہ کل"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"اسکور"</string>
</resources>
diff --git a/res/values-uz-rUZ/arrays.xml b/res/values-uz-rUZ/arrays.xml
index 72a89932..71619002 100644
--- a/res/values-uz-rUZ/arrays.xml
+++ b/res/values-uz-rUZ/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"To‘liq"</item>
<item msgid="8568284598210500589">"Miqyos"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Barcha kanallar"</item>
- <item msgid="6897460857821394118">"Oila va bolalar"</item>
- <item msgid="551257741825778215">"Sport"</item>
- <item msgid="452133796804325879">"Xaridlar"</item>
- <item msgid="3296058637230163031">"Filmlar"</item>
- <item msgid="1054540282883891201">"Komediya"</item>
- <item msgid="7900158429062595471">"Sayohat"</item>
- <item msgid="3768998587825611787">"Dramalar"</item>
- <item msgid="8340620094959282881">"Ta’lim"</item>
- <item msgid="7396447839483867269">"Tabiat va jonivorlar"</item>
- <item msgid="4738043455148062673">"Yangiliklar"</item>
- <item msgid="7405041316051047427">"O‘yinlar"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Barcha kanallar"</item>
- <item msgid="7909003973960375395">"Oila va bolalar"</item>
- <item msgid="3185279732911635789">"Sport"</item>
- <item msgid="4704858492065325964">"Xaridlar"</item>
- <item msgid="6083795019290250078">"Filmlar"</item>
- <item msgid="8302638329222449550">"Komediya"</item>
- <item msgid="3803709976021475052">"Sayohat"</item>
- <item msgid="8116747365234169059">"Dramalar"</item>
- <item msgid="7356447541595315913">"Ta’lim"</item>
- <item msgid="7511135485827589547">"Tabiat va jonivorlar"</item>
- <item msgid="6961248112238009967">"Yangiliklar"</item>
- <item msgid="6484685553679698447">"O‘yinlar"</item>
- <item msgid="2737158328243183190">"San’at"</item>
- <item msgid="6577176952650166615">"Hordiq"</item>
- <item msgid="7886693831871777617">"Turmush tarzi"</item>
- <item msgid="8145832312485577062">"Musiqa"</item>
- <item msgid="1345789204804308580">"Premyera"</item>
- <item msgid="2736680312770771994">"Fan va texnika"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Barcha kanallar"</item>
+ <item msgid="928298872841713530">"Oila va bolalar"</item>
+ <item msgid="2751606947569857164">"Sport"</item>
+ <item msgid="7345749789651321496">"Xarid"</item>
+ <item msgid="167201149441442173">"Filmlar"</item>
+ <item msgid="525966731464264290">"Komediya"</item>
+ <item msgid="6096710741527327836">"Sayohat"</item>
+ <item msgid="2851882187117833883">"Drama"</item>
+ <item msgid="78492781188719038">"Ta’lim"</item>
+ <item msgid="7221999662426308394">"Tabiat va jonivorlar"</item>
+ <item msgid="375300513250925001">"Yangiliklar"</item>
+ <item msgid="7746320336582330410">"O‘yinlar"</item>
+ <item msgid="1255741860568329178">"San’at"</item>
+ <item msgid="7603949681065702867">"Ko‘ngilochar"</item>
+ <item msgid="4453821994746804366">"Turmush tarzi"</item>
+ <item msgid="3488534597567932843">"Musiqa"</item>
+ <item msgid="7452153120614274095">"Premyera"</item>
+ <item msgid="8215762047341133299">"Fan va texnika"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Jonli efir"</item>
diff --git a/res/values-uz-rUZ/rating_system_strings.xml b/res/values-uz-rUZ/rating_system_strings.xml
index 470af93e..91d82748 100644
--- a/res/values-uz-rUZ/rating_system_strings.xml
+++ b/res/values-uz-rUZ/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-uz-rUZ/strings.xml b/res/values-uz-rUZ/strings.xml
index e1343d55..55a0324f 100644
--- a/res/values-uz-rUZ/strings.xml
+++ b/res/values-uz-rUZ/strings.xml
@@ -27,11 +27,10 @@
<string name="play_controls_description_play_pause" msgid="7225542861669250558">"Ijro yoki pauza"</string>
<string name="play_controls_description_fast_forward" msgid="4414963867482448652">"Oldinga tezkor o‘tkazish"</string>
<string name="play_controls_description_fast_rewind" msgid="953488122681015803">"Orqaga o‘tkazish"</string>
- <string name="play_controls_description_skip_next" msgid="1603587562124694592">"Keyingi"</string>
+ <string name="play_controls_description_skip_next" msgid="1603587562124694592">"Keyingisi"</string>
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Avvalgi"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Tele-yo‘lboshchi"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Yangi kanallar mavjud"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Hech qanday havola yo‘q"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasini ochish"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Taglavhalar"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Ekran rejimi"</string>
@@ -124,10 +123,11 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Sub-reytinglar"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Bu kanalni ko‘rish uchun PIN kodni kiriting"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Bu dasturni ko‘rish uchun PIN kodni kiriting"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Bu dastur uchun yosh cheklovi: <xliff:g id="RATING">%1$s</xliff:g>. Bu dasturni ko‘rish uchun PIN kodni kiriting"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"PIN kodni kiriting"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ota-ona nazoratini o‘rnatish uchun PIN-kod yarating"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Yangi PIN kodni kiriting"</string>
- <string name="pin_enter_again" msgid="2618999754723090427">"PIN kodni tasdiqlang"</string>
+ <string name="pin_enter_again" msgid="2618999754723090427">"PIN kodni kiriting"</string>
<string name="pin_enter_old_pin" msgid="4588282612931041919">"Joriy PIN kodni kiriting"</string>
<plurals name="pin_enter_countdown" formatted="false" msgid="3415233538538544309">
<item quantity="other">Siz PIN kodni 5 marta noto‘g‘ri kiritdingiz.\n<xliff:g id="REMAINING_SECONDS_1">%1$d</xliff:g> soniyadan keyin qayta urinib ko‘ring.</item>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Ochiq kodli DT litsenziyalari"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Ochiq kodli DT litsenziyalari"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Versiyasi"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Jonli efir ilovasini yaxshilashga ko‘maklashish"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Jonli kanallar xizmatini yaxshilash va ishdan chiqish hamda qotib qolish muammolarining oldini olish uchun Google’ga anonim tarzda foydalanish to‘g‘risidagi va tashxis ma’lumotlarini yuboring."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Bu kanalni ko‘rish uchun o‘ngga qaragan chiziqni bosing va PIN kodni kiriting"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Bu dasturni ko‘rish uchun o‘ngga qaragan chiziqni bosing va PIN kodni kiriting"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Bu dastur uchun yosh cheklovi: <xliff:g id="RATING">%1$s</xliff:g>.\nUshbu dasturni ko‘rish uchun o‘ngga qaragan milni bosing va PIN-kodni kiriting."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Faqat audio"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Signal kuchsiz"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Internet aloqasi yo‘q"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Bu kanalni <xliff:g id="END_TIME_1">%1$s</xliff:g> gacha yoqib bo‘lmaydi, chunki boshqa kanallar yozib olinmoqda. \n\nYozib olish jadvalini o‘zgartirish uchun o‘ng strelkani bosing.</item>
+ <item quantity="one">Bu kanalni <xliff:g id="END_TIME_0">%1$s</xliff:g> gacha yoqib bo‘lmaydi, chunki boshqa kanal yozib olinmoqda. \n\nYozib olish jadvalini o‘zgartirish uchun o‘ng strelkani bosing.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Nomsiz"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Kanal bloklangan"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Yangi"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Hech qanday kanal mavjud emas"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Yangi"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Sozlanmagan"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Ko‘proq kanal manbalarini olish"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Jonli kanallarni taklif etuvchi ilovalarni ko‘rish"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Ko‘proq kanal manbalarini olish"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Jonli kanallarni taklif etuvchi ilovalarni ko‘rish"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Yangi kanal manbalari mavjud"</string>
<string name="new_sources_description" msgid="749649005588426813">"Yangi manbalar yangi kanallarni taqdim etadi.\nUlarni hozir yoki kanal manbalari sozlamalarida keyinroq sozlashingiz mumkin."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Hozir sozlash"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Barcha kanallar berkitilgan.\nTomosha qilish uchun kamida bitta kanalni tanlang."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video kutilmaganda yo‘q bo‘lib qoldi."</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"ORQAGA tugmasi ulangan qurilmani boshqaradi. Chiqish uchun BOSHI tugmasini bosing."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Jonli efir Android Lollipop tizimi o‘rnatilgan mazkur qurilmada ishlamaydi."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Teledasturlarni o‘qish uchun ruxsat zarur."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Manbalarni sozlash"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Jonli efirlar ilovalar tomonidan taqdim etiladigan translatsiya qilinadigan kanallar bilan an’anaviy televizor kanallarini uyg‘unlashtiradi. \n\nOldin o‘rnatilgan kanal manbalarini sozlash bilan boshlashingiz mumkin. Yoki jonli efirlarni taklif etadigan boshqa ilovalarni Google Play Market orqali ko‘rib chiqishingiz mumkin."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Yozuvlar va jadvallar"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 daqiqa"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 daqiqa"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 soat"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 soat"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Yaqinda"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Rejalashtirilgan"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Seriallar"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Boshqalar"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Bu kanalni yozib bo‘lmaydi."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Bu dasturni yozib bo‘lmaydi."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> dasturini yozib olish rejalashtirildi"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> dasturini yozib olish boshlandi (<xliff:g id="ENDTIME">%2$s</xliff:g> gacha yoziladi)"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"To‘liq jadval"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">Keyingi %1$d kun</item>
+ <item quantity="one">Keyingi %1$d kun</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d daqiqa</item>
+ <item quantity="one">%1$d daqiqa</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d ta yangi yozuv</item>
+ <item quantity="one">%1$d ta yangi yozuv</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d ta yozuv</item>
+ <item quantity="one">%1$d ta yozuv</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d ta yozuv rejalashtirilgan</item>
+ <item quantity="one">%1$d ta yozuv rejalashtirilgan</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Tomosha qilish"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Boshidan ijro etish"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Ijroni davom ettirish"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"O‘chirish"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Yozuvlarni o‘chirish"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Davom ettirish"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"<xliff:g id="SEASON_NUMBER">%1$s</xliff:g>-fasl"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Jadvalni ko‘rish"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Batafsil"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Yozuvlarni o‘chirish"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"O‘chirib tashlash kerak bo‘lgan qismlarni tanlang. O‘chirilgach, qayta tiklab bo‘lmaydi."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"O‘chirib tashlash uchun hech narsa yo‘q."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Ko‘rilgan qismlarni belgilash"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Barcha qismlarni belgilash"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Hammasini bekor qilish"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Ko‘rilgan: <xliff:g id="WATCHED">%1$d</xliff:g> daqiqa (jami: <xliff:g id="DURATION">%2$d</xliff:g> daqiqa)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Ko‘rilgan: <xliff:g id="WATCHED">%1$d</xliff:g> soniya (jami: <xliff:g id="DURATION">%2$d</xliff:g> soniya)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Ko‘rilmaganlar"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d ta qism o‘chirib tashlandi (jami: %2$d ta)</item>
+ <item quantity="one">%1$d ta qism o‘chirib tashlandi (jami: %2$d ta)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Muhimlik darajasi"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Eng yuqori"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Eng past"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"# <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kanallar"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Har qanday"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Muhimlilik darajasini tanlash"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Bir vaqtning o‘zida bir nechta dasturlar yozib olinishi kerak bo‘lsa, faqat muhimlilik darajasi yuqori dasturlargina yozib olinadi."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Saqlash"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Bir martalik yozuvlarning muhimlilik darajasi yuqori"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Bekor q-sh"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Bekor qilish"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"O‘chirib tashlash"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"To‘xtatish"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Yozib olish jadvalini ko‘rish"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Faqat bu dastur"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"hozir – <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"To‘liq serial…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Baribir yozib olinsin"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Bu dasturni yozib olish"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Bu yozib olishni bekor qilish"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Tomosha qilish"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Yozib olish mumkin"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Yozib olish rejalashtirildi"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Yozib olish taymerida ziddiyat"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Yozib olish"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Yozib olib bo‘lmadi"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Yozib olish jadvallarini yaratish uchun dasturlar o‘qib chiqilmoqda"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Dasturlar o‘qib chiqilmoqda"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR uchun ko‘proq joy kerak"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Dasturlarni DVR orqali yozib olish mumkin. Lekin hozir DVR ishlashi uchun qurilmangizda yetarli joy qolmadi. <xliff:g id="STORAGE_SIZE">%1$s</xliff:g> GB va undan katta hajmli tashqi xotira qurilmasini ulang va qurilma xotirasi sifatida formatlash uchun ko‘rsatmalarga amal qiling."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Xotira mavjud emas"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Xotira topilmadi. Videomagnitofonni qayta yoqishdan oldin tashqi xotirani ulang yoki undan foydalanib bo‘lmasa, xotirani o‘chirib tashlang."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Xotira o‘chirib tashlansinmi?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Barcha yozib olingan kontentlar va jadvallar o‘chib ketadi."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Yozib olish to‘xtatilsinmi?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Yozib olingan kontent saqlab qo‘yiladi."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Yozib olish rejalashtirildi, lekin ixtiloflar bor"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Yozib olish jadvalida ixtiloflar bor"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"“<xliff:g id="PROGRAMNAME">%1$s</xliff:g>” dasturi yozib olinadi."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"“<xliff:g id="CHANNELNAME">%1$s</xliff:g>” kanalidagi video yozib olinmoqda."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"“<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>” dasturining faqat bir qismi yozib olinadi."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"“<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>” va “<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>” dasturlarining faqat bir qismi yozib olinadi."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"“<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>”, “<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>” va yana bitta dasturning faqat bir qismi yozib olinadi."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other"><xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> va yana %3$d ta dasturning faqat bir qismi yozib olinadi.</item>
+ <item quantity="one"><xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> va yana %3$d ta dasturning faqat bir qismi yozib olinadi.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Nimalar yozib olinsin?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Qancha vaqt yozib olinsin?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Allaqachon rejalashtirilgan"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Bu dasturni allaqachon <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> da yozib olish rejalashtirilgan."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Dastur allaqachon yozib olingan"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Bu dastur allaqachon yozib olingan. U DVR kutubxonasida saqlanadi."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Yozib olingan dasturni topib bo‘lmadi."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Aloqador yozuvlar"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Dastur haqida ma’lumot yo‘q)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d ta yozuv</item>
+ <item quantity="one">%1$d ta yozuv</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> yozuvi jadvaldan olib tashlandi"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Tyuner yo‘qligi sababli qisman yozib olinadi."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Tyuner yo‘qligi sababli yozib olinmaydi."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Jadval bo‘sh.\nTele-yo‘lboshlovchi orqali yozib olishni rejalashtirish mumkin."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d ta yozib olish bo‘yicha ziddiyat</item>
+ <item quantity="one">%1$d ta yozib olish bo‘yicha ziddiyat</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Qismlar sozlamalari"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Yozib olishni boshlash"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Yozib olishni to‘xtatish"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Yozib olish to‘xtatilsinmi?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Yozib olingan qismlar DVR kutubxonasida saqlanadi."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"To‘xtatish"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Hali serial qismi chiqmagan.\nEfirga chiqishi bilan yozib olinadi."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d daqiqa)</item>
+ <item quantity="one">(%1$d daqiqa) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Bugun"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Ertaga"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Kecha"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"Bugun <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"Ertaga <xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Ball"</string>
</resources>
diff --git a/res/values-vi/arrays.xml b/res/values-vi/arrays.xml
index 524ae9b9..202d287a 100644
--- a/res/values-vi/arrays.xml
+++ b/res/values-vi/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Toàn màn hình"</item>
<item msgid="8568284598210500589">"Thu phóng"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Tất cả các kênh"</item>
- <item msgid="6897460857821394118">"Gia đình/Trẻ em"</item>
- <item msgid="551257741825778215">"Thể thao"</item>
- <item msgid="452133796804325879">"Mua sắm"</item>
- <item msgid="3296058637230163031">"Phim"</item>
- <item msgid="1054540282883891201">"Hài kịch"</item>
- <item msgid="7900158429062595471">"Du lịch"</item>
- <item msgid="3768998587825611787">"Kịch"</item>
- <item msgid="8340620094959282881">"Giáo dục"</item>
- <item msgid="7396447839483867269">"Động vật/Thiên nhiên"</item>
- <item msgid="4738043455148062673">"Tin tức"</item>
- <item msgid="7405041316051047427">"Trò chơi"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Tất cả các kênh"</item>
- <item msgid="7909003973960375395">"Gia đình/Trẻ em"</item>
- <item msgid="3185279732911635789">"Thể thao"</item>
- <item msgid="4704858492065325964">"Mua sắm"</item>
- <item msgid="6083795019290250078">"Phim"</item>
- <item msgid="8302638329222449550">"Hài kịch"</item>
- <item msgid="3803709976021475052">"Du lịch"</item>
- <item msgid="8116747365234169059">"Kịch"</item>
- <item msgid="7356447541595315913">"Giáo dục"</item>
- <item msgid="7511135485827589547">"Động vật/Thiên nhiên"</item>
- <item msgid="6961248112238009967">"Tin tức"</item>
- <item msgid="6484685553679698447">"Trò chơi"</item>
- <item msgid="2737158328243183190">"Nghệ thuật"</item>
- <item msgid="6577176952650166615">"Giải trí"</item>
- <item msgid="7886693831871777617">"Lối sống"</item>
- <item msgid="8145832312485577062">"Âm nhạc"</item>
- <item msgid="1345789204804308580">"Cao cấp"</item>
- <item msgid="2736680312770771994">"Công nghệ/Khoa học"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Tất cả các kênh"</item>
+ <item msgid="928298872841713530">"Gia đình/Trẻ em"</item>
+ <item msgid="2751606947569857164">"Thể thao"</item>
+ <item msgid="7345749789651321496">"Mua sắm"</item>
+ <item msgid="167201149441442173">"Phim"</item>
+ <item msgid="525966731464264290">"Hài kịch"</item>
+ <item msgid="6096710741527327836">"Du lịch"</item>
+ <item msgid="2851882187117833883">"Kịch"</item>
+ <item msgid="78492781188719038">"Giáo dục"</item>
+ <item msgid="7221999662426308394">"Động vật/Động vật hoang dã"</item>
+ <item msgid="375300513250925001">"Tin tức"</item>
+ <item msgid="7746320336582330410">"Trò chơi"</item>
+ <item msgid="1255741860568329178">"Nghệ thuật"</item>
+ <item msgid="7603949681065702867">"Giải trí"</item>
+ <item msgid="4453821994746804366">"Lối sống"</item>
+ <item msgid="3488534597567932843">"Âm nhạc"</item>
+ <item msgid="7452153120614274095">"Cao cấp"</item>
+ <item msgid="8215762047341133299">"Công nghệ/Khoa học"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Kênh trực tiếp"</item>
diff --git a/res/values-vi/rating_system_strings.xml b/res/values-vi/rating_system_strings.xml
index 88b460f8..7dcc2d9c 100644
--- a/res/values-vi/rating_system_strings.xml
+++ b/res/values-vi/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 449e2796..a8c4ab09 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Trước"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Hướng dẫn chương trình"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Đã có kênh mới"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Không có liên kết"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Mở <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Phụ đề"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Chế độ hiển thị"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Xếp hạng phụ"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Nhập mã PIN của bạn để xem kênh này"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Nhập mã PIN của bạn để xem chương trình này"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Chương trình này được xếp hạng <xliff:g id="RATING">%1$s</xliff:g>. Nhập mã PIN của bạn để xem chương trình này"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Nhập mã PIN của bạn"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Để đặt kiểm soát của phụ huynh, hãy tạo mã PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Nhập mã PIN mới"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Giấy phép nguồn mở"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Giấy phép nguồn mở"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Phiên bản"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Giúp cải tiến ứng dụng Kênh trực tiếp"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Chia sẻ ẩn danh dữ liệu sử dụng và chẩn đoán với Google để chúng tôi có thể làm cho Kênh trực tiếp tốt hơn và ngăn chặn các sự cố như bị lỗi và treo."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Để xem kênh này, hãy nhấn vào Quyền và nhập mã PIN của bạn"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Để xem chương trình này, hãy nhấn vào Quyền và nhập mã PIN của bạn"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Chương trình này được xếp hạng <xliff:g id="RATING">%1$s</xliff:g>.\nĐể xem chương trình này, hãy nhấn vào Quyền và nhập mã PIN của bạn."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Chỉ âm thanh"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Tín hiệu yếu"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Không có kết nối Internet"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">Không thể phát kênh này cho đến <xliff:g id="END_TIME_1">%1$s</xliff:g> vì đang ghi các kênh khác. \n\nNhấn vào Quyền để điều chỉnh lịch ghi.</item>
+ <item quantity="one">Không thể phát kênh này cho đến <xliff:g id="END_TIME_0">%1$s</xliff:g> vì đang ghi kênh khác. \n\nNhấn vào Quyền để điều chỉnh lịch ghi.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Không có tiêu đề"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Đã chặn kênh"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Mới"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Không có kênh nào"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Mới"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Chưa thiết lập"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Xem nguồn khác"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Duyệt qua các ứng dụng cung cấp kênh truyền hình trực tiếp"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Xem nguồn khác"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Duyệt qua các ứng dụng cung cấp kênh truyền hình trực tiếp"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Có nguồn kênh mới"</string>
<string name="new_sources_description" msgid="749649005588426813">"Nguồn kênh mới có kênh để cung cấp.\nHãy thiết lập các kênh bây giờ hoặc thiết lập sau này trong cài đặt nguồn kênh."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Thiết lập ngay"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Tất cả các kênh nguồn đều bị ẩn.\nHãy chọn ít nhất một kênh để xem."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Video đột nhiên không có"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Phím QUAY LẠI dành cho thiết bị đã kết nối. Nhấn nút HOME để thoát."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Kênh trực tiếp không được hỗ trợ trên thiết bị chạy Android Lollipop này."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Kênh trực tiếp cần quyền đọc danh sách TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Thiết lập nguồn của bạn"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Kênh trực tiếp kết hợp trải nghiệm của các kênh TV truyền thống với các kênh truyền trực tuyến do các ứng dụng cung cấp. \n\nHãy bắt đầu bằng cách thiết lập các nguồn kênh đã được cài đặt. Hoặc duyệt qua Cửa hàng Google Play để có thêm nhiều ứng dụng cung cấp kênh trực tiếp."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Bản ghi &amp; lịch"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 phút"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 phút"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 giờ"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 giờ"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Gần đây"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Đã được lên lịch"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Loạt phim"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Khác"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Không thể ghi kênh."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Không thể ghi chương trình."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> đã được lên lịch để ghi"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Đang ghi <xliff:g id="PROGRAMNAME">%1$s</xliff:g> từ giờ đến <xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Lịch trình đầy đủ"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">%1$d ngày tiếp theo</item>
+ <item quantity="one">%1$d ngày tiếp theo</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d phút</item>
+ <item quantity="one">%1$d phút</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d bản ghi mới</item>
+ <item quantity="one">%1$d bản ghi mới</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d bản ghi</item>
+ <item quantity="one">%1$d bản ghi</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">%1$d bản ghi được lên lịch</item>
+ <item quantity="one">%1$d bản ghi được lên lịch</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Xem"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Phát từ đầu"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Tiếp tục phát"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Xóa"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Xóa bản ghi"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Tiếp tục"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Phần <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Xem lịch ghi"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Đọc thêm"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Xóa bản ghi"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Chọn các tập bạn muốn xóa. Không thể khôi phục chúng khi đã xóa."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Không có bản ghi nào để xóa."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Chọn các tập đã xem"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Chọn tất cả các tập"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Bỏ chọn tất cả các tập"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"Đã xem <xliff:g id="WATCHED">%1$d</xliff:g> trong tổng số <xliff:g id="DURATION">%2$d</xliff:g> phút"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"Đã xem <xliff:g id="WATCHED">%1$d</xliff:g> trong tổng số <xliff:g id="DURATION">%2$d</xliff:g> giây"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Chưa bao giờ xem"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">%1$d trong tổng số %2$d tập bị xóa</item>
+ <item quantity="one">%1$d trong tổng số %2$d tập bị xóa</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Mức độ ưu tiên"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Cao nhất"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Thấp nhất"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Hạng <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Kênh"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Bất kỳ"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Chọn mức độ ưu tiên"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Khi có quá nhiều chương trình được ghi cùng lúc, chỉ có những chương trình với mức ưu tiên cao hơn sẽ được ghi."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Lưu"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Ghi một lần có mức độ ưu tiên cao nhất"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Hủy"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Hủy"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Quên"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Dừng"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Xem lịch ghi"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Chương trình duy nhất này"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"bây giờ - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Toàn bộ loạt phim..."</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Vẫn lên lịch"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Ghi chương trình này để thay thế"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Hủy lịch ghi này"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Xem ngay bây giờ"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Có thể ghi được"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Đã lên lịch ghi"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Lịch ghi xung đột"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Đang ghi"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Ghi không thành công"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Đang đọc các chương trình để tạo lịch ghi"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Đang đọc chương trình"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR cần thêm bộ nhớ"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Bạn sẽ có thể ghi các chương trình với DVR. Tuy nhiên không có đủ bộ nhớ trên thiết bị của bạn bây giờ để DVR hoạt động. Vui lòng kết nối ổ đĩa ngoài <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB hoặc lớn hơn và làm theo các bước để định dạng ổ đĩa ngoài làm thiết bị lưu trữ."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Thiếu bộ nhớ"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Một số bộ nhớ được DVR sử dụng bị thiếu. Vui lòng kết nối các ổ đĩa ngoài bạn đã sử dụng trước đó để bật lại DVR. Ngoài ra bạn còn có thể chọn để quên bộ nhớ nếu bộ nhớ không còn nữa."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Quên bộ nhớ?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Tất cả nội dung đã ghi và lịch ghi của bạn sẽ bị mất."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Dừng ghi?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Nội dung đã ghi sẽ được lưu."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Đã lên lịch ghi nhưng có xung đột"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Đã bắt đầu ghi nhưng có xung đột"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> sẽ được ghi."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> đang được ghi."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Một số phần của <xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> sẽ không được ghi."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Một số phần của <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> và <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> sẽ không được ghi."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Một số phần của <xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> và một lịch ghi khác sẽ không được ghi."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">Một số phần của <xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> và %3$d lịch ghi khác sẽ không được ghi.</item>
+ <item quantity="one">Một số phần của <xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g> và %3$d lịch ghi khác sẽ không được ghi.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Bạn muốn ghi gì?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Bạn muốn ghi bao lâu?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Đã được lên lịch"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Chương trình tương tự đã được lên lịch để ghi lúc <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Đã được ghi"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Chương trình này đã được ghi. Chương trình có sẵn trong thư viện DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Không tìm thấy chương trình nào được ghi."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Bản ghi liên quan"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Không có mô tả chương trình)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d bản ghi</item>
+ <item quantity="one">%1$d bản ghi</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"Đã xóa <xliff:g id="PROGRAMNAME">%1$s</xliff:g> khỏi lịch ghi"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Sẽ được ghi một phần do xung đột bộ dò."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Sẽ không được ghi do xung đột bộ dò."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Chưa có lịch ghi nào.\nBạn có thể lên lịch ghi từ hướng dẫn chương trình."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d xung đột ghi</item>
+ <item quantity="one">%1$d xung đột ghi</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Cài đặt cho loạt phim"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Bắt đầu ghi loạt phim"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Dừng ghi loạt phim"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Dừng ghi loạt phim?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Các tập đã ghi sẽ vẫn có sẵn trong thư viện DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Dừng"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Không có sẵn tập nào.\nChúng sẽ được ghi khi có sẵn."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d phút)</item>
+ <item quantity="one">(%1$d phút) </item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Hôm nay"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Ngày mai"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Hôm qua"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> hôm nay"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> ngày mai"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Điểm"</string>
</resources>
diff --git a/res/values-zh-rCN/arrays.xml b/res/values-zh-rCN/arrays.xml
index 0dbbfe58..4bd6fa10 100644
--- a/res/values-zh-rCN/arrays.xml
+++ b/res/values-zh-rCN/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"全屏"</item>
<item msgid="8568284598210500589">"缩放"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"所有频道"</item>
- <item msgid="6897460857821394118">"亲子"</item>
- <item msgid="551257741825778215">"体育"</item>
- <item msgid="452133796804325879">"购物"</item>
- <item msgid="3296058637230163031">"电影"</item>
- <item msgid="1054540282883891201">"喜剧"</item>
- <item msgid="7900158429062595471">"旅行"</item>
- <item msgid="3768998587825611787">"戏剧"</item>
- <item msgid="8340620094959282881">"教育"</item>
- <item msgid="7396447839483867269">"动物/野生生物"</item>
- <item msgid="4738043455148062673">"新闻"</item>
- <item msgid="7405041316051047427">"游戏"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"所有频道"</item>
- <item msgid="7909003973960375395">"亲子"</item>
- <item msgid="3185279732911635789">"体育"</item>
- <item msgid="4704858492065325964">"购物"</item>
- <item msgid="6083795019290250078">"电影"</item>
- <item msgid="8302638329222449550">"喜剧"</item>
- <item msgid="3803709976021475052">"旅行"</item>
- <item msgid="8116747365234169059">"戏剧"</item>
- <item msgid="7356447541595315913">"教育"</item>
- <item msgid="7511135485827589547">"动物/野生生物"</item>
- <item msgid="6961248112238009967">"新闻"</item>
- <item msgid="6484685553679698447">"游戏"</item>
- <item msgid="2737158328243183190">"艺术"</item>
- <item msgid="6577176952650166615">"娱乐"</item>
- <item msgid="7886693831871777617">"生活时尚"</item>
- <item msgid="8145832312485577062">"音乐"</item>
- <item msgid="1345789204804308580">"首映"</item>
- <item msgid="2736680312770771994">"科技"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"所有频道"</item>
+ <item msgid="928298872841713530">"亲子"</item>
+ <item msgid="2751606947569857164">"体育"</item>
+ <item msgid="7345749789651321496">"购物"</item>
+ <item msgid="167201149441442173">"电影"</item>
+ <item msgid="525966731464264290">"喜剧"</item>
+ <item msgid="6096710741527327836">"旅游"</item>
+ <item msgid="2851882187117833883">"剧情类"</item>
+ <item msgid="78492781188719038">"教育"</item>
+ <item msgid="7221999662426308394">"动物/野生生物"</item>
+ <item msgid="375300513250925001">"新闻"</item>
+ <item msgid="7746320336582330410">"游戏"</item>
+ <item msgid="1255741860568329178">"艺术"</item>
+ <item msgid="7603949681065702867">"娱乐"</item>
+ <item msgid="4453821994746804366">"生活时尚"</item>
+ <item msgid="3488534597567932843">"音乐"</item>
+ <item msgid="7452153120614274095">"首映"</item>
+ <item msgid="8215762047341133299">"科技"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"直播频道"</item>
diff --git a/res/values-zh-rCN/rating_system_strings.xml b/res/values-zh-rCN/rating_system_strings.xml
index 93dcac1d..b3f23337 100644
--- a/res/values-zh-rCN/rating_system_strings.xml
+++ b/res/values-zh-rCN/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 6a316495..e3d8ea08 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"上一项"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"收视指南"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"有新的频道"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"没有任何应用链接"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"打开<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"字幕"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"显示模式"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"二级分级"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"输入PIN码即可观看此频道"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"输入PIN码即可观看此节目"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"该节目的分级是“<xliff:g id="RATING">%1$s</xliff:g>”。要观看此节目,请输入您的 PIN 码"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"输入您的PIN码"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"要设置家长控制功能,请创建一个PIN码"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"请输入新的PIN码"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"开放源代码许可"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"开放源代码许可"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"版本"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"帮助改进直播频道"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"将匿名使用情形和诊断数据提供给 Google,以协助我们改进直播频道并避免发生崩溃和死机等问题。"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"要观看此频道,请按“向右”按钮,然后输入您的PIN码"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"要观看此节目,请按“向右”按钮,然后输入您的PIN码"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"此节目的分级为:<xliff:g id="RATING">%1$s</xliff:g>。\n要观看此节目,请按“向右”按钮,然后输入您的 PIN 码。"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"仅提供音频"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"信号弱"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"未连接到互联网"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">目前正在录制其他频道,因此在<xliff:g id="END_TIME_1">%1$s</xliff:g> 前无法播放此频道。\n\n按向右箭头即可调整录制时间安排。</item>
+ <item quantity="one">目前正在录制另一个频道,因此在<xliff:g id="END_TIME_0">%1$s</xliff:g> 前无法播放此频道。\n\n按向右箭头即可调整录制时间安排。</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"无标题"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"频道已屏蔽"</string>
<string name="setup_category_new" msgid="2899355289563443627">"新来源"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"没有任何频道"</string>
<string name="setup_input_new" msgid="3337725672277046798">"新的输入设备"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"未设置"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"获取更多来源"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"浏览提供直播频道的应用"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"获取更多来源"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"浏览提供直播频道的应用"</string>
<string name="new_sources_title" msgid="3878933676500061895">"有可用的新频道来源"</string>
<string name="new_sources_description" msgid="749649005588426813">"新频道来源有频道可提供。\n立即设置这些频道,或稍后转到频道来源设置中进行设置。"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"立即设置"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"所有来源频道均处于隐藏状态。\n请至少选择一个频道来观看。"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"此视频出现异常,无法播放"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"“返回”键用于控制连接的设备。按“主屏幕”按钮即可退出。"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"此 Android Lollipop 设备不支持直播频道。"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"直播频道需要获取相应权限才能读取电视节目列表。"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"设置您的频道来源"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"直播频道结合了传统电视频道和网络直播频道(由应用提供)的观看体验。\n\n要开始使用,请先设置已安装的频道来源,或前往 Google Play 商店浏览查找更多提供直播频道的应用。"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"录制内容和时间安排"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 分钟"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 分钟"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 小时"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 小时"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"近期"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"已排定"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"剧集"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"其他"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"无法录制该频道。"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"无法录制该节目。"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"已排定《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》的录制时间"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"从现在起到<xliff:g id="ENDTIME">%2$s</xliff:g> 录制《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"完整时间表"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">接下来 %1$d 天</item>
+ <item quantity="one">接下来 %1$d 天</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d 分钟</item>
+ <item quantity="one">%1$d 分钟</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d 项新录制内容</item>
+ <item quantity="one">%1$d 项新录制内容</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d 项录制内容</item>
+ <item quantity="one">%1$d 项录制内容</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">已安排录制 %1$d 项内容</item>
+ <item quantity="one">已安排录制 %1$d 项内容</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"观看"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"从头播放"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"继续播放"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"删除"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"删除录制内容"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"继续"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"查看时间表"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"了解详情"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"删除录制内容"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"请选择您要删除的剧集。这些剧集一旦删除,便无法恢复。"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"没有可供删除的录制内容。"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"选择观看过的剧集"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"选择所有剧集"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"取消选择所有剧集"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"已观看 <xliff:g id="WATCHED">%1$d</xliff:g> 分钟(共 <xliff:g id="DURATION">%2$d</xliff:g> 分钟)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"已观看 <xliff:g id="WATCHED">%1$d</xliff:g> 秒(共 <xliff:g id="DURATION">%2$d</xliff:g> 秒)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"从未观看过"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">已删除 %1$d 集(共 %2$d 集)</item>
+ <item quantity="one">已删除 %1$d 集(共 %2$d 集)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"优先级"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"最高"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"最低"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"排名第 <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"频道"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"不限"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"选择优先级"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"如果同一时段有太多的节目要录制,系统只会录制优先级较高的节目。"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"保存"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"一次性录制内容具有最高优先级"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"取消"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"取消"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"移除"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"停止"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"查看录制时间表"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"只录这一集节目"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"现在 - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"全部剧集…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"仍然安排录制计划"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"改录这个节目"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"取消这项录制安排"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"立即观看"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"可录制"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"已排定录制时间"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"录制冲突"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"正在录制"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"录制失败"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"正在读取节目以创建录制时间安排表"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"正在读取节目"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR 需要更多存储空间"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"您将可以使用 DVR 录制节目,但目前您设备上的存储空间不足,因此无法使用 DVR。请连接存储空间不小于 <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB 的外部驱动器,然后按照相关步骤将其格式化为设备的存储空间。"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"无法访问存储空间"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"无法访问 DVR 使用的部分存储空间。请连接您先前使用的外部驱动器,以重新启用 DVR。如果存储空间已无法再使用,您也可以选择忽略该存储空间。"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"要移除此存储空间吗?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"您的所有录制内容和录制安排计划都将丢失。"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"要停止录制吗?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"系统将保存已录制的内容。"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"已排定录制时间,但录制时间存在冲突"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"已开始录制,但存在冲突"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"系统将会录制《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》。"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"正在录制<xliff:g id="CHANNELNAME">%1$s</xliff:g>。"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"《<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>》将有部分内容无法录制。"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》和《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》将有部分内容无法录制。"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》和另外 1 个排定的节目将有部分内容无法录制。"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">《<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>》和另外 %3$d 个排定的节目将有部分内容无法录制。</item>
+ <item quantity="one">《<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>》和另外 %3$d 个排定的节目将有部分内容无法录制。</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"您要录制哪些内容?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"您要录制多久?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"已安排录制计划"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"已安排在以下时间录制同一节目:<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>。"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"已录制"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"此节目已完成录制并保存在 DVR 媒体库中。"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"未找到录制的节目。"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"相关录制内容"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(没有节目说明)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d 项录制内容</item>
+ <item quantity="one">%1$d 项录制内容</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"已从录制时间表中移除《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"没有可用的调谐器,因此只能录制部分内容。"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"没有可用的调谐器,因此无法录制。"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"尚未安排任何录制计划。\n您可以根据收视指南安排录制计划。"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d 项录制冲突</item>
+ <item quantity="one">%1$d 项录制冲突</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"剧集录制设置"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"开始创建剧集录制时间表"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"停止创建剧集录制时间表"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"要停止创建剧集录制时间表吗?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"已录制的剧集仍会保存到 DVR 媒体库中。"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"停止"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"没有已录制的剧集。\n一旦有剧集可供录制,系统将立即开始录制。"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d 分钟)</item>
+ <item quantity="one">(%1$d 分钟)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"今天"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"明天"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"昨天"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"今天<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"明天<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"评分"</string>
</resources>
diff --git a/res/values-zh-rHK/arrays.xml b/res/values-zh-rHK/arrays.xml
index 0951b0be..1fcac667 100644
--- a/res/values-zh-rHK/arrays.xml
+++ b/res/values-zh-rHK/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"全螢幕"</item>
<item msgid="8568284598210500589">"縮放"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"所有頻道"</item>
- <item msgid="6897460857821394118">"家庭/兒童"</item>
- <item msgid="551257741825778215">"體育"</item>
- <item msgid="452133796804325879">"購物"</item>
- <item msgid="3296058637230163031">"電影"</item>
- <item msgid="1054540282883891201">"喜劇"</item>
- <item msgid="7900158429062595471">"旅遊"</item>
- <item msgid="3768998587825611787">"戲劇"</item>
- <item msgid="8340620094959282881">"教育"</item>
- <item msgid="7396447839483867269">"動物/野生動植物"</item>
- <item msgid="4738043455148062673">"新聞"</item>
- <item msgid="7405041316051047427">"遊戲"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"所有頻道"</item>
- <item msgid="7909003973960375395">"家庭/兒童"</item>
- <item msgid="3185279732911635789">"體育"</item>
- <item msgid="4704858492065325964">"購物"</item>
- <item msgid="6083795019290250078">"電影"</item>
- <item msgid="8302638329222449550">"喜劇"</item>
- <item msgid="3803709976021475052">"旅遊"</item>
- <item msgid="8116747365234169059">"戲劇"</item>
- <item msgid="7356447541595315913">"教育"</item>
- <item msgid="7511135485827589547">"動物/野生動植物"</item>
- <item msgid="6961248112238009967">"新聞"</item>
- <item msgid="6484685553679698447">"遊戲"</item>
- <item msgid="2737158328243183190">"藝術"</item>
- <item msgid="6577176952650166615">"娛樂"</item>
- <item msgid="7886693831871777617">"生活品味"</item>
- <item msgid="8145832312485577062">"音樂"</item>
- <item msgid="1345789204804308580">"首映"</item>
- <item msgid="2736680312770771994">"科技/科學"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"所有頻道"</item>
+ <item msgid="928298872841713530">"家庭/兒童"</item>
+ <item msgid="2751606947569857164">"體育"</item>
+ <item msgid="7345749789651321496">"購物"</item>
+ <item msgid="167201149441442173">"電影"</item>
+ <item msgid="525966731464264290">"喜劇"</item>
+ <item msgid="6096710741527327836">"旅遊"</item>
+ <item msgid="2851882187117833883">"戲劇"</item>
+ <item msgid="78492781188719038">"教育"</item>
+ <item msgid="7221999662426308394">"動物/野生動物"</item>
+ <item msgid="375300513250925001">"新聞"</item>
+ <item msgid="7746320336582330410">"遊戲"</item>
+ <item msgid="1255741860568329178">"藝術"</item>
+ <item msgid="7603949681065702867">"娛樂"</item>
+ <item msgid="4453821994746804366">"生活品味"</item>
+ <item msgid="3488534597567932843">"音樂"</item>
+ <item msgid="7452153120614274095">"首選"</item>
+ <item msgid="8215762047341133299">"科技/科學"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"直播頻道"</item>
diff --git a/res/values-zh-rHK/rating_system_strings.xml b/res/values-zh-rHK/rating_system_strings.xml
index 50a3db56..e0c18237 100644
--- a/res/values-zh-rHK/rating_system_strings.xml
+++ b/res/values-zh-rHK/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index b024e687..5fe984d5 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"返回"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"節目指南"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"可供設定的新頻道"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"沒有可用連結"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"隱藏式字幕"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"顯示模式"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"子分級"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"輸入您的 PIN 即可觀看這個頻道"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"輸入您的 PIN 即可觀看這個節目"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"此節目的內容分級是「<xliff:g id="RATING">%1$s</xliff:g>」。如要觀看此節目,請輸入 PIN"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"請輸入您的 PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"如要設定家長監護,請建立 PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"輸入新的 PIN"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"開放原始碼授權"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"開放原始碼授權"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"版本"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"協助改善「直播頻道」"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"與 Google 分享匿名使用和診斷資料,以協助改善「直播頻道」,並防止當機問題發生。"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"按向右鍵並輸入您的 PIN,以觀看這個頻道"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"按向右鍵並輸入您的 PIN,以觀看這個節目"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"這個節目的評級為<xliff:g id="RATING">%1$s</xliff:g>。\n要觀看這個節目,請按向右鍵並輸入您的 PIN。"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"只限音效"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"訊號微弱"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"沒有互聯網連線"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">由於系統正在錄影其他頻道,因此在<xliff:g id="END_TIME_1">%1$s</xliff:g>前將無法播放此頻道。\n\n請按向右鍵調整錄影時間表。</item>
+ <item quantity="one">由於系統正在錄影另一個頻道,因此在<xliff:g id="END_TIME_0">%1$s</xliff:g>前將無法播放此頻道。\n\n請按向右鍵調整錄影時間表。</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"無標題"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"已封鎖的頻道"</string>
<string name="setup_category_new" msgid="2899355289563443627">"最新"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"沒有頻道可用"</string>
<string name="setup_input_new" msgid="3337725672277046798">"最新"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"未設定"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"取得更多來源"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"瀏覽提供直播頻道的應用程式"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"查看更多來源"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"瀏覽提供直播頻道的應用程式"</string>
<string name="new_sources_title" msgid="3878933676500061895">"有可用的新頻道來源"</string>
<string name="new_sources_description" msgid="749649005588426813">"新頻道來源有可用頻道。\n立即設定頻道,或稍後在頻道來源中設定。"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"立即設定"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"所有來源頻道均已隱藏。\n請選取至少一個要觀看的頻道。"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"影片無法播放"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"[返回] 鍵適用於已連結的裝置。按一下 [主畫面] 按鈕即可結束。"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"此 Android Lollipop 裝置不支援「直播頻道」。"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"「直播頻道」需要權限方可讀取電視節目表。"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"設定頻道來源"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"直播頻道結合了傳統電視頻道和串流播放頻道 (由應用程式提供) 的觀看體驗。\n\n如要開始使用,請設定已安裝的頻道來源;或瀏覽「Google Play 商店」尋找更多提供直播頻道的應用程式。"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"錄影和時間表"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 分鐘"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 分鐘"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 小時"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 小時"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"最近"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"已預定"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"劇集"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"其他"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"無法錄影此頻道。"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"無法錄影此節目。"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"已預定《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》的錄影時間"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"從現在起到<xliff:g id="ENDTIME">%2$s</xliff:g>錄影《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"完整時間表"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">接下來 %1$d 天</item>
+ <item quantity="one">接下來 %1$d 天</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d 分鐘</item>
+ <item quantity="one">%1$d 分鐘</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d 個新錄影</item>
+ <item quantity="one">%1$d 個新錄影</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d 個錄影</item>
+ <item quantity="one">%1$d 個錄影</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">已預定 %1$d 個錄影</item>
+ <item quantity="one">已預定 %1$d 個錄影</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"觀看"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"從頭開始播放"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"恢復播放"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"刪除"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"刪除錄影"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"恢復"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"查看時間表"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"閱讀更多"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"刪除錄影"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"選取要刪除的集數。一旦刪除,將無法復原。"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"沒有可刪除的錄影。"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"選取已觀看的集數"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"選取所有集數"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"取消選取所有集數"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"已觀看 <xliff:g id="WATCHED">%1$d</xliff:g> 分鐘 (共 <xliff:g id="DURATION">%2$d</xliff:g> 分鐘)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"已觀看 <xliff:g id="WATCHED">%1$d</xliff:g> 秒 (共 <xliff:g id="DURATION">%2$d</xliff:g> 秒)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"從未觀看"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">已刪除 %1$d 集 (共 %2$d 集)</item>
+ <item quantity="one">已刪除 %1$d 集 (共 %2$d 集)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"優先級別"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"最高"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"最低"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"第 <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"頻道"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"任何頻道"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"選擇優先級別"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"如果同一時間有太多需要錄影的節目,系統只會錄影優先級別較高的節目。"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"儲存"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"單次錄影享有最高優先級別"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"取消"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"取消"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"刪除"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"停止"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"查看錄影時間表"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"只錄影這一集"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"現在 - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"全部劇集…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"仍要預定錄影"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"改為錄影此節目"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"取消此錄影"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"立即觀看"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"可錄影"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"已排定錄影時間"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"錄影時間有衝突"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"正在錄影"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"錄影失敗"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"正在讀取節目以建立錄影時間表"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"正在讀取節目"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR 需要更多儲存空間"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"您可以使用 DVR 錄影節目,但裝置目前的儲存空間不足,因此無法使用 DVR。請連接 <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB 或以上的外置硬碟,然後按步驟格式化,以用作裝置儲存空間。"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"無法存取儲存空間"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"系統存取部分 DVR 使用的儲存空間。請連接您先前使用的外置磁碟,然後重新啟用 DVR。如果儲存空間已無法使用,您亦可選擇刪除儲存空間。"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"要刪除儲存空間嗎?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"所有已錄影的內容和時間表將會遺失。"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"要停止錄影嗎?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"系統將儲存已錄影的內容。"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"已預定錄影時間,但與錄影時間有衝突"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"已開始錄影,但與其他預定錄影時間有衝突"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"系統將錄影《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》。"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"系統正在錄影「<xliff:g id="CHANNELNAME">%1$s</xliff:g>」。"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"《<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>》的部分內容將無法錄影。"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》和《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》的部分內容將無法錄影。"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》和另外一個預定節目的部分內容將無法錄影。"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">《<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>》和另外 %3$d 個預定節目的部分內容將無法錄影。</item>
+ <item quantity="one">《<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>》和另外 %3$d 個預定節目的部分內容將無法錄影。</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"您要錄影哪些內容?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"您要錄影多久?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"已預定錄影"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"已預定在 <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>錄影相同的節目。"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"已錄影"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"系統已錄影此節目並儲存在 DVR 媒體庫中。"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"找不到已錄影的節目。"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"相關錄影"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(沒有節目說明)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d 個錄影</item>
+ <item quantity="one">%1$d 個錄影</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">"/"</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》已從錄影時間表中移除"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"由於調諧器有衝突,系統只會錄影部分預定節目。"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"由於調諧器有衝突,系統不會錄影預定節目。"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"尚未預定錄影時間。\n您可以在電視節目指南中預定錄影。"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d 個錄影時間有衝突</item>
+ <item quantity="one">%1$d 個錄影時間有衝突</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"劇集設定"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"開始錄影劇集"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"停止錄影劇集"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"要停止錄影劇集嗎?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"已錄影的劇集仍將保留在 DVR 媒體庫中。"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"停止"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"沒有可供錄影的劇集。\n系統會在劇集播出時立即錄影。"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d 分鐘)</item>
+ <item quantity="one">(%1$d 分鐘)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"今天"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"明天"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"昨天"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"今天<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"明天<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"分數"</string>
</resources>
diff --git a/res/values-zh-rTW/arrays.xml b/res/values-zh-rTW/arrays.xml
index 2576dafc..8647afb4 100644
--- a/res/values-zh-rTW/arrays.xml
+++ b/res/values-zh-rTW/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"16:9 模式"</item>
<item msgid="8568284598210500589">"縮放模式"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"所有頻道"</item>
- <item msgid="6897460857821394118">"家庭/兒童"</item>
- <item msgid="551257741825778215">"體育"</item>
- <item msgid="452133796804325879">"購物"</item>
- <item msgid="3296058637230163031">"電影"</item>
- <item msgid="1054540282883891201">"喜劇"</item>
- <item msgid="7900158429062595471">"旅遊"</item>
- <item msgid="3768998587825611787">"戲劇"</item>
- <item msgid="8340620094959282881">"教育"</item>
- <item msgid="7396447839483867269">"動物/野生動物"</item>
- <item msgid="4738043455148062673">"新聞"</item>
- <item msgid="7405041316051047427">"遊戲"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"所有頻道"</item>
- <item msgid="7909003973960375395">"家庭/兒童"</item>
- <item msgid="3185279732911635789">"體育"</item>
- <item msgid="4704858492065325964">"購物"</item>
- <item msgid="6083795019290250078">"電影"</item>
- <item msgid="8302638329222449550">"喜劇"</item>
- <item msgid="3803709976021475052">"旅遊"</item>
- <item msgid="8116747365234169059">"戲劇"</item>
- <item msgid="7356447541595315913">"教育"</item>
- <item msgid="7511135485827589547">"動物/野生動物"</item>
- <item msgid="6961248112238009967">"新聞"</item>
- <item msgid="6484685553679698447">"遊戲"</item>
- <item msgid="2737158328243183190">"藝術"</item>
- <item msgid="6577176952650166615">"娛樂"</item>
- <item msgid="7886693831871777617">"生活品味"</item>
- <item msgid="8145832312485577062">"音樂"</item>
- <item msgid="1345789204804308580">"首映"</item>
- <item msgid="2736680312770771994">"科技/科學"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"所有頻道"</item>
+ <item msgid="928298872841713530">"家庭/兒童"</item>
+ <item msgid="2751606947569857164">"體育"</item>
+ <item msgid="7345749789651321496">"購物"</item>
+ <item msgid="167201149441442173">"電影"</item>
+ <item msgid="525966731464264290">"喜劇"</item>
+ <item msgid="6096710741527327836">"旅遊"</item>
+ <item msgid="2851882187117833883">"劇情"</item>
+ <item msgid="78492781188719038">"教育"</item>
+ <item msgid="7221999662426308394">"動物/野生動物"</item>
+ <item msgid="375300513250925001">"新聞"</item>
+ <item msgid="7746320336582330410">"遊戲"</item>
+ <item msgid="1255741860568329178">"藝術"</item>
+ <item msgid="7603949681065702867">"娛樂"</item>
+ <item msgid="4453821994746804366">"生活品味"</item>
+ <item msgid="3488534597567932843">"音樂"</item>
+ <item msgid="7452153120614274095">"首映"</item>
+ <item msgid="8215762047341133299">"科技/科學"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"直播頻道"</item>
diff --git a/res/values-zh-rTW/rating_system_strings.xml b/res/values-zh-rTW/rating_system_strings.xml
index 081edccb..e1cc8e8f 100644
--- a/res/values-zh-rTW/rating_system_strings.xml
+++ b/res/values-zh-rTW/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index f69a96d8..e33998ba 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"上一個"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"節目指南"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"有新頻道"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"沒有可用的連結"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"開啟 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"字幕"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"顯示模式"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"子分級"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"輸入您的 PIN 即可觀看這個頻道"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"輸入您的 PIN 即可觀看這個節目"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"這個節目的分級是「<xliff:g id="RATING">%1$s</xliff:g>」。如要觀看此節目,請輸入 PIN 碼"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"請輸入您的 PIN"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"如要設定家長監護,請建立 PIN"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"輸入新的 PIN"</string>
@@ -134,7 +134,7 @@
<item quantity="one">您已輸入 5 次錯誤的 PIN 碼,\n請於 <xliff:g id="REMAINING_SECONDS_0">%1$d</xliff:g> 秒後再試一次。</item>
</plurals>
<string name="pin_toast_wrong" msgid="2126295626095048746">"該 PIN 錯誤,請再試一次。"</string>
- <string name="pin_toast_not_match" msgid="4283624338659521768">"PIN 不符,請再試一次"</string>
+ <string name="pin_toast_not_match" msgid="4283624338659521768">"PIN 碼不符,請再試一次"</string>
<string name="side_panel_title_settings" msgid="8244327316510918755">"設定"</string>
<string name="settings_channel_source_item_customize_channels" msgid="6115770679732624593">"自訂頻道清單"</string>
<string name="settings_channel_source_item_customize_channels_description" msgid="8966243790328235580">"為您的節目指南選擇頻道"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"開放原始碼授權"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"開放原始碼授權"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"版本"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"協助改善直播頻道"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"將匿名的使用情形資料與診斷資料提供給 Google,協助我們改善直播頻道以及避免發生當機和畫面凍結等問題。"</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"如要觀看這個頻道,請按向右鍵並輸入您的 PIN"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"如要觀看這個節目,請按向右鍵並輸入您的 PIN"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"這個節目的分級是「<xliff:g id="RATING">%1$s</xliff:g>」。\n如要觀看這個節目,請按向右鍵並輸入您的 PIN"</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"僅限音訊"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"訊號微弱"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"沒有網際網路連線"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="other">目前正在錄製其他頻道,因此<xliff:g id="END_TIME_1">%1$s</xliff:g> 前都無法播放這個頻道。\n\n按向右鍵可調整錄製時間表。</item>
+ <item quantity="one">目前正在錄製其他頻道,因此<xliff:g id="END_TIME_0">%1$s</xliff:g> 前都無法播放這個頻道。\n\n按向右鍵可調整錄製時間表。</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"無標題"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"頻道遭到封鎖"</string>
<string name="setup_category_new" msgid="2899355289563443627">"新的頻道來源"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"沒有任何頻道"</string>
<string name="setup_input_new" msgid="3337725672277046798">"新輸入裝置"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"尚未設定"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"取得更多頻道來源"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"瀏覽提供直播頻道的應用程式"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"取得更多頻道來源"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"瀏覽提供直播頻道的應用程式"</string>
<string name="new_sources_title" msgid="3878933676500061895">"有可用的新頻道來源"</string>
<string name="new_sources_description" msgid="749649005588426813">"新頻道來源現在可提供更多頻道。\n您可選擇立即設定這些頻道,或稍後再前往頻道來源設定專區進行設定。"</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"立即設定"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"所有來源頻道皆已隱藏。\n請選取至少一個要觀看的頻道。"</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"影片無法播放,原因不明"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"返回鍵適用於連線的裝置,按下主螢幕按鈕即可結束。"</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"這個搭載 Android Lollipop 的裝置不支援「直播頻道」。"</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"「直播頻道」需要權限才能讀取電視節目表。"</string>
<string name="setup_sources_text" msgid="4988039637873759839">"設定您的頻道來源"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"直播頻道具備傳統電視頻道的功能,同時還能播放應用程式所提供的串流頻道。\n\n如要開始使用,請設定已安裝的頻道來源,或是前往 Google Play 商店尋找更多提供直播頻道的應用程式。"</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"錄製項目和錄製時間表"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 分鐘"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 分鐘"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 小時"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 小時"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"近期錄下的節目"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"預約錄影"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"劇集"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"其他"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"無法錄製這個頻道。"</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"無法錄製這個節目。"</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"已排定《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》的錄影時間"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"從現在起到<xliff:g id="ENDTIME">%2$s</xliff:g>,系統將錄製《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"完整時間表"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="other">接下來 %1$d 天</item>
+ <item quantity="one">接下來 %1$d 天</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="other">%1$d 分鐘</item>
+ <item quantity="one">%1$d 分鐘</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="other">%1$d 個新的錄製項目</item>
+ <item quantity="one">%1$d 個新的錄製項目</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="other">%1$d 個錄製項目</item>
+ <item quantity="one">%1$d 個錄製項目</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="other">已預約錄製 %1$d 個節目</item>
+ <item quantity="one">已預約錄製 %1$d 個節目</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"觀看"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"從頭開始播放"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"繼續播放"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"刪除"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"刪除錄影節目"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"繼續"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"第 <xliff:g id="SEASON_NUMBER">%1$s</xliff:g> 季"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"查看時間表"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"閱讀完整內容"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"刪除錄影節目"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"選取要刪除的集數。請注意,刪除後即無法復原。"</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"沒有可刪除的錄影節目。"</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"選取觀看過的集數"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"選取所有集數"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"取消刪除所有集數"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"已觀看 <xliff:g id="WATCHED">%1$d</xliff:g> 分鐘 (共 <xliff:g id="DURATION">%2$d</xliff:g> 分鐘)"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"已觀看 <xliff:g id="WATCHED">%1$d</xliff:g> 秒 (共 <xliff:g id="DURATION">%2$d</xliff:g> 秒)"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"從未觀看過"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="other">已刪除 %1$d 集 (共 %2$d 集)</item>
+ <item quantity="one">已刪除 %1$d 集 (共 %2$d 集)</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"優先順序"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"最高"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"最低"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"第 <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"頻道"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"不限"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"選擇優先順序"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"如果同一時段錄製的節目過多,系統只會錄製優先順序較高的節目。"</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"儲存"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"只排定錄製一次的項目優先順序最高"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"取消"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"取消"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"移除"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"停止"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"查看錄影時間表"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"只錄這一集"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"現在 - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"整部影集…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"仍要預約錄影"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"改錄這個節目"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"取消這項錄影預約"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"立即觀看"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"可錄影"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"已排定錄影時間"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"錄影衝突"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"錄製中"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"錄製失敗"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"正在讀取節目以建立錄影時間表"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"正在讀取節目"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"DVR 需要更多儲存空間"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"你可以利用 DVR 錄製節目,但目前裝置儲存空間不足,因此無法使用 DVR。請連接 <xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB 以上的外接式磁碟,然後按照相關步驟將該磁碟格式化為裝置儲存空間。"</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"無法存取儲存空間"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"無法存取部分 DVR 使用的儲存空間。請連接你先前使用的外接式磁碟以重新啟用 DVR。如果儲存空間已無法使用,你也可以選擇移除儲存空間。"</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"要移除儲存空間嗎?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"所有錄製內容和錄影時間表都不會保存下來。"</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"要停止錄影嗎?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"系統將儲存已錄製的內容。"</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"已排定錄影時間,但錄影時間發生衝突"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"已開始錄影,但發生衝突"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"系統將會錄製《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》。"</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"正在錄製「<xliff:g id="CHANNELNAME">%1$s</xliff:g>」。"</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"《<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g>》將有部分內容無法錄製。"</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》和《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》將有部分內容無法錄製。"</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"《<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g>》和另外 1 個排定的節目將有部分內容無法錄製。"</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="other">《<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>》、<xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g>》和另外 %3$d 個排定的節目將有部分內容無法錄製。</item>
+ <item quantity="one">《<xliff:g id="CONFLICTPROGRAMNAME_1_0">%1$s</xliff:g>》、《<xliff:g id="CONFLICTPROGRAMNAME_2_1">%2$s</xliff:g>》和另外 %3$d 個排定的節目將有部分內容無法錄製。</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"您要錄製哪些內容?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"你/妳想錄製多久的時間?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"已預約錄影"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"同一個節目已預約在 <xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g> 錄影。"</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"已錄影"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"這個節目已完成錄影並儲存在 DVR 媒體庫中。"</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"找不到錄製的節目。"</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"相關錄影"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(無節目說明)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="other">%1$d 個錄製項目</item>
+ <item quantity="one">%1$d 個錄製項目</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">"/"</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"《<xliff:g id="PROGRAMNAME">%1$s</xliff:g>》已從錄影時間表中移除"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"沒有可用的調諧器,因此只能錄製部分內容。"</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"沒有可用的調諧器,因此無法錄製。"</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"沒有任何預約錄影。\n你可以透過節目指南預約錄影。"</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="other">%1$d 項錄影衝突</item>
+ <item quantity="one">%1$d 項錄影衝突</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"影集錄製設定"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"開始建立影集錄製時間表"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"停止建立影集錄製時間表"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"要停止建立影集錄製時間表嗎?"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"錄製完畢的集數會保存在 DVR 媒體庫中。"</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"停止"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"目前沒有可供觀看的集數。\n系統會在節目播出時立即錄影。"</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="other">(%1$d 分鐘)</item>
+ <item quantity="one">(%1$d 分鐘)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"今天"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"明天"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"昨天"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"今天:<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"明天:<xliff:g id="TIME_RANGE">%1$s</xliff:g>"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"分數"</string>
</resources>
diff --git a/res/values-zu/arrays.xml b/res/values-zu/arrays.xml
index f1f9bd7f..03f7be29 100644
--- a/res/values-zu/arrays.xml
+++ b/res/values-zu/arrays.xml
@@ -22,39 +22,25 @@
<item msgid="2533030282864800794">"Kugcwele"</item>
<item msgid="8568284598210500589">"Sondeza"</item>
</string-array>
- <string-array name="genre_labels_l">
- <item msgid="4730006281716266127">"Zonke iziteshi"</item>
- <item msgid="6897460857821394118">"Umndeni/abantwana"</item>
- <item msgid="551257741825778215">"Ezemidlalo"</item>
- <item msgid="452133796804325879">"Ukuthenga"</item>
- <item msgid="3296058637230163031">"Ama-Movie"</item>
- <item msgid="1054540282883891201">"Awamahlaya"</item>
- <item msgid="7900158429062595471">"Ukuvakasha"</item>
- <item msgid="3768998587825611787">"IDrama"</item>
- <item msgid="8340620094959282881">"Imfundo"</item>
- <item msgid="7396447839483867269">"Izilwane/impilo yasendle"</item>
- <item msgid="4738043455148062673">"Izindaba"</item>
- <item msgid="7405041316051047427">"Awamageyimu"</item>
- </string-array>
- <string-array name="genre_labels_l_mr1">
- <item msgid="7173498629837517739">"Zonke iziteshi"</item>
- <item msgid="7909003973960375395">"Umndeni/abantwana"</item>
- <item msgid="3185279732911635789">"Ezemidlalo"</item>
- <item msgid="4704858492065325964">"Ukuthenga"</item>
- <item msgid="6083795019290250078">"Ama-Movie"</item>
- <item msgid="8302638329222449550">"Awamahlaya"</item>
- <item msgid="3803709976021475052">"Ukuvakasha"</item>
- <item msgid="8116747365234169059">"IDrama"</item>
- <item msgid="7356447541595315913">"Imfundo"</item>
- <item msgid="7511135485827589547">"Izilwane/impilo yasendle"</item>
- <item msgid="6961248112238009967">"Izindaba"</item>
- <item msgid="6484685553679698447">"Awamageyimu"</item>
- <item msgid="2737158328243183190">"Ezobuciko"</item>
- <item msgid="6577176952650166615">"Okokuzijabulisa"</item>
- <item msgid="7886693831871777617">"Indlela yokuphila"</item>
- <item msgid="8145832312485577062">"Umculo"</item>
- <item msgid="1345789204804308580">"I-Premier"</item>
- <item msgid="2736680312770771994">"Ubuchwepheshe/isayensi"</item>
+ <string-array name="genre_labels">
+ <item msgid="3241959001790384341">"Zonke iziteshi"</item>
+ <item msgid="928298872841713530">"Umndeni/abantwana"</item>
+ <item msgid="2751606947569857164">"Ezemidlalo"</item>
+ <item msgid="7345749789651321496">"Ukuthenga"</item>
+ <item msgid="167201149441442173">"Ama-movie"</item>
+ <item msgid="525966731464264290">"Awamahlaya"</item>
+ <item msgid="6096710741527327836">"Ukuvakasha"</item>
+ <item msgid="2851882187117833883">"Awomdlalo"</item>
+ <item msgid="78492781188719038">"Imfundo"</item>
+ <item msgid="7221999662426308394">"Izilwane/impilo yasendle"</item>
+ <item msgid="375300513250925001">"Awezindaba"</item>
+ <item msgid="7746320336582330410">"Awamageyimu"</item>
+ <item msgid="1255741860568329178">"Ezobuciko"</item>
+ <item msgid="7603949681065702867">"Ukuzijabulisa"</item>
+ <item msgid="4453821994746804366">"Indlela yokuphila"</item>
+ <item msgid="3488534597567932843">"Umculo"</item>
+ <item msgid="7452153120614274095">"I-Premier"</item>
+ <item msgid="8215762047341133299">"Ubuchwepheshe/isayensi"</item>
</string-array>
<string-array name="welcome_page_titles">
<item msgid="8322900543391231769">"Iziteshi ezibukhoma"</item>
diff --git a/res/values-zu/rating_system_strings.xml b/res/values-zu/rating_system_strings.xml
index 404825f5..1a21d354 100644
--- a/res/values-zu/rating_system_strings.xml
+++ b/res/values-zu/rating_system_strings.xml
@@ -17,6 +17,54 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for description_age_4 (2260506104299774027) -->
+ <skip />
+ <!-- no translation found for description_age_5 (312882360850848623) -->
+ <skip />
+ <!-- no translation found for description_age_6 (7780895021659413979) -->
+ <skip />
+ <!-- no translation found for description_age_7 (7465836675187750087) -->
+ <skip />
+ <!-- no translation found for description_age_8 (8518389733138803056) -->
+ <skip />
+ <!-- no translation found for description_age_9 (1963837231871036561) -->
+ <skip />
+ <!-- no translation found for description_age_10 (9199865628328446876) -->
+ <skip />
+ <!-- no translation found for description_age_11 (1056140065021078183) -->
+ <skip />
+ <!-- no translation found for description_age_12 (2523883089926997157) -->
+ <skip />
+ <!-- no translation found for description_age_13 (4539863086843940979) -->
+ <skip />
+ <!-- no translation found for description_age_14 (276938165219847540) -->
+ <skip />
+ <!-- no translation found for description_age_15 (3875804533354572649) -->
+ <skip />
+ <!-- no translation found for description_age_16 (7068358107904351707) -->
+ <skip />
+ <!-- no translation found for description_age_17 (6090244054207338066) -->
+ <skip />
+ <!-- no translation found for description_age_18 (7827138562117972763) -->
+ <skip />
+ <!-- no translation found for description_age_19 (5739639668332937969) -->
+ <skip />
+ <!-- no translation found for description_age_20 (8099318760823109592) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_exempt (3869530797231884669) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c (6170724506314571912) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_c8 (7942870097063909046) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_g (7893908216230285607) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_pg (2736709384517099303) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_14 (8063534593921657009) -->
+ <skip />
+ <!-- no translation found for description_ca_tv_en_18 (3552078692829803323) -->
+ <skip />
<!-- no translation found for description_fr_dvb_u (8232083238497153682) -->
<skip />
<!-- no translation found for description_es_dvb_all (4821183217465284547) -->
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index fc39708a..ff1cfb3d 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -31,7 +31,6 @@
<string name="play_controls_description_skip_previous" msgid="3858447678278021381">"Okwangaphambilini"</string>
<string name="channels_item_program_guide" msgid="2889807207930678418">"Umhlahlandlela wohlelo"</string>
<string name="channels_item_setup" msgid="6557412175737379022">"Iziteshi ezintsha ziyatholakala"</string>
- <string name="channels_item_app_link_no_app_link" msgid="1884830234777824408">"Asikho isixhumanisi esitholakalayo"</string>
<string name="channels_item_app_link_app_launcher" msgid="1395352122187670523">"Vula i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="options_item_closed_caption" msgid="5945274655046367170">"Amazwibela avaliwe"</string>
<string name="options_item_display_mode" msgid="7989243076748680140">"Imodi yesibonisi"</string>
@@ -124,6 +123,7 @@
<string name="option_subrating_header" msgid="4637961301549615855">"Izilinganiso zangaphansi"</string>
<string name="pin_enter_unlock_channel" msgid="4797922378296393173">"Faka iphinikhodi yakho ukuze ubuke lesi siteshi"</string>
<string name="pin_enter_unlock_program" msgid="7311628843209871203">"Faka iphinikhodi yakho ukuze ubuke lolu hlelo"</string>
+ <string name="pin_enter_unlock_dvr" msgid="1637468108723176684">"Lolu hlelo lulinganiselwe ku-<xliff:g id="RATING">%1$s</xliff:g>. Faka iphini yakho ukuze ubuke lolu hlelo"</string>
<string name="pin_enter_pin" msgid="249314665028035038">"Faka iphinikhodi yakho"</string>
<string name="pin_enter_create_pin" msgid="3385754356793309946">"Ukuze usethe izilawuli zomzali, dala iphinikhodi"</string>
<string name="pin_enter_new_pin" msgid="1739471585849790384">"Faka iphinikhodi entsha"</string>
@@ -144,8 +144,6 @@
<string name="settings_menu_licenses" msgid="1257646083838406103">"Amalayisense womthombo ovulekile"</string>
<string name="dialog_title_licenses" msgid="4471754920475076623">"Amalayisense womthombo ovulekile"</string>
<string name="settings_menu_version" msgid="2604030372029921403">"Inguqulo"</string>
- <string name="about_menu_improve" msgid="3712578027009311401">"Siza ukuthuthukisa Iziteshi Ezibukhoma"</string>
- <string name="about_menu_improve_summary" msgid="7548489011760588571">"Yabelana ngedatha yokusebenza yokungaziwa neyokuhlola ne-Google ukuze sikwazi ukwenza kangcono iziteshi ezibukhoma futhi sivikele izinkinga ezifana nokusaphazeka nokjema."</string>
<string name="tvview_channel_locked" msgid="6486375335718400728">"Ukuze ubuke lesi siteshi, cindezela Kwesokudla uphinde ufake i-PIN yakho"</string>
<string name="tvview_content_locked" msgid="391823084917017730">"Ukuze ubuke lolu hlelo, cindezela Kwesokudla uphinde ufake i-PIN yakho"</string>
<string name="tvview_content_locked_format" msgid="3741874636031338247">"Lolu hlelo lulinganiselwe ngo-<xliff:g id="RATING">%1$s</xliff:g>.\nUkuze ubuke lolu hlelo, cindezela Kwesokudla uphinde ufake i-PIN yakho."</string>
@@ -157,6 +155,10 @@
<string name="tvview_msg_audio_only" msgid="1356866203687173329">"Umsindo kuphela"</string>
<string name="tvview_msg_weak_signal" msgid="1095050812622908976">"Isignali engaqinile"</string>
<string name="tvview_msg_no_internet_connection" msgid="7655994401188888231">"Alukho uxhumano lwe-intanethi"</string>
+ <plurals name="tvview_msg_input_no_resource" formatted="false" msgid="8581894855153658823">
+ <item quantity="one">Lesi siteshi asikwazi ukudlalwa kuze kube ngu-<xliff:g id="END_TIME_1">%1$s</xliff:g> ngoba ezinye iziteshi ziyarekhodwa. \n\nCindezela Kwesokudla ukuze ulungise ishejuli yokurekhoda.</item>
+ <item quantity="other">Lesi siteshi asikwazi ukudlalwa kuze kube ngu-<xliff:g id="END_TIME_1">%1$s</xliff:g> ngoba ezinye iziteshi ziyarekhodwa. \n\nCindezela Kwesokudla ukuze ulungise ishejuli yokurekhoda.</item>
+ </plurals>
<string name="channel_banner_no_title" msgid="8660301979190693176">"Asikho isihloko"</string>
<string name="channel_banner_locked_channel_title" msgid="2006564967318945980">"Isiteshi sivinjiw"</string>
<string name="setup_category_new" msgid="2899355289563443627">"Okusha"</string>
@@ -168,8 +170,8 @@
<string name="setup_input_no_channels" msgid="1669327912393163331">"Azikho iziteshi ezitholakalayo"</string>
<string name="setup_input_new" msgid="3337725672277046798">"Okusha"</string>
<string name="setup_input_setup_now" msgid="1772000402336958967">"Akusethiwe"</string>
- <string name="setup_play_store_action_title" msgid="859347291072224673">"Thola imithombo eminingi"</string>
- <string name="setup_play_store_action_description" msgid="2472226338824629506">"Dlulisa amehlo kuziphequluli ezinikeza iziteshi ezibukhoma"</string>
+ <string name="setup_store_action_title" msgid="4083402039720973414">"Thola imithombo eminingi"</string>
+ <string name="setup_store_action_description" msgid="6820482635042445297">"Dlulisa amehlo kuziphequluli ezinikeza iziteshi ezibukhoma"</string>
<string name="new_sources_title" msgid="3878933676500061895">"Imithombo yesiteshi esisha iyatholakala"</string>
<string name="new_sources_description" msgid="749649005588426813">"Imithombo yesiteshi emisha ineziteshi ezinikezelayo.\nIsethe manje, noma yenza lokhu emuva kwesikhathi kusilungiselelo somthombo wesiteshi."</string>
<string name="new_sources_action_setup" msgid="177693761664016811">"Setha manje"</string>
@@ -187,8 +189,162 @@
<string name="msg_all_channels_hidden" msgid="777397634062471936">"Zonke iziteshi zomthombo zifihliwe.\nKhetha okungenani isiteshi esisodwa ukuze ubuke."</string>
<string name="msg_channel_unavailable_unknown" msgid="765586450831081871">"Ividiyo ayitholakali ngokungalindelekile"</string>
<string name="msg_back_key_guide" msgid="7404682718828721924">"Ukhiye we-EMUVA ungowedivayisi exhunyiwe. Cindezela kunkinobho ye-IKHAYA ukuze uphume."</string>
- <string name="msg_not_supported_device" msgid="4469404625040284722">"Iziteshi ezibukhoma azisekelwa kule divayisi nge-Android Lollipop."</string>
<string name="msg_read_tv_listing_permission_denied" msgid="8882813301235518909">"Iziteshi ezibukhoma zidinga imvume ukuze zifunde ukufakwa kuhlu kwe-TV."</string>
<string name="setup_sources_text" msgid="4988039637873759839">"Setha imithombo yakho"</string>
<string name="setup_sources_description" msgid="5695518946225445202">"Iziteshi ezibukhoma zihlanganisa umuzwa wosiko weziteshi ze-TV ngokusakaza iziteshi ezinikezwe izinhlelo zokusebenza.\n\nQalisa ngokusetha imithombo yesiteshi esivele ifakiwe. Noma dlulisa amehlo ku-Google Play Isitolo ukuze uthole izinhlelo zokusebenza eziningi ezinikezela iziteshi ezibukhoma."</string>
+ <string name="channels_item_dvr" msgid="8911915252648532469">"Ukurekhoda manashejuli"</string>
+ <string name="recording_start_dialog_10_min_duration" msgid="5739636508245795292">"10 amaminithi"</string>
+ <string name="recording_start_dialog_30_min_duration" msgid="4691127772622189977">"30 amaminithi"</string>
+ <string name="recording_start_dialog_1_hour_duration" msgid="7159533207022355641">"1 ihora"</string>
+ <string name="recording_start_dialog_3_hours_duration" msgid="295984419320006238">"3 amahora"</string>
+ <string name="dvr_main_recent" msgid="2553805424822806495">"Okwakamuva"</string>
+ <string name="dvr_main_scheduled" msgid="7837260963086408492">"Ishejuliwe"</string>
+ <string name="dvr_main_series" msgid="8278256687595691676">"Uchungechunge"</string>
+ <string name="dvr_main_others" msgid="2970835573614038153">"Abanye"</string>
+ <string name="dvr_msg_cannot_record_channel" msgid="6836291367918532447">"Isiteshi asikwazi ukurekhodwa."</string>
+ <string name="dvr_msg_cannot_record_program" msgid="4184046342810946090">"Uhlelo alukwazi ukurekhodwa."</string>
+ <string name="dvr_msg_program_scheduled" msgid="3800847542300367572">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> ishejulelwe ukurekhodwa"</string>
+ <string name="dvr_msg_current_program_scheduled" msgid="2505247201782991463">"Irekhoda i-<xliff:g id="PROGRAMNAME">%1$s</xliff:g> kusukela manje ukuya ku-<xliff:g id="ENDTIME">%2$s</xliff:g>"</string>
+ <string name="dvr_full_schedule_card_view_title" msgid="7198521806965950089">"Ishejuli egcwele"</string>
+ <plurals name="dvr_full_schedule_card_view_content" formatted="false" msgid="790788122541080768">
+ <item quantity="one">Izinsuku ezingu-%1$d ezilandelayo</item>
+ <item quantity="other">Izinsuku ezingu-%1$d ezilandelayo</item>
+ </plurals>
+ <plurals name="dvr_program_duration" formatted="false" msgid="6742119148312354741">
+ <item quantity="one">%1$d amaminithi</item>
+ <item quantity="other">%1$d amaminithi</item>
+ </plurals>
+ <plurals name="dvr_count_new_recordings" formatted="false" msgid="3569310208305402815">
+ <item quantity="one">%1$d ukurekhodwa okusha</item>
+ <item quantity="other">%1$d ukurekhodwa okusha</item>
+ </plurals>
+ <plurals name="dvr_count_recordings" formatted="false" msgid="7417379223468131391">
+ <item quantity="one">%1$d ukurekhodwa</item>
+ <item quantity="other">%1$d ukurekhodwa</item>
+ </plurals>
+ <plurals name="dvr_count_scheduled_recordings" formatted="false" msgid="1650330290765214511">
+ <item quantity="one">%1$d ukurekhodwa okushejuliwe</item>
+ <item quantity="other">%1$d ukurekhodwa okushejuliwe</item>
+ </plurals>
+ <string name="dvr_detail_watch" msgid="7085694764364338215">"Buka"</string>
+ <string name="dvr_detail_play_from_beginning" msgid="8475543568260411836">"Dlala kusuka ekuqaleni"</string>
+ <string name="dvr_detail_resume_play" msgid="875591300274416373">"Qalisa ukudlala"</string>
+ <string name="dvr_detail_delete" msgid="4535881013528321898">"Susa"</string>
+ <string name="dvr_detail_series_delete" msgid="4831926831670312674">"Susa ukurekhodwa"</string>
+ <string name="dvr_detail_series_resume" msgid="6935136228671386246">"Qalisa kabusha"</string>
+ <string name="dvr_detail_series_season_title" msgid="5474850936497854790">"Isizini <xliff:g id="SEASON_NUMBER">%1$s</xliff:g>"</string>
+ <string name="dvr_detail_view_schedule" msgid="7137536927421904426">"Buka ishejula"</string>
+ <string name="dvr_detail_read_more" msgid="2588920758094498544">"Funda kabanzi"</string>
+ <string name="dvr_series_deletion_title" msgid="7672649492494507574">"Susa ukurekhodwa"</string>
+ <string name="dvr_series_deletion_description" msgid="994839237906552969">"Khetha zonke iziqephu ongathanda ukuzisusa. Azikwazi ukuphinda zitholwe uma sezisusiwe."</string>
+ <string name="dvr_series_deletion_no_recordings" msgid="481210819034514">"Akukho ukurekhodwa okuzosuswa."</string>
+ <string name="dvr_series_select_watched" msgid="3608122404146716502">"Khetha iziqephu ezibukiwe"</string>
+ <string name="dvr_series_select_all" msgid="5415749261739544048">"Khetha zonke iziqephu"</string>
+ <string name="dvr_series_deselect_all" msgid="1680395960166387572">"Susa ukukhetha kuzo zonke iziqephu"</string>
+ <string name="dvr_series_watched_info_minutes" msgid="5656926431901526030">"<xliff:g id="WATCHED">%1$d</xliff:g> yamaminithi angu-<xliff:g id="DURATION">%2$d</xliff:g> abukiwe"</string>
+ <string name="dvr_series_watched_info_seconds" msgid="2667537184197566662">"<xliff:g id="WATCHED">%1$d</xliff:g> yamasekhondi angu-<xliff:g id="DURATION">%2$d</xliff:g> abukiwe"</string>
+ <string name="dvr_series_never_watched" msgid="6086008065876122655">"Okungakaze kwabukwa sanhlobo"</string>
+ <plurals name="dvr_msg_episodes_deleted" formatted="false" msgid="5627112959798353905">
+ <item quantity="one">%1$d yeziqephu ezingu-%2$d zisusiwe</item>
+ <item quantity="other">%1$d yeziqephu ezingu-%2$d zisusiwe</item>
+ </plurals>
+ <string name="dvr_series_settings_priority" msgid="5836437092774185710">"Okubalulekile"</string>
+ <string name="dvr_series_settings_priority_highest" msgid="1072006447796648382">"Kuphezulu kakhulu"</string>
+ <string name="dvr_series_settings_priority_lowest" msgid="6003996497908810225">"Kuphansi kakhulu"</string>
+ <string name="dvr_series_settings_priority_rank" msgid="667778382820956116">"Inombolo. <xliff:g id="RANK">%1$d</xliff:g>"</string>
+ <string name="dvr_series_settings_channels" msgid="3164900110165729909">"Iziteshi"</string>
+ <string name="dvr_series_settings_channels_all" msgid="656434955168572976">"Noma ikuphi"</string>
+ <string name="dvr_priority_title" msgid="1537886929061487213">"Khetha okubalulekile"</string>
+ <string name="dvr_priority_description" msgid="8362040921417154645">"Uma kunezinhlelo eziningi kakhulu okufanele zirekhodwe ngesikhathi esisodwa, yilezo ezinokukhetha okuphezulu ezizorekhodwa."</string>
+ <string name="dvr_priority_button_action_save" msgid="4773524273649733008">"Londoloza"</string>
+ <string name="dvr_priority_action_one_time_recording" msgid="8174297042282719478">"Ukurekhoda kwesikhathi esisodwa kunokubaluleka okuphezulu kakhulu"</string>
+ <string name="dvr_action_cancel" msgid="8094060199570272625">"Khansela"</string>
+ <string name="dvr_action_error_cancel" msgid="6822474458738023531">"Khansela"</string>
+ <string name="dvr_action_error_forget_storage" msgid="5869994565663655638">"Khohlwa"</string>
+ <string name="dvr_action_stop" msgid="1378723485295471381">"Misa"</string>
+ <string name="dvr_action_view_schedules" msgid="7442990695392774263">"Buka ishejuli yokurekhoda"</string>
+ <string name="dvr_action_record_episode" msgid="8596182676610326327">"Lolu hlelo olulodwa"</string>
+ <string name="dvr_action_record_episode_from_now_description" msgid="5125122951529985697">"manje - <xliff:g id="ENDTIME">%1$s</xliff:g>"</string>
+ <string name="dvr_action_record_series" msgid="8501991316179436899">"Lonke uchungechunge…"</string>
+ <string name="dvr_action_record_anyway" msgid="991470058034937231">"Shejula noma kunjalo"</string>
+ <string name="dvr_action_record_instead" msgid="6821164728752215738">"Rekhoda lokhu esikhundleni"</string>
+ <string name="dvr_action_record_cancel" msgid="8644254745772185288">"Khansela lokhu kurekhoda"</string>
+ <string name="dvr_action_watch_now" msgid="7181211920959075976">"Bukela njengamanje"</string>
+ <string name="dvr_epg_program_recordable" msgid="609229576209476903">"Okungarekhodeka"</string>
+ <string name="dvr_epg_program_recording_scheduled" msgid="1367741844291055016">"Ukurekhoda kushejuliwe"</string>
+ <string name="dvr_epg_program_recording_conflict" msgid="4827911748865195373">"Ukungqubuzana kokurekhoda"</string>
+ <string name="dvr_epg_program_recording_in_progress" msgid="2158340443975313745">"Iyarekhoda"</string>
+ <string name="dvr_epg_program_recording_failed" msgid="5589124519442328896">"Ukurekhoda kuhlulekile"</string>
+ <string name="dvr_schedule_progress_message_reading_programs" msgid="6502513156469172313">"Ifunda izinhlelo ukuze idale amashejuli okurekhoda"</string>
+ <string name="dvr_series_schedules_progress_message_reading_programs" msgid="7221275889560136115">"Izinhlelo ezifundayo"</string>
+ <!-- no translation found for dvr_series_schedules_progress_message_updating_programs (6670286486601662465) -->
+ <skip />
+ <string name="dvr_error_small_sized_storage_title" msgid="5020225460011469011">"I-DVR idinga isitoreji esiningi"</string>
+ <string name="dvr_error_small_sized_storage_description" msgid="8909789097974895119">"Uzokwazi ukurekhoda izinhlelo nge-DVR. Kodwa asikho isitoreji esanele kudivayisi yakho manje ukuze i-DVR isebenze. Sicela uxhume idrayivu yangaphandle engu-<xliff:g id="STORAGE_SIZE">%1$s</xliff:g>GB noma enkulu bese ulandela izinyathelo uyifomethe njengesitoreji sedivayisi."</string>
+ <string name="dvr_error_missing_storage_title" msgid="691914341845362669">"Isitoreji esilahlekile"</string>
+ <string name="dvr_error_missing_storage_description" msgid="1036680750969954236">"Esinye sesitoreji esisetshenziswa yi-DVR silahlekile. Sicela uxhume idrayivu engaphandle oyisebenzise ngaphambilini ukuze uphinde unike amandla i-DVR. Okunye, ungakhetha ukukhohlwa isitoreji uma singasatholakali."</string>
+ <string name="dvr_error_forget_storage_title" msgid="4996547357826788002">"Khohlwa isitoreji?"</string>
+ <string name="dvr_error_forget_storage_description" msgid="3973761741009546142">"Konke okuqukethwe kwakho okurekhodiwe namashejuli azolahleka."</string>
+ <string name="dvr_stop_recording_dialog_title" msgid="2587018956502704278">"Misa ukurekhoda?"</string>
+ <string name="dvr_stop_recording_dialog_description" msgid="4637830189399967761">"Okuqukethwe okurekhodiwe kuzolondolozwa."</string>
+ <!-- no translation found for dvr_stop_recording_dialog_description_on_conflict (7876857267536083760) -->
+ <skip />
+ <string name="dvr_program_conflict_dialog_title" msgid="109323740107060379">"Ukurekhoda kushejuliwe kodwa kunokugqubuzana"</string>
+ <string name="dvr_channel_conflict_dialog_title" msgid="7461033430572027786">"Ukurekhoda kuqalile kodwa kunokugxubuzana"</string>
+ <string name="dvr_program_conflict_dialog_description_prefix" msgid="5520062013211648196">"<xliff:g id="PROGRAMNAME">%1$s</xliff:g> izorekhodwa."</string>
+ <string name="dvr_channel_conflict_dialog_description_prefix" msgid="212344250779878791">"<xliff:g id="CHANNELNAME">%1$s</xliff:g> iyarekhodwa."</string>
+ <string name="dvr_program_conflict_dialog_description_1" msgid="2278200346765501164">"Ezinye izingxenye ze-<xliff:g id="CONFLICTPROGRAMNAME">%1$s</xliff:g> ngeke zirekhodwe."</string>
+ <string name="dvr_program_conflict_dialog_description_2" msgid="5648524408147235696">"Ezinye izingxenye ze-<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g> ne-<xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> ngeke zirekhodwe."</string>
+ <string name="dvr_program_conflict_dialog_description_3" msgid="6879199850098595108">"Ezinye izingxenye ze-<xliff:g id="CONFLICTPROGRAMNAME_1">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2">%2$s</xliff:g> neshejuli eyodwa ngaphezulu ngeke kurekhodwe."</string>
+ <plurals name="dvr_program_conflict_dialog_description_many" formatted="false" msgid="1008340710252647947">
+ <item quantity="one">Ezinye izinhlelo ze-<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> namashejuli angu-%3$d ngaphezulu ngeke kurekhodwe.</item>
+ <item quantity="other">Ezinye izinhlelo ze-<xliff:g id="CONFLICTPROGRAMNAME_1_2">%1$s</xliff:g>, <xliff:g id="CONFLICTPROGRAMNAME_2_3">%2$s</xliff:g> namashejuli angu-%3$d ngaphezulu ngeke kurekhodwe.</item>
+ </plurals>
+ <string name="dvr_schedule_dialog_title" msgid="5235629824986156058">"Ungathanda ukurekhoda ini?"</string>
+ <string name="dvr_channel_record_duration_dialog_title" msgid="4601361040431047918">"Ungathanda ukurekhoda isikhathi esingakanani?"</string>
+ <string name="dvr_already_scheduled_dialog_title" msgid="4525318291210934311">"Sekuhlele kuhleliwe"</string>
+ <string name="dvr_already_scheduled_dialog_description" msgid="8170126125996414810">"Uhlelo olufanayo seluvele luhlelwe ukurekhodwa ngo-<xliff:g id="PROGRAMSTARTTIME">%1$s</xliff:g>."</string>
+ <string name="dvr_already_recorded_dialog_title" msgid="2760294707162057216">"Sekuvele kurekhodiwe"</string>
+ <string name="dvr_already_recorded_dialog_description" msgid="8966051583682746434">"Lolu hlelo seluvele lurekhodiwe. Lutholakala kulabhulali ye-DVR."</string>
+ <!-- no translation found for dvr_series_recording_dialog_title (3521956660855853797) -->
+ <skip />
+ <!-- no translation found for dvr_series_recording_scheduled_no_conflict (2796926724821316879) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_this_series_conflict (2800805130979023066) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_one_conflict (3632394665556633158) -->
+ <!-- no translation found for dvr_series_recording_scheduled_this_and_other_series_conflict (2331412040101938479) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_one_conflict (5213169239215104024) -->
+ <!-- no translation found for dvr_series_recording_scheduled_only_other_series_conflict (5159645486201045330) -->
+ <string name="dvr_program_not_found" msgid="3282879532038010202">"Uhlelo olurekhodiwe alutholakali."</string>
+ <string name="dvr_playback_related_recordings" msgid="6978658039329924961">"Ukurekhodwa okuhlobene"</string>
+ <string name="dvr_msg_no_program_description" msgid="2521723281247322645">"(Ayikho incazelo yohlelo)"</string>
+ <plurals name="dvr_schedules_section_subtitle" formatted="false" msgid="9180744010405976007">
+ <item quantity="one">%1$d ukurekhoda</item>
+ <item quantity="other">%1$d ukurekhoda</item>
+ </plurals>
+ <string name="dvr_schedules_information_separator" msgid="1669116853379998479">" / "</string>
+ <string name="dvr_schedules_deletion_info" msgid="2837586459900271031">"I-<xliff:g id="PROGRAMNAME">%1$s</xliff:g> isusiwe kusukela kushejuli yokurekhoda"</string>
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded" msgid="5280490298546908729">"Izorekhodwa kancane ngenxa yokushayisana kweshuna."</string>
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info" msgid="5065400564003201095">"Ngeke ize irekhodwe ngenxa yokushayisana kweshuna."</string>
+ <string name="dvr_schedules_empty_state" msgid="1291529283469462741">"Akukho ukurekhoda kushejuli okwamanje.\nUngahlela ukurekhoda kusuka kumhlahlandlela yohlelo."</string>
+ <plurals name="dvr_series_schedules_header_description" formatted="false" msgid="9077188267856194114">
+ <item quantity="one">%1$d ukugcubuzana kokurekhoda</item>
+ <item quantity="other">%1$d ukugcubuzana kokurekhoda</item>
+ </plurals>
+ <string name="dvr_series_schedules_settings" msgid="4868501926847903985">"Izilungiselelo zochungechunge"</string>
+ <string name="dvr_series_schedules_start" msgid="8458768834047133835">"Qala ukurekhoda kochungechunge"</string>
+ <string name="dvr_series_schedules_stop" msgid="3427479298317584961">"Misa ukurekhodwa kochungechunge"</string>
+ <string name="dvr_series_schedules_stop_dialog_title" msgid="4975886236535334420">"Misa ukurekhodwa kochungechunge"</string>
+ <string name="dvr_series_schedules_stop_dialog_description" msgid="7547266283366940085">"Iziqephu ezirekhodiwe zizohlala zitholakala kulabhulali ye-DVR."</string>
+ <string name="dvr_series_schedules_stop_dialog_action_stop" msgid="2351839914865142478">"Misa"</string>
+ <string name="dvr_series_schedules_empty_state" msgid="3407962945399698707">"Azikho iziqephu ezitholakalayo.\nZizorekhodwa uma zitholakala."</string>
+ <plurals name="dvr_schedules_recording_duration" formatted="false" msgid="3701771573063918552">
+ <item quantity="one">(%1$d amaminithi)</item>
+ <item quantity="other">(%1$d amaminithi)</item>
+ </plurals>
+ <string name="dvr_date_today" msgid="7691050705354303471">"Namhlanje"</string>
+ <string name="dvr_date_tomorrow" msgid="4136735681186981844">"Kusasa"</string>
+ <string name="dvr_date_yesterday" msgid="2127672919053118239">"Izolo"</string>
+ <string name="dvr_date_today_time" msgid="8359696776305244535">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> namhlanje"</string>
+ <string name="dvr_date_tomorrow_time" msgid="8364654556105292594">"<xliff:g id="TIME_RANGE">%1$s</xliff:g> kusasa"</string>
+ <string name="program_guide_critic_score" msgid="340530743913585150">"Isikolo"</string>
</resources>
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index 856e5cc4..a6c8735b 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -26,30 +26,11 @@
<item>Zoom</item>
</string-array>
- <!-- The category strings to be displayed in the channel guide for LMP.
+ <!-- The category strings to be displayed in the channel guide.
This list should be synced the data in src/com/android/tv/data/GenreItems.java -->
<eat-comment />
- <!-- Genre list for LMP [CHAR LIMIT=20] -->
- <string-array name="genre_labels_l" translatable="true">
- <item>All channels</item>
- <item>Family/Kids</item>
- <item>Sports</item>
- <item>Shopping</item>
- <item>Movies</item>
- <item>Comedy</item>
- <item>Travel</item>
- <item>Drama</item>
- <item>Education</item>
- <item>Animal/Wildlife</item>
- <item>News</item>
- <item>Gaming</item>
- </string-array>
-
- <!-- The category strings to be displayed in the channel guide for LMP MR1.
- This list should be synced the data in src/com/android/tv/data/GenreItems.java -->
- <eat-comment />
- <!-- Genre list for LMP MR1 [CHAR LIMIT=20] -->
- <string-array name="genre_labels_l_mr1" translatable="true">
+ <!-- Genre list [CHAR LIMIT=20] -->
+ <string-array name="genre_labels" translatable="true">
<item>All channels</item>
<item>Family/Kids</item>
<item>Sports</item>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index cb0bd2df..b6b40563 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -38,6 +38,8 @@
<color name="play_controls_body_background_enabled">#0277BD</color>
<color name="play_controls_body_background_disabled">#800277BD</color>
<color name="play_controls_unavailable_message_text_color">#B3EEEEEE</color>
+ <color name="play_controls_icon_color">#FFEEEEEE</color>
+ <color name="play_controls_recording_icon_color_on_focus">#FFF44336</color>
<!-- Base card -->
<color name="card_meta_text_color_enabled">#EEEEEE</color>
@@ -101,6 +103,7 @@
<color name="program_guide_table_detail_episode_title_text_color">#B3EEEEEE</color>
<color name="program_guide_table_detail_title_grayed_text_color">#4CEEEEEE</color>
<color name="program_guide_table_detail_time_text_color">#B3EEEEEE</color>
+ <color name="program_guide_table_detail_dvr_text_color">#EEEEEE</color>
<color name="program_guide_table_detail_desc_text_color">#B3EEEEEE</color>
<color name="program_guide_time_indicator_color">#17FFFF</color>
@@ -139,5 +142,20 @@
<color name="setup_actions_background">#B30374BF</color>
<!-- Add alpha value to common_setup_done_container_background -->
<color name="setup_done_button_container_background">#8004549D</color>
+ <color name="setup_sub_actions_background">#4004549D</color>
<color name="setup_category">#3EC2FF</color>
+
+ <!-- DVR -->
+ <color name="dvr_card_info">#37474F</color>
+ <color name="dvr_card_episode_text_color">#B3EEEEEE</color>
+ <color name="dvr_schedules_item_main">#FFEEEEEE</color>
+ <color name="dvr_schedules_header_description">#4CEEEEEE</color>
+ <color name="dvr_schedules_item_info_grey">#4CFFFFFF</color>
+ <color name="dvr_schedules_item_info">#80EEEEEE</color>
+ <color name="dvr_schedules_item_background">#FF384248</color>
+ <color name="dvr_schedules_list_item_selector">#1AFFFFFF</color>
+ <color name="dvr_guided_step_action_text_color">#EEEEEE</color>
+ <color name="dvr_guided_step_action_text_color_selected">#111111</color>
+ <color name="dvr_detail_default_background">#FF01579B</color>
+ <color name="dvr_detail_default_background_scrim">#CC000000</color>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index bdd77774..ca601775 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -53,7 +53,8 @@
<dimen name="play_controls_button_background_height">90dp</dimen>
<dimen name="play_controls_button_width">90dp</dimen>
<dimen name="play_controls_button_height">64dp</dimen>
- <dimen name="play_controls_button_start_margin">6dp</dimen>
+ <dimen name="play_controls_button_normal_margin">3dp</dimen>
+ <dimen name="play_controls_button_compact_margin">-3dp</dimen>
<dimen name="play_controls_time_width">80dp</dimen>
<dimen name="play_controls_time_text_size">12sp</dimen>
<!-- The margin is different from the redlines due to the descenders.
@@ -195,6 +196,7 @@
<dimen name="program_guide_table_header_row_overlap">-52dp</dimen>
<dimen name="program_guide_table_item_row_height">64dp</dimen>
<dimen name="program_guide_table_item_padding">16dp</dimen>
+ <dimen name="program_guide_table_item_compound_drawable_padding">8dp</dimen>
<dimen name="program_guide_table_item_program_title_font_size">14sp</dimen>
<dimen name="program_guide_table_item_program_episode_title_font_size">12sp</dimen>
<dimen name="program_guide_table_item_visible_threshold">48dp</dimen>
@@ -213,8 +215,22 @@
<dimen name="program_guide_table_detail_episode_title_text_size">16sp</dimen>
<dimen name="program_guide_table_detail_time_margin_top">22dp</dimen>
<dimen name="program_guide_table_detail_time_text_size">12sp</dimen>
+ <dimen name="program_guide_table_detail_meta_margin_start">20dp</dimen>
+ <dimen name="program_guide_table_detail_meta_margin_bottom">2dp</dimen>
+ <dimen name="program_guide_table_detail_dvr_text_size">12sp</dimen>
+ <dimen name="program_guide_table_detail_dvr_margin_start">16dp</dimen>
+ <dimen name="program_guide_table_detail_dvr_margin_start_without_track">0dp</dimen>
+ <dimen name="program_guide_table_detail_dvr_icon_margin_top">0.5dp</dimen>
+ <dimen name="program_guide_table_detail_dvr_drawable_padding">4dp</dimen>
<dimen name="program_guide_table_detail_meta_margin_start">12dp</dimen>
<dimen name="program_guide_table_detail_meta_margin_bottom">4sp</dimen>
+ <dimen name="program_guide_table_detail_critic_scores_margin_start">6dp</dimen>
+ <dimen name="program_guide_table_detail_critic_score_margin_start">6dp</dimen>
+ <dimen name="program_guide_table_detail_critic_score_logo_dimen">10dp</dimen>
+ <dimen name="program_guide_table_detail_critic_score_logo_margin_start">6dp</dimen>
+ <dimen name="program_guide_table_detail_critic_score_score_margin_start">6dp</dimen>
+ <dimen name="program_guide_table_critic_score_source_text_size">12dp</dimen>
+ <dimen name="program_guide_table_critic_score_score_text_size">12dp</dimen>
<dimen name="program_guide_table_detail_desc_margin_top">46dp</dimen>
<dimen name="program_guide_table_detail_desc_text_size">12sp</dimen>
<dimen name="program_guide_table_width_per_hour">384dp</dimen>
@@ -225,6 +241,7 @@
<dimen name="tvview_block_icon_height">120dp</dimen>
<dimen name="tvview_block_vertical_spacing">15dp</dimen>
<dimen name="tvview_block_text_size">16sp</dimen>
+ <dimen name="tvview_block_line_spacing_extra">4sp</dimen>
<dimen name="shrunken_tvview_block_icon_width">60dp</dimen>
<dimen name="shrunken_tvview_block_icon_height">60dp</dimen>
<dimen name="shrunken_tvview_block_vertical_spacing">24dp</dimen>
@@ -271,6 +288,7 @@
<dimen name="channel_banner_track_meta_text_size">8sp</dimen>
<dimen name="channel_banner_enter_offset_y">16dp</dimen>
<dimen name="channel_banner_exit_offset_y">16dp</dimen>
+ <dimen name="channel_banner_recording_icon_padding">4sp</dimen>
<!-- Input banner -->
<dimen name="input_banner_item_height">48dp</dimen>
@@ -320,10 +338,69 @@
<!-- DVR screens -->
<eat-comment />
- <dimen name="dvr_card_layout_width">200dp</dimen>
- <dimen name="dvr_card_layout_height">200dp</dimen>
+ <dimen name="dvr_card_layout_width">196dp</dimen>
+
+ <!--DVR schedules list-->
+ <dimen name="dvr_schedules_layout_padding">132dp</dimen>
+ <dimen name="dvr_schedules_row_divider_height">1dp</dimen>
+ <dimen name="dvr_schedules_item_width">960dp</dimen>
+ <dimen name="dvr_schedules_header_selector_radius">2dp</dimen>
+ <dimen name="dvr_schedules_selector_radius">39dp</dimen>
+ <dimen name="dvr_schedules_item_time_width">219dp</dimen>
+ <dimen name="dvr_series_schedules_item_time_width">286dp</dimen>
+ <dimen name="dvr_schedules_item_time_start_padding">32dp</dimen>
+ <dimen name="dvr_schedules_item_time_margin">14dp</dimen>
+ <dimen name="dvr_schedules_item_info_top_margin">15dp</dimen>
+ <dimen name="dvr_schedules_item_conflict_info_top_margin">12dp</dimen>
+ <dimen name="dvr_schedules_item_conflict_info_bottom_margin">15dp</dimen>
+ <dimen name="dvr_schedules_item_schedule_width">56dp</dimen>
+ <dimen name="dvr_schedules_item_delete_width">46dp</dimen>
+ <dimen name="dvr_schedules_item_section_margin">32dp</dimen>
+ <dimen name="dvr_schedules_item_icon_size">18dp</dimen>
+ <dimen name="dvr_schedules_item_focus_translation_delta">2dp</dimen>
+ <dimen name="dvr_schedules_item_focus_width_delta">10dp</dimen>
+ <dimen name="dvr_schedules_header_margin_top">32dp</dimen>
+ <dimen name="dvr_schedules_header_margin_bottom">24dp</dimen>
+ <dimen name="dvr_schedules_header_subtitle_margin_top">5dp</dimen>
+ <dimen name="dvr_schedules_header_icon_container_width">143dp</dimen>
+ <dimen name="dvr_schedules_header_icon_size">32dp</dimen>
+ <dimen name="dvr_schedules_header_icon_horizontal_margin">12dp</dimen>
+ <dimen name="dvr_schedules_warning_icon_padding">4dp</dimen>
+
<!-- card width - margin-->
- <dimen name="dvr_card_image_layout_width">196dp</dimen>
- <dimen name="dvr_card_image_layout_height">140dp</dimen>
+ <dimen name="dvr_card_image_layout_width">192dp</dimen>
+ <dimen name="dvr_card_image_layout_height">108dp</dimen>
+ <dimen name="dvr_card_progress_height">2dp</dimen>
+
+ <!-- DVR playback fragment -->
+ <dimen name="dvr_related_recordings_width">146dp</dimen>
+ <dimen name="dvr_related_recordings_height">82dp</dimen>
+ <!-- This value is used to adjust position of DVR playback controls row when there is no
+ program description -->
+ <dimen name="dvr_playback_controls_extra_padding_top">27.5dp</dimen>
+ <!-- This value is used to adjust position of DVR playback overlay fragment when there is no
+ related recordings -->
+ <dimen name="dvr_playback_fragment_extra_padding_top">48dp</dimen>
+ <dimen name="lb_playback_controls_padding_top">265dp</dimen>
+ <dimen name="lb_playback_controls_padding_bottom">40dp</dimen>
+
+ <!-- details fragment -->
+ <dimen name="dvr_details_poster_width">219dp</dimen>
+ <dimen name="dvr_details_poster_height">123dp</dimen>
+ <item name="dvr_conflict_guidedstep_keyline" format="float" type="string">30.0</item>
+ <dimen name="dvr_deletion_check_mark_size">32dp</dimen>
+ <dimen name="dvr_deletion_check_mark_margin">20dp</dimen>
+ <dimen name="dvr_details_overview_description_margin_start">12dp</dimen>
+ <dimen name="dvr_details_overview_description_margin_end">12dp</dimen>
+ <!-- Below values are used to avoid detail titles' layout changing with two-line titles -->
+ <dimen name="dvr_details_description_title_resized_text_size">34sp</dimen>
+ <dimen name="dvr_details_description_title_padding_adjust_top">0dp</dimen>
+ <dimen name="dvr_details_description_title_padding_adjust_bottom">0dp</dimen>
+ <!-- DVR settings -->
+ <dimen name="dvr_settings_one_line_action_container_height">49dp</dimen>
+ <!-- actions list width = 352dp (fixed weight = 1)
+ button actions list width = 138dp (weight = 0.39) -->
+ <item name="dvr_settings_button_actions_list_width_weight" format="float" type="dimen">0.39</item>
+ <item name="dvr_settings_guidedactions_width_weight" format="float" type="string">1.15</item>
</resources>
diff --git a/res/values/google-services.xml b/res/values/google-services.xml
new file mode 100755
index 00000000..379a3453
--- /dev/null
+++ b/res/values/google-services.xml
@@ -0,0 +1,8 @@
+<?xml version='1.0' encoding='utf-8'?>
+<resources>
+ <string name="firebase_database_url" translatable="false">https://live-channels-1237.firebaseio.com</string>
+ <string name="gcm_defaultSenderId" translatable="false">399597460505</string>
+ <string name="google_api_key" translatable="false">AIzaSyDK2BtNulo2ltWIogD64y1hBWKrdg9Sa7k</string>
+ <string name="google_crash_reporting_api_key" translatable="false">AIzaSyDK2BtNulo2ltWIogD64y1hBWKrdg9Sa7k</string>
+ <string name="google_app_id" translatable="false">1:399597460505:android:6c699100869b1467</string>
+</resources>
diff --git a/res/values/integers.xml b/res/values/integers.xml
index 5aa59ffd..81ccbeb7 100644
--- a/res/values/integers.xml
+++ b/res/values/integers.xml
@@ -84,4 +84,7 @@
<integer name="half_sized_dialog_anim_duration">250</integer>
<integer name="half_sized_dialog_enter_offset_y">32</integer>
<integer name="half_sized_dialog_exit_offset_y">32</integer>
+
+ <!-- DVR library -->
+ <integer name="dvr_details_full_text_animation_duration">500</integer>
</resources>
diff --git a/res/values/rating_system_strings.xml b/res/values/rating_system_strings.xml
index 2441f96f..45c48d87 100644
--- a/res/values/rating_system_strings.xml
+++ b/res/values/rating_system_strings.xml
@@ -19,23 +19,23 @@
<!-- Age based TV content rating strings used in DVB and ISDB.
For more info, please see STD-B10 in http://www.dibeg.org/techp/aribstd/aribstd.html (ISDB)
and Table 81 of DVB SI (EN 300 468 V1.14.1) in https://www.dvb.org/standards (DVB).-->
- <string name="description_age_4" translatable="false">Recommended for ages 4 and over.</string>
- <string name="description_age_5" translatable="false">Recommended for ages 5 and over.</string>
- <string name="description_age_6" translatable="false">Recommended for ages 6 and over.</string>
- <string name="description_age_7" translatable="false">Recommended for ages 7 and over.</string>
- <string name="description_age_8" translatable="false">Recommended for ages 8 and over.</string>
- <string name="description_age_9" translatable="false">Recommended for ages 9 and over.</string>
- <string name="description_age_10" translatable="false">Recommended for ages 10 and over.</string>
- <string name="description_age_11" translatable="false">Recommended for ages 11 and over.</string>
- <string name="description_age_12" translatable="false">Recommended for ages 12 and over.</string>
- <string name="description_age_13" translatable="false">Recommended for ages 13 and over.</string>
- <string name="description_age_14" translatable="false">Recommended for ages 14 and over.</string>
- <string name="description_age_15" translatable="false">Recommended for ages 15 and over.</string>
- <string name="description_age_16" translatable="false">Recommended for ages 16 and over.</string>
- <string name="description_age_17" translatable="false">Recommended for ages 17 and over.</string>
- <string name="description_age_18" translatable="false">Recommended for ages 18 and over.</string>
- <string name="description_age_19" translatable="false">Recommended for ages 19 and over.</string>
- <string name="description_age_20" translatable="false">Recommended for ages 20 and over.</string>
+ <string name="description_age_4">Recommended for ages 4 and over.</string>
+ <string name="description_age_5">Recommended for ages 5 and over.</string>
+ <string name="description_age_6">Recommended for ages 6 and over.</string>
+ <string name="description_age_7">Recommended for ages 7 and over.</string>
+ <string name="description_age_8">Recommended for ages 8 and over.</string>
+ <string name="description_age_9">Recommended for ages 9 and over.</string>
+ <string name="description_age_10">Recommended for ages 10 and over.</string>
+ <string name="description_age_11">Recommended for ages 11 and over.</string>
+ <string name="description_age_12">Recommended for ages 12 and over.</string>
+ <string name="description_age_13">Recommended for ages 13 and over.</string>
+ <string name="description_age_14">Recommended for ages 14 and over.</string>
+ <string name="description_age_15">Recommended for ages 15 and over.</string>
+ <string name="description_age_16">Recommended for ages 16 and over.</string>
+ <string name="description_age_17">Recommended for ages 17 and over.</string>
+ <string name="description_age_18">Recommended for ages 18 and over.</string>
+ <string name="description_age_19">Recommended for ages 19 and over.</string>
+ <string name="description_age_20">Recommended for ages 20 and over.</string>
<!-- TV content rating system strings for AR TV. These strings are from Wikipedia.
See http://en.wikipedia.org/wiki/Television_content_rating_systems -->
@@ -78,13 +78,13 @@
<!-- TV content rating system strings for CA TV. These strings are from
http://www.cbsc.ca/english/agvot/englishsystem.php -->
- <string name="description_ca_tv_en_exempt" translatable="false">Exempt programming includes: news, sports, documentaries and other information programming; talk shows, music videos, and variety programming.</string>
- <string name="description_ca_tv_en_c" translatable="false">This programming is intended for younger children under the age of 8 years.</string>
- <string name="description_ca_tv_en_c8" translatable="false">This programming is intended for youngsters 8 years and over. It is suggested that a parent/guardian co-view programming assigned this classification with younger children under the age of 8.</string>
- <string name="description_ca_tv_en_g" translatable="false">This programming is intended for all age groups and appropriate viewing for the entire family.</string>
- <string name="description_ca_tv_en_pg" translatable="false">This programming, while intended for a general audience, may not be suitable for younger children (under the age of 8). Parents/guardians should be aware that there might be content elements which some could consider inappropriate for unsupervised viewing by children in the 8-13 age range.</string>
- <string name="description_ca_tv_en_14" translatable="false">Programming with this classification contains themes or content elements which might not be suitable for viewers under the age of 14. Parents are strongly cautioned to exercise discretion in permitting viewing by pre-teens and early teens without parent/guardian supervision, as programming with this classification could deal with mature themes and societal issues in a realistic fashion.</string>
- <string name="description_ca_tv_en_18" translatable="false">This programming is intended for viewers 18 years and older.</string>
+ <string name="description_ca_tv_en_exempt">Exempt programming includes: news, sports, documentaries and other information programming; talk shows, music videos, and variety programming.</string>
+ <string name="description_ca_tv_en_c">This programming is intended for younger children under the age of 8 years.</string>
+ <string name="description_ca_tv_en_c8">This programming is intended for youngsters 8 years and over. It is suggested that a parent/guardian co-view programming assigned this classification with younger children under the age of 8.</string>
+ <string name="description_ca_tv_en_g">This programming is intended for all age groups and appropriate viewing for the entire family.</string>
+ <string name="description_ca_tv_en_pg">This programming, while intended for a general audience, may not be suitable for younger children (under the age of 8). Parents/guardians should be aware that there might be content elements which some could consider inappropriate for unsupervised viewing by children in the 8-13 age range.</string>
+ <string name="description_ca_tv_en_14">Programming with this classification contains themes or content elements which might not be suitable for viewers under the age of 14. Parents are strongly cautioned to exercise discretion in permitting viewing by pre-teens and early teens without parent/guardian supervision, as programming with this classification could deal with mature themes and societal issues in a realistic fashion.</string>
+ <string name="description_ca_tv_en_18">This programming is intended for viewers 18 years and older.</string>
<!-- TV content rating system strings for CA TV (French). -->
<!-- A short title of the rating system that appears in the parentheses right next to the
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 224aa298..a58f2d36 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -91,9 +91,6 @@
<string name="channels_item_setup">New channels available</string>
<!-- Label of the app link card used for Google analytics. -->
<string name="channels_item_app_link" translatable="false">App link</string>
- <!-- Default label of the app link card indicating there is no app link available for
- the current channel. [CHAR LIMIT=23] -->
- <string name="channels_item_app_link_no_app_link">No link available</string>
<!-- Label of app link card for launching app in the channel list row. [CHAR LIMIT=NONE] -->
<string name="channels_item_app_link_app_launcher">Open <xliff:g id="app_name" example="YouTube">%1$s</xliff:g></string>
@@ -114,6 +111,8 @@
<string name="options_item_multi_audio">Multi-audio</string>
<!-- Label of "Get more channels" item in the TV option row. [CHAR LIMIT=17] -->
<string name="options_item_more_channels">Get more channels</string>
+ <!-- Label of "Developer Options" item in the TV option row. [CHAR LIMIT=17] -->
+ <string name="options_item_developer" translatable="false">Developer options</string>
<!-- Label of "Settings" item in the TV option row. [CHAR LIMIT=17] -->
<string name="options_item_settings">Settings</string>
@@ -347,6 +346,9 @@
<!-- Title of PIN dialog when an user is asked to enter PIN to unlock program.
[CHAR LIMIT=NONE] -->
<string name="pin_enter_unlock_program">Enter your PIN to watch this program</string>
+ <!-- Title of PIN dialog when an user is asked to enter PIN to unlock DVR playback.
+ [CHAR LIMIT=NONE] -->
+ <string name="pin_enter_unlock_dvr">This program is rated <xliff:g id="rating" example="TV_MA">%1$s</xliff:g>. Enter your PIN to watch this program</string>
<!-- Title of PIN dialog when an user tries to change Parental control setting.
[CHAR LIMIT=NONE] -->
<string name="pin_enter_pin">Enter your PIN</string>
@@ -395,12 +397,6 @@
<!-- opt out preferences -->
<eat-comment />
- <!--Title of option set to improve the Live TV app.
- "Live TV" should match app_name -->
- <string name="about_menu_improve">Help improve Live TV</string>
- <!--Summary of option to improve the Live TV app. -->
- <string name="about_menu_improve_summary">Share anonymous usage and diagnostics data with Google so we can make Live TV better and prevent issues like crashing and freezing.</string>
-
<!-- TunableTvView -->
<eat-comment />
<!-- Description on the locked screen when current channel is locked by parental control. [CHAR LIMIT=NONE] -->
@@ -429,6 +425,14 @@
<!-- The text message which is shown when the internet connection fails.
This message is shown at the center of the screen. [CHAR LIMIT=NONE] -->
<string name="tvview_msg_no_internet_connection">No internet connection</string>
+ <!-- The text message which is shown when the tune fails due to no available tuners.
+ This message is shown at the center of the screen. [CHAR LIMIT=NONE] -->
+ <plurals name="tvview_msg_input_no_resource">
+ <item quantity="one">This channel can\'t be played until <xliff:g id="end_time" example="9:30 PM">%1$s</xliff:g> because another channel is being recorded.
+\n\nPress Right to adjust recording schedule.</item>
+ <item quantity="other">This channel can\'t be played until <xliff:g id="end_time" example="9:30 PM">%1$s</xliff:g> because other channels are being recorded.
+\n\nPress Right to adjust recording schedule.</item>
+ </plurals>
<!-- Channel Banner -->
<eat-comment />
@@ -454,10 +458,10 @@
<string name="setup_input_new">New</string>
<!-- Description of an input which was installed but not setup yet. [CHAR LIMIT=40] -->
<string name="setup_input_setup_now">Not set up</string>
- <!-- Title for the link to the play store to get more channel sources. -->
- <string name="setup_play_store_action_title">Get more sources</string>
- <!-- Description for the link to the play store to get more channel sources. -->
- <string name="setup_play_store_action_description">Browse apps that offer live channels</string>
+ <!-- Title for the link to the online store to get more channel sources. -->
+ <string name="setup_store_action_title">Get more sources</string>
+ <!-- Description for the link to the online store to get more channel sources. -->
+ <string name="setup_store_action_description">Browse apps that offer live channels</string>
<!-- New Sources Fragment -->
<eat-comment />
@@ -507,17 +511,19 @@
<!-- Message to notify the different use of Back Button: Home Button(To exit) Back button
(commands for external device) [CHAR LIMIT=NONE] -->
<string name="msg_back_key_guide">BACK key is for connected device. Press HOME button to exit.</string>
- <!-- Error message when Live channels has been launched in Lollipop devices without system
- permission. [CHAR LIMIT=NONE] -->
- <string name="msg_not_supported_device">Live TV is not supported on this device with Android Lollipop.</string>
<!-- Error message when a user denied to grant READ_TV_LISTING permission. [CHAR LIMIT=NONE] -->
<string name="msg_read_tv_listing_permission_denied">Live TV needs permission to read the TV listings.</string>
<!-- Strings for debug or not to be shown to users -->
<eat-comment />
<!-- Debug Options -->
- <string name="menu_debug_options" translatable="false">Debug options</string>
- <string name="item_watch_history" translatable="false">Watch history</string>
+ <string name="menu_developer_options" translatable="false">Developer options</string>
+ <string name="dev_item_watch_history" translatable="false">Watch history</string>
+ <string name="dev_item_fetch_epg" translatable="false">Fetch program guide</string>
+ <string name="dev_item_send_feedback" translatable="false">Send feedback</string>
+ <string name="dev_item_store_ts_on" translatable="false">Store TS for debugging: On</string>
+ <string name="dev_item_store_ts_off" translatable="false">Store TS for debugging: Off</string>
+ <string name="dev_item_store_ts_description" translatable="false">Store some TS data before exceptions/crash for debugging.</string>
<!-- Title of Recently watched dialog. It is used for debug purpose. -->
<string name="recently_watched" translatable="false">Recently watched</string>
@@ -539,13 +545,9 @@
<!-- DVR TODO(DVR): make translatable true. -->
<eat-comment />
<!-- Dialog message to ask to remove the selected recording schedule. -->
- <string name="epg_dvr_dialog_message_remove_recording_schedule" translatable="false">Remove the scheduled recording?</string>
+ <string name="epg_dvr_dialog_message_remove_recording_schedule" translatable="false">Cancel recording</string>
<!-- Dialog message to ask to stop the current recording. -->
- <string name="epg_dvr_dialog_message_stop_recording" translatable="false">Stop the recording?</string>
- <!-- Dialog message to ask to schedule the recording of the selected program. -->
- <string name="epg_dvr_dialog_message_schedule_recording" translatable="false">Schedule the program recording?</string>
- <!-- Dialog message to ask to delecte the recorded program. -->
- <string name="epg_dvr_dialog_message_delete_schedule" translatable="false">Delete the recording schedule?</string>
+ <string name="epg_dvr_dialog_message_stop_recording" translatable="false">Stop recording</string>
<!-- Item label to schedule program recording. -->
<string name="epg_dvr_record_program" translatable="false">Record program</string>
<!-- Item label to schedule whole season recording of a TV show. -->
@@ -555,49 +557,421 @@
<string name="epg_dvr_delete_program" translatable="false">Delete schedule</string>
<!-- Menu item label to start DVR manager UI. -->
- <string name="channels_item_dvr" translatable="false">Recorded programs</string>
+ <string name="channels_item_dvr">Recordings &amp; schedules</string>
<!-- Menu item label to start recording of the current channel. -->
<string name="channels_item_record_start" translatable="false">Start recording</string>
<!-- Menu item label to start recording of the current channel. -->
<string name="channels_item_record_stop" translatable="false">Stop recording</string>
- <!-- Item of record start dialog item for 10 min recording. -->
- <string name="recording_start_dialog_10_min_duration" translatable="false">10 min.</string>
- <!-- Item of record start dialog item for 30 min recording. -->
- <string name="recording_start_dialog_30_min_duration" translatable="false">30 min.</string>
- <!-- Item of record start dialog item for 1 hour recording. -->
- <string name="recording_start_dialog_1_hour_duration" translatable="false">1 hour</string>
- <!-- Item of record start dialog item for 3 min recording. -->
- <string name="recording_start_dialog_3_hours_duration" translatable="false">3 hours</string>
- <!-- Item of record start dialog item until the end of the current program. -->
- <string name="recording_start_dialog_till_end_of_program" translatable="false">End of program</string>
+ <!-- The action to record the current channel for 10 minutes. [CHAR LIMIT=30] -->
+ <string name="recording_start_dialog_10_min_duration">10 minutes</string>
+ <!-- The action to record the current channel for 30 minutes. [CHAR LIMIT=30] -->
+ <string name="recording_start_dialog_30_min_duration">30 minutes</string>
+ <!-- The action to record the current channel for 1 hour. [CHAR LIMIT=30] -->
+ <string name="recording_start_dialog_1_hour_duration">1 hour</string>
+ <!-- The action to record the current channel for 3 hours. [CHAR LIMIT=30] -->
+ <string name="recording_start_dialog_3_hours_duration">3 hours</string>
<!--TODO(DVR): decide if translation needed Name of DVR service [CHAR LIMIT=NONE] -->
<string name="dvr_service_name" translatable="false">DVR Service</string>
<!-- DVR Menu strings. -->
<eat-comment />
- <string name="dvr_main_current_recordings" translatable="false">Current Recordings</string>
- <string name="dvr_main_scheduled_recordings" translatable="false">Scheduled Recordings</string>
- <string name="dvr_main_recorded_programs" translatable="false">Recorded Programs</string>
- <string name="dvr_main_settings" translatable="false">Settings</string>
+ <!-- Row label of lists of scheduled recording in DVR menu. -->
+ <!-- Header of DVR tab label for recently recorded programs list [CHAR LIMIT=20] -->
+ <string name="dvr_main_recent">Recent</string>
+ <!-- Header of DVR tab label for recording scheduled list [CHAR LIMIT=20] -->
+ <string name="dvr_main_scheduled">Scheduled</string>
+ <!-- Header of DVR tab label for recordings lists of TV series [CHAR LIMIT=20] -->
+ <string name="dvr_main_series">Series</string>
+ <!-- Header of DVR tab label for recorded programs list without any genre [CHAR LIMIT=20] -->
+ <string name="dvr_main_others">Others</string>
<string name="dvr_msg_no_recording_on_the_row" translatable="false">None</string>
- <string name="dvr_msg_program_title_unknown" translatable="false">Unknown</string>
<string name="dvr_msg_channel_unknown" translatable="false">Channel unknown</string>
+ <string name="dvr_msg_no_available_tuners_for_recording_channel" translatable="false">No available tuners to record this channel.</string>
+ <string name="dvr_msg_channel_already_recording" translatable="false">The channel is already being recorded.</string>
+ <!-- Toast message that the current channel cannot be recorded. -->
+ <string name="dvr_msg_cannot_record_channel">The channel cannot be recorded.</string>
+ <!-- Toast message that the current program cannot be recorded. -->
+ <string name="dvr_msg_cannot_record_program">The program cannot be recorded.</string>
+ <string name="dvr_msg_no_item_in_browse" translatable="false">There is no item.</string>
+ <!-- Toast message that a new recording schedule has been created from the user action. -->
+ <string name="dvr_msg_program_scheduled"><xliff:g id="programName" example="Big bang theory">%1$s</xliff:g> has been scheduled to be recorded</string>
+ <!-- Toast message that a new recording schedule of the current program has been created
+ from the user action. -->
+ <string name="dvr_msg_current_program_scheduled">Recording <xliff:g id="programName" example="Big bang theory">%1$s</xliff:g> from now to <xliff:g id="endTime" example="12:30 PM">%2$s</xliff:g></string>
+ <!-- Description of a card view to show full list of scheduled recordings. [CHAR LIMIT=25] -->
+ <string name="dvr_full_schedule_card_view_title">Full schedule</string>
+ <!-- Description of how many following days the schedule list will show. [CHAR LIMIT=25] -->
+ <plurals name="dvr_full_schedule_card_view_content">
+ <item quantity="one">Next %1$d day</item>
+ <item quantity="other">Next %1$d days</item>
+ </plurals>
+ <!-- Description of recording card views for recorded programs' length. [CHAR LIMIT=15] -->
+ <plurals name="dvr_program_duration">
+ <item quantity="one">%1$d minute</item>
+ <item quantity="other">%1$d minutes</item>
+ </plurals>
+ <!-- Description of recording card views for number of new recorded programs [CHAR LIMIT=32] -->
+ <plurals name="dvr_count_new_recordings">
+ <item quantity="one">%1$d new recording</item>
+ <item quantity="other">%1$d new recordings</item>
+ </plurals>
+ <!-- Description of recording card views for number of recorded programs [CHAR LIMIT=32] -->
+ <plurals name="dvr_count_recordings">
+ <item quantity="one">%1$d recording</item>
+ <item quantity="other">%1$d recordings</item>
+ </plurals>
+ <!-- Description of recording card views for number of scheduled recordings [CHAR LIMIT=32] -->
+ <plurals name="dvr_count_scheduled_recordings">
+ <item quantity="one">%1$d recording scheduled</item>
+ <item quantity="other">%1$d recordings scheduled</item>
+ </plurals>
+
<!-- DVR detailed page -->
<eat-comment />
<string name="dvr_detail_cancel" translatable="false">Cancel recording</string>
<string name="dvr_detail_stop_keep" translatable="false">Stop and keep recording</string>
<string name="dvr_detail_stop_delete" translatable="false">Stop and delete recording</string>
- <string name="dvr_detail_play" translatable="false">Play recording</string>
- <string name="dvr_detail_delete" translatable="false">Delete recording</string>
+ <!-- Button label to play recorded programs from beginning.
+ Displayed when there's no watched history available. [CHAR LIMIT=15] -->
+ <string name="dvr_detail_watch">Watch</string>
+ <!-- Button label to play recorded programs from beginning. [CHAR LIMIT=25] -->
+ <string name="dvr_detail_play_from_beginning">Play from beginning</string>
+ <!-- Button label to play recorded programs from last watched position. [CHAR LIMIT=20] -->
+ <string name="dvr_detail_resume_play">Resume playing</string>
+ <!-- Button label to remove a recorded program in a recording details page [CHAR LIMIT=20] -->
+ <string name="dvr_detail_delete">Delete</string>
+ <!-- Button label to remove a recorded program in a series recording details page
+ [CHAR LIMIT=30] -->
+ <string name="dvr_detail_series_delete">Delete recordings</string>
+ <!-- Button label to resume playback of a recorded program [CHAR LIMIT=20] -->
+ <string name="dvr_detail_series_resume">Resume</string>
+ <!-- Row label to show the season number of series recordings [CHAR LIMIT=20] -->
+ <string name="dvr_detail_series_season_title">Season <xliff:g id="season_number">%1$s</xliff:g></string>
+ <!-- Button label to open full schedule list page [CHAR LIMIT=15] -->
+ <string name="dvr_detail_view_schedule">View schedule</string>
+ <!-- Text label to indicate there's more text in the details description [CHAR LIMIT=20] -->
+ <string name="dvr_detail_read_more">Read more</string>
+
+ <!-- DVR series settings -->
+ <eat-comment />
+ <!-- Title of DVR series deletion [CHAR LIMIT=25] -->
+ <string name="dvr_series_deletion_title">Delete recordings</string>
+ <!-- Description of DVR series deletion. -->
+ <string name="dvr_series_deletion_description">Select the episodes you would like to delete. They can\'t be recovered once deleted.</string>
+ <!-- Toast message of no recordings can be deleted [CHAR LIMIT=40] -->
+ <string name="dvr_series_deletion_no_recordings">There\'re no recordings to delete.</string>
+ <!-- Button label to select all watched episodes of the given series [CHAR LIMIT=35] -->
+ <string name="dvr_series_select_watched">Select watched episodes</string>
+ <!-- Button label to select all episodes of the given series [CHAR LIMIT=35] -->
+ <string name="dvr_series_select_all">Select all episodes</string>
+ <!-- Button label to deselect all episodes of the given series [CHAR LIMIT=35] -->
+ <string name="dvr_series_deselect_all">Deselect all episodes</string>
+ <!-- Description of recording's watched position in minutes. -->
+ <string name="dvr_series_watched_info_minutes"><xliff:g id="watched">%1$d</xliff:g> of <xliff:g id="duration">%2$d</xliff:g> minutes watched</string>
+ <!-- Description of recording's watched position in seconds. -->
+ <string name="dvr_series_watched_info_seconds"><xliff:g id="watched">%1$d</xliff:g> of <xliff:g id="duration">%2$d</xliff:g> seconds watched</string>
+ <!-- Description of never watched recordings [CHAR LIMIT=25] -->
+ <string name="dvr_series_never_watched">Never watched</string>
+ <!-- Message after recorded episodes are deleted. -->
+ <plurals name="dvr_msg_episodes_deleted">
+ <item quantity="one">%1$d of %2$d episode is deleted</item>
+ <item quantity="other">%1$d of %2$d episodes are deleted</item>
+ </plurals>
+ <!-- Title of DVR series settings -->
+ <string name="dvr_series_settings_title" translatable="false">Recording settings</string>
+ <!-- Item label to change priority of TV series for DVR -->
+ <string name="dvr_series_settings_priority">Priority</string>
+ <!-- Item description when the current series has the height proirty among scheduled
+ TV series. -->
+ <string name="dvr_series_settings_priority_highest">Highest</string>
+ <!-- Item description when the current series has the lowest proirty among scheduled
+ TV series. -->
+ <string name="dvr_series_settings_priority_lowest">Lowest</string>
+ <!-- Item description of the priority rank of the current series among all scheduled
+ TV series. -->
+ <string name="dvr_series_settings_priority_rank">No. <xliff:g id="rank">%1$d</xliff:g></string>
+ <!-- Item label to specify channel which will be recorded for TV series recording -->
+ <string name="dvr_series_settings_channels">Channels</string>
+ <!-- Sub item label to record TV series from any channel. c.f., a user can
+ specify a channel like CNN -->
+ <string name="dvr_series_settings_channels_all">Any</string>
+ <!-- Title of priority settings fragment -->
+ <string name="dvr_priority_title">Choose priority</string>
+ <!-- Description of priority settings fragment -->
+ <string name="dvr_priority_description">When there are too many programs to be recorded at the same time, only the ones with higher priorities will be recorded.</string>
+ <!-- Button lable in priority settings fragment to save the current settings -->
+ <string name="dvr_priority_button_action_save">Save</string>
+ <!-- Button label in priority settings fragment for one-time recordings -->
+ <string name="dvr_priority_action_one_time_recording">One-time recordings have the highest priority</string>
<!-- DVR epg strings -->
<eat-comment />
- <string name="dvr_epg_record" translatable="false">Record</string>
- <string name="dvr_epg_do_not_record" translatable="false">Do not record</string>
- <string name="dvr_epg_conflict_dialog_title" translatable="false">Recording this program will
- prevent the recording of the following programs:</string>
+ <string name="dvr_action_tune" translatable="false">Tune</string>
+ <!-- The action to cancel and close the dialog. [CHAR LIMIT=10] -->
+ <string name="dvr_action_cancel">Cancel</string>
+ <string name="dvr_action_delete_schedule" translatable="false">Delete schedule</string>
+ <string name="dvr_action_record_program" translatable="false">Record program</string>
+ <string name="dvr_action_record_one_episode" translatable="false">Record this episode only</string>
+ <string name="dvr_action_error_done" translatable="false">Done</string>
+ <string name="dvr_action_error_open_dvr" translatable="false">Open DVR</string>
+ <!-- The action to cancel forgetting DVR storage. -->
+ <string name="dvr_action_error_cancel">Cancel</string>
+ <!-- The action to forget DVR storage which is missing currently -->
+ <string name="dvr_action_error_forget_storage">Forget</string>
+ <!-- The action to stop recording. [CHAR LIMIT=10] -->
+ <string name="dvr_action_stop">Stop</string>
+ <!-- The action to open the activity which shows all the schedules.[CHAR LIMIT=32] -->
+ <string name="dvr_action_view_schedules">View recording schedule</string>
+ <!-- The action to make the recording schedule for only this program(episode).
+ [CHAR LIMIT=30] -->
+ <string name="dvr_action_record_episode">This single program</string>
+ <!-- The description for the action "dvr_action_record_episode" to show the recording duration
+ which starts now and ends at the end of the program.
+ [CHAR LIMIT=30] -->
+ <string name="dvr_action_record_episode_from_now_description">now - <xliff:g id="endTime" example="11:30">%1$s</xliff:g></string>
+ <!-- The action to make the recording schedule for the series (i.e. all the episodes). The
+ ellipsis(&#8230) means that there will be a next setup page for the series recording.
+ [CHAR LIMIT=30] -->
+ <string name="dvr_action_record_series">Entire series&#8230;</string>
+ <!-- The title of the action to create a schedule for the program even though there are some
+ problems. [CHAR LIMIT=32] -->
+ <string name="dvr_action_record_anyway">Schedule anyway</string>
+ <!-- The title of the action to record this program instead of the other. This happens when the
+ user tries to record a program while there is a existing schedule with the same episode
+ as the program. [CHAR LIMIT=35] -->
+ <string name="dvr_action_record_instead">Record this one instead</string>
+ <!-- The title of the action to cancel to create the new schedule. This happens when the user
+ created a schedule while there is a existing schedule with the same episode as the program.
+ This action cancels the new schedule. [CHAR LIMIT=32] -->
+ <string name="dvr_action_record_cancel">Cancel this recording</string>
+ <!-- The title of the action to show the details of the recorded program. [CHAR LIMIT=32] -->
+ <string name="dvr_action_watch_now">Watch now</string>
+ <!-- Dvr label in epg to indicate the program is recordable. [CHAR LIMIT=30] -->
+ <string name="dvr_epg_program_recordable">Recordable</string>
+ <!-- Dvr label in epg to indicate the program is scheduled to be recorded. [CHAR LIMIT=30] -->
+ <string name="dvr_epg_program_recording_scheduled">Recording scheduled</string>
+ <!-- Dvr label in epg to indicate the program has a conflicted scheduled recording. [CHAR LIMIT=30] -->
+ <string name="dvr_epg_program_recording_conflict">Recording conflict</string>
+ <!-- Dvr label in epg to indicate the program is recording now. [CHAR LIMIT=30] -->
+ <string name="dvr_epg_program_recording_in_progress">Recording</string>
+ <!-- Dvr label in epg to indicate the recording of the program has been failed. [CHAR LIMIT=30] -->
+ <string name="dvr_epg_program_recording_failed">Recording failed</string>
+ <string name="dvr_epg_program_icon_text" translatable="false">DVR</string>
+ <string name="dvr_epg_channel_watch_conflict_dialog_title" translatable="false">Upcoming schedules</string>
+ <string name="dvr_epg_channel_watch_conflict_dialog_description" translatable="false">The programs will not be recorded if you keep watching this channel. Cancel the recordings, or current channel will be blocked when the recording starts.</string>
+ <!-- A popup message which informs that Live TV is reading program information to create
+ recording schedules. -->
+ <string name="dvr_schedule_progress_message_reading_programs">Reading programs to create recording schedules</string>
+ <!-- A popup message which informs that Live TV is reading program information. -->
+ <string name="dvr_series_schedules_progress_message_reading_programs">Reading programs</string>
+ <!-- A popup message which informs that Live TV is updating series recording. -->
+ <string name="dvr_series_schedules_progress_message_updating_programs">Updating series recording</string>
+ <string name="dvr_error_insufficient_space_title" translatable="false">Insufficient storage space</string>
+ <string name="dvr_error_insufficient_space_description" translatable="false">No sufficient storage space for recording. Please clean up the storage.</string>
+ <!-- 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 tthe 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$s</xliff:g>GB or larger and follow the steps to format it as device storage.</string>
+ <!-- Dialog title which will be shown when the current DVR storage is not accessible. -->
+ <string name="dvr_error_missing_storage_title">Missing storage</string>
+ <!-- Dialog description which will be shown when the current DVR storage is not accessible. -->
+ <string name="dvr_error_missing_storage_description">Some of the storage used by DVR is missing. Please connect the external drive you used before to re-enable DVR. Alternately, you can choose to forget the storage if it\'s no longer available.</string>
+ <!-- Dialog title which will be shown when you confirmed to forget the current DVR storage. -->
+ <string name="dvr_error_forget_storage_title">Forget storage?</string>
+ <!-- Dialog description which will be shown when you confirmed to forget the current DVR
+ storage. -->
+ <string name="dvr_error_forget_storage_description">All your recorded content and schedules will be lost.</string>
+ <!-- The recording being requested to play is not existent in storage. It may be deleted. -->
+ <string name="dvr_toast_recording_deleted" translatable="false">The recording seems to be deleted.</string>
+
+ <!-- DVR half sized dialogs -->
+ <eat-comment />
+ <!-- The title of the stop recording dialog which asks the user whether to stop recording of the
+ current channel or not. -->
+ <string name="dvr_stop_recording_dialog_title">Stop recording?</string>
+ <!-- The description of the stop recording dialog which asks the user whether to stop recording
+ of the current channel or not. -->
+ <string name="dvr_stop_recording_dialog_description">The recorded content will be saved.</string>
+ <!-- The description of the stop recording dialog which asks the user whether to stop the
+ current recording to start another conflict schedule. -->
+ <string name="dvr_stop_recording_dialog_description_on_conflict">The recording of <xliff:g id="programName" example="Friends">%1$s</xliff:g> will be stopped because it conflicts with this program. The recorded content will be saved.</string>
+ <!--The title of the dialog to notify the user that the new schedule conflicts with others. -->
+ <string name="dvr_program_conflict_dialog_title">Recording scheduled but has conflicts</string>
+ <!--The title of the dialog to notify the user that the recording of the current channel
+ conflicts with other schedules. -->
+ <string name="dvr_channel_conflict_dialog_title">Recording has started but has conflicts</string>
+ <!-- The message which says that the new recording schedule has been created. -->
+ <string name="dvr_program_conflict_dialog_description_prefix"><xliff:g id="programName" example="Friends">%1$s</xliff:g> will be recorded.</string>
+ <!-- The message which says that the recording of the current channel has been started. -->
+ <string name="dvr_channel_conflict_dialog_description_prefix"><xliff:g id="channelName" example="KQED">%1$s</xliff:g> is being recorded.</string>
+ <!--The description of the dialog to notify the user that the new recording schedule conflicts
+ with another schedule. In this case the old schedule will be clipped or not be recorded.
+ "Clipped" means that only a part of the program is recorded. -->
+ <string name="dvr_program_conflict_dialog_description_1">Some parts of <xliff:g id="conflictProgramName" example="Friends">%1$s</xliff:g> will not be recorded.</string>
+ <!--The description of the dialog to notify the user that the new recording schedule conflicts
+ with two other schedule. In this case the old schedule will be clipped or not be recorded.
+ "Clipped" means that only a part of the program is recorded. -->
+ <string name="dvr_program_conflict_dialog_description_2">Some parts of <xliff:g id="conflictProgramName_1" example="Friends">%1$s</xliff:g> and <xliff:g id="conflictProgramName_2" example="Friends">%2$s</xliff:g> will not be recorded.</string>
+ <!--The description of the dialog to notify the user that the new recording schedule conflicts
+ with another schedules. In this case the old schedule will be clipped or not be recorded.
+ "Clipped" means that only a part of the program is recorded. -->
+ <string name="dvr_program_conflict_dialog_description_3">Some parts of <xliff:g id="conflictProgramName_1" example="Friends">%1$s</xliff:g>, <xliff:g id="conflictProgramName_2" example="Friends">%2$s</xliff:g> and one more schedule will not be recorded.</string>
+ <!--The description of the dialog to notify the user that the new recording schedule conflicts
+ with more than two schedules. In this case the old schedule will be clipped or not be
+ recorded. "Clipped" means that only a part of the program is recorded. Note that this string
+ is used only when the quantity is greater than one. -->
+ <plurals name="dvr_program_conflict_dialog_description_many">
+ <item quantity="one">Some parts of <xliff:g id="conflictProgramName_1" example="Friends">%1$s</xliff:g>, <xliff:g id="conflictProgramName_2" example="Friends">%2$s</xliff:g> and %3$d more schedule will not be recorded.</item>
+ <item quantity="other">Some parts of <xliff:g id="conflictProgramName_1" example="Friends">%1$s</xliff:g>, <xliff:g id="conflictProgramName_2" example="Friends">%2$s</xliff:g> and %3$d more schedules will not be recorded.</item>
+ </plurals>
+ <!-- The title of the DVR schedule dialog which asks the user whether he/she want to make the
+ one-time recording or series recording. -->
+ <string name="dvr_schedule_dialog_title">What would you like to record?</string>
+ <!-- The title of the DVR channel recording dialog which asks the user how long he/she wants
+ record the current channel. -->
+ <string name="dvr_channel_record_duration_dialog_title">How long would you like to record?</string>
+ <!-- The title of the dialog which notifies the user that a schedule which is the same episode
+ as this program has already been created. -->
+ <string name="dvr_already_scheduled_dialog_title">Already scheduled</string>
+ <!-- The description of the dialog which notifies the user that a schedule which is the same
+ episode as this program has already been created. -->
+ <string name="dvr_already_scheduled_dialog_description">The same program has already been scheduled to be recorded at <xliff:g id="programStartTime" example="7:30 AM on Jun 27.">%1$s</xliff:g>.</string>
+ <!-- The title of the dialog which notifies the user that the same episode as the program has
+ already been recorded. -->
+ <string name="dvr_already_recorded_dialog_title">Already recorded</string>
+ <!-- The description of the dialog which notifies the user that the same episode as the program
+ has already been recorded. -->
+ <string name="dvr_already_recorded_dialog_description">This program has already been recorded. It’s available in the DVR library.</string>
+ <!-- The title of dialog that notifies the user the series recording has been scheduled. -->
+ <string name="dvr_series_recording_dialog_title">Series recording scheduled</string>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording.-->
+ <plurals name="dvr_series_recording_scheduled_no_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s.</item>
+ </plurals>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording. But some of them won't be recorded due to conflicts. -->
+ <plurals name="dvr_series_recording_scheduled_only_this_series_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s. %3$d of them will not be recorded due to conflicts.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s. %3$d of them will not be recorded due to conflicts.</item>
+ </plurals>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording. But only 1 episode of other series won't be recorded due to conflict
+ with this series. -->
+ <plurals name="dvr_series_recording_scheduled_this_and_other_series_one_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s. 1 episode of this series and other series will not be recorded due to conflicts.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s. 1 episode of this series and other series will not be recorded due to conflicts.</item>
+ </plurals>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording. But some episodes of other series won't be recorded due to conflict
+ with this. -->
+ <plurals name="dvr_series_recording_scheduled_this_and_other_series_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s. %3$d episodes of this series and other series will not be recorded due to conflicts.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s. %3$d episodes of this series and other series will not be recorded due to conflicts.</item>
+ </plurals>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording. But only 1 episode of other series won't be recorded due to conflict
+ with this series but no conflicts in this series. -->
+ <plurals name="dvr_series_recording_scheduled_only_other_series_one_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s. 1 episode of other series will not be recorded due to conflicts.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s. 1 episode of other series will not be recorded due to conflicts.</item>
+ </plurals>
+ <!-- The description of the dialog which notifies how many schedules has been added
+ for series recording. But some of other series won't be recorded due to conflict with this
+ series but no conflicts in this series . -->
+ <plurals name="dvr_series_recording_scheduled_only_other_series_conflict">
+ <item quantity="one">%1$d recording has been scheduled for %2$s. %3$d episodes of other series will not be recorded due to conflicts.</item>
+ <item quantity="other">%1$d recordings have been scheduled for %2$s. %3$d episodes of other series will not be recorded due to conflicts.</item>
+ </plurals>
+
+ <!-- DVR playback strings -->
+ <eat-comment />
+ <string name="dvr_now_playing_card_no_title" translatable="false">Recorded Program</string>
+ <!-- DVR playback activity's warning about the recorded program is not found. -->
+ <string name="dvr_program_not_found">Recorded program not found.</string>
+ <!-- Label used in DVR playback activity as the header of the row of related recordings. [CHAR LIMIT=32] -->
+ <string name="dvr_playback_related_recordings">Related recordings</string>
+ <!-- Label used in related recording cards to indicate that the program does not have descriptions. [CHAR LIMIT=32] -->
+ <string name="dvr_msg_no_program_description">(No program description)</string>
+
+ <!-- DVR channel banner strings -->
+ <eat-comment />
+ <string name="dvr_recording_till_format" translatable="false">Recording till <xliff:g id="recordingEndTime" example="9:00pm">%1$s</xliff:g></string>
+
+ <!-- Account Selection strings -->
+ <eat-comment />
+ <string name="account_selected" translatable="false">%1$s is the selected account</string>
+ <string name="no_account_selected" translatable="false">No account available</string>
+
+ <!-- DVR schedule list strings -->
+ <eat-comment/>
+ <!-- Description of list's header about how many recordings in the recording list. -->
+ <plurals name="dvr_schedules_section_subtitle">
+ <item quantity="one">%1$d recording</item>
+ <item quantity="other">%1$d recordings</item>
+ </plurals>
+ <!-- Separator between program name and channel name. -->
+ <string name="dvr_schedules_information_separator">&#160;/&#160;</string>
+ <!-- Description of which recording has been removed. -->
+ <string name="dvr_schedules_deletion_info"><xliff:g id="programName" example="Big bang theory">%1$s</xliff:g> removed from recording schedule</string>
+ <!-- Description of the schedule will be partially recorded, because of no available tuner
+ for recording. [CHAR LIMIT=60] -->
+ <string name="dvr_schedules_tuner_conflict_will_be_partially_recorded">Will be partially recorded due to tuner conflicts.</string>
+ <!-- Description of the schedule will not be recorded, because of no available tuner for
+ recording. [CHAR LIMIT=60] -->
+ <string name="dvr_schedules_tuner_conflict_will_not_be_recorded_info">Won\'t be recorded due to tuner conflicts.</string>
+ <!-- Description of no schedule recording for now, and ask user to schedule recordings from
+ the program guide. -->
+ <string name="dvr_schedules_empty_state">There are no recordings on schedule yet.\nYou can schedule recording from the program guide.</string>
+ <!-- Description of schedule list header about how many recordings conflict. -->
+ <plurals name="dvr_series_schedules_header_description">
+ <item quantity="one">%1$d recording conflict</item>
+ <item quantity="other">%1$d recording conflicts</item>
+ </plurals>
+ <!-- Button label of settings for DVR series recordings [CHAR LIMIT=25] -->
+ <string name="dvr_series_schedules_settings">Series settings</string>
+ <!-- Button label of the action which starts creating schedules for the series automatically.[CHAR LIMIT=32] -->
+ <string name="dvr_series_schedules_start">Start series recording</string>
+ <!-- Button label of the action which stops creating schedules for the series automatically. [CHAR LIMIT=32]-->
+ <string name="dvr_series_schedules_stop">Stop series recording</string>
+ <!-- The title of asking user whether to stop creating schedules. -->
+ <string name="dvr_series_schedules_stop_dialog_title">Stop series recording?</string>
+ <!-- The description of asking user whether to stop creating schedules for the series. -->
+ <string name="dvr_series_schedules_stop_dialog_description">Recorded episodes will remain available in the DVR library.</string>
+ <!-- Action to stop creating the schedules for the series. -->
+ <string name="dvr_series_schedules_stop_dialog_action_stop">Stop</string>
+ <!-- Description of no episodes in series recording, and the episodes will be recorded once
+ they are available. -->
+ <string name="dvr_series_schedules_empty_state">No episodes are available.\nThey will be recorded once they are available.</string>
+ <!-- Tag of schedules header focus view. -->
+ <string name="dvr_schedules_header_focus_view" translatable="false">DvrSchedulesHeaderFocusView</string>
+ <!-- Tag of schedules item focus view. -->
+ <string name="dvr_schedules_item_focus_view" translatable="false">DvrSchedulesItemFocusView</string>
+ <!-- Description of recordings' duration in minutes. [CHAR LIMIT=25] -->
+ <plurals name="dvr_schedules_recording_duration">
+ <item quantity="one">(%1$d minute) </item>
+ <item quantity="other">(%1$d minutes)</item>
+ </plurals>
+ <!-- DVR date related strings -->
+ <eat-comment/>
+ <!-- Date text to represent today. -->
+ <string name="dvr_date_today">Today</string>
+ <!-- Date text to represent tomorrow. -->
+ <string name="dvr_date_tomorrow">Tomorrow</string>
+ <!-- Date text to represent yesterday. -->
+ <string name="dvr_date_yesterday">Yesterday</string>
+ <!-- Date text to represent time with today like 8 - 9 AM today -->
+ <string name="dvr_date_today_time"><xliff:g id="time_range" example="10:00 am - 11:00 am">%1$s</xliff:g> today</string>
+ <!-- Date text to represent time with today like 8 - 9 AM tomorrow -->
+ <string name="dvr_date_tomorrow_time"><xliff:g id="time_range" example="10:00 am - 11:00 am">%1$s</xliff:g> tomorrow</string>
+
+ <!-- Program Guide Strings -->
+ <eat-comment/>
+ <!-- Text that goes after a Critic Score to indicate that it's a score -->
+ <string name="program_guide_critic_score">Score</string>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 82a5258e..3a34af52 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -16,10 +16,10 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="channel_banner_track_meta_text">
+ <style name="track_meta_text">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">12dp</item>
- <item name="android:layout_marginEnd">8dp</item>
+ <item name="android:layout_marginEnd">4dp</item>
<item name="android:gravity">center</item>
<item name="android:paddingStart">4dp</item>
<item name="android:paddingEnd">4dp</item>
@@ -31,6 +31,10 @@
<item name="android:background">@drawable/track_meta_border</item>
</style>
+ <style name="track_meta_text.channel_banner">
+ <item name="android:layout_marginEnd">8dp</item>
+ </style>
+
<style name="pin_dialog_animation" parent="@android:style/Animation.Activity">
<item name="android:windowEnterAnimation">@anim/pin_dialog_enter</item>
<item name="android:windowExitAnimation">@anim/pin_dialog_exit</item>
@@ -40,6 +44,10 @@
<item name="android:textColor">@color/channel_banner_episode_text_color</item>
</style>
+ <style name="text_appearance_card_view_episode_number">
+ <item name="android:textColor">@color/dvr_card_episode_text_color</item>
+ </style>
+
<style name="pin_number_view">
<item name="android:layout_width">@dimen/pin_number_picker_text_view_width</item>
<item name="android:layout_height">@dimen/pin_number_picker_text_view_height</item>
@@ -80,6 +88,19 @@
<item name="android:paddingTop">@dimen/menu_row_contents_padding_top</item>
</style>
+ <style name="dvr_card_view_title_text">
+ <item name="android:textSize">14sp</item>
+ <item name="android:textColor">@color/lb_basic_card_title_text_color</item>
+ <item name="android:fontFamily">sans-serif-condensed</item>
+ <item name="android:singleLine">true</item>
+ <item name="android:ellipsize">end</item>
+ </style>
+
+ <style name="dvr_card_view_content_text" parent="dvr_card_view_title_text">
+ <item name="android:textSize">12sp</item>
+ <item name="android:textColor">@color/lb_basic_card_content_text_color</item>
+ </style>
+
<style name="Animation.SelectInputActivity" parent="android:Animation.Activity">
<item name="android:windowEnterAnimation">@anim/select_input_activity_enter</item>
<item name="android:windowExitAnimation">@anim/select_input_activity_exit</item>
@@ -95,28 +116,84 @@
</style>
<style name="TV.Dvr.GuidanceTitleStyle" parent="Widget.Setup.GuidanceTitleStyle">
+ <item name="android:layout_alignParentStart">false</item>
<item name="android:layout_toStartOf">@null</item>
- <item name="android:layout_alignParentTop">true</item>
- <item name="android:layout_marginTop">55dp</item>
+ <item name="android:layout_marginTop">0dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:textSize">34sp</item>
<item name="android:fontFamily">@string/light_font</item>
<item name="android:gravity">start</item>
</style>
+ <style name="TV.Dvr.GuidanceBreadcrumbStyle" parent="Widget.Setup.GuidanceBreadcrumbStyle">
+ <item name="android:layout_marginTop">55dp</item>
+ </style>
+
<style name="TV.Dvr.GuidanceDescriptionStyle" parent="Widget.Setup.GuidanceDescriptionStyle">
+ <item name="android:layout_alignParentStart">false</item>
<item name="android:layout_width">match_parent</item>
<item name="android:fontFamily">@string/light_font</item>
<item name="android:textColor">#ADEEEEEE</item>
<item name="android:gravity">start</item>
</style>
+ <!-- Style for the icon view in a half sized dialog. -->
+ <style name="TV.Dvr.GuidanceIconStyle" parent="Widget.Leanback.GuidanceIconStyle">
+ <item name="android:layout_width">60dp</item>
+ <item name="android:layout_height">60dp</item>
+ </style>
+
<style name="TV.Dvr.GuidedActionsListStyle" parent="Widget.Setup.GuidedActionsListStyle">
<item name="android:layout_marginTop">51dp</item>
+ <item name="android:layout_marginBottom">10dp</item>
+ <item name="android:layout_marginEnd">56dp</item>
</style>
<style name="TV.Dvr.GuidedActionItemContainerStyle" parent="Widget.Setup.GuidedActionItemContainerStyle">
- <item name="android:layout_height">45dp</item>
+ <item name="android:layout_height">48dp</item>
<item name="android:layout_marginTop">7dp</item>
+ <item name="android:paddingBottom">15dp</item>
+ <item name="android:paddingEnd">16dp</item>
+ <item name="android:paddingStart">16dp</item>
+ <item name="android:paddingTop">14dp</item>
+ </style>
+
+ <style name="TV.Dvr.GuidedActionItemContainerStyle.Twoline.Action" parent="TV.Dvr.GuidedActionItemContainerStyle">
+ <item name="android:layout_height">64dp</item>
+ </style>
+
+ <style name="TV.Dvr.Conflict.GuidanceTitleStyle" parent="TV.Dvr.GuidanceTitleStyle">
+ <item name="android:textSize">28sp</item>
+ </style>
+
+ <style name="TV.Dvr.Conflict.GuidedActionsListStyle" parent="TV.Dvr.GuidedActionsListStyle">
+ <item name="android:layout_marginTop">30dp</item>
+ </style>
+
+ <style name="TV.Dvr.Settings.GuidedSubActionsListStyle" parent="Widget.Leanback.GuidedSubActionsListStyle">
+ <item name="android:layout_marginTop">51dp</item>
+ <item name="android:paddingTop">10dp</item>
+ <item name="android:layout_marginBottom">51dp</item>
+ <item name="android:background">@color/common_setup_done_container_background</item>
+ </style>
+
+ <style name="TV.Dvr.Settings.GuidedButtonActionsListStyle" parent="Widget.Leanback.GuidedButtonActionsListStyle">
+ <item name="android:background">@color/common_setup_done_container_background</item>
+ </style>
+
+ <style name="TV.Dvr.Settings.Priority.GuidedActionItemContainerStyle" parent="Widget.Setup.GuidedActionItemContainerStyle">
+ <item name="android:layout_height">@dimen/dvr_settings_one_line_action_container_height</item>
+ </style>
+
+ <style name="TV.Dvr.Series.Deletion.guidedActionItemCheckmarkStyle" parent="Widget.Leanback.GuidedActionItemCheckmarkStyle">
+ <item name="android:layout_width">@dimen/dvr_deletion_check_mark_size</item>
+ <item name="android:layout_height">@dimen/dvr_deletion_check_mark_size</item>
+ <item name="android:layout_marginEnd">@dimen/dvr_deletion_check_mark_margin</item>
+ </style>
+
+ <style name="TV.Dvr.Browse.DetailsDescriptionTitleStyle" parent="Widget.Leanback.DetailsDescriptionTitleStyle">
+ <item name="resizedTextSize">@dimen/dvr_details_description_title_resized_text_size</item>
+ <item name="resizedPaddingAdjustmentTop">@dimen/dvr_details_description_title_padding_adjust_top</item>
+ <item name="resizedPaddingAdjustmentBottom">@dimen/dvr_details_description_title_padding_adjust_bottom</item>
</style>
-</resources>
+</resources> \ No newline at end of file
diff --git a/res/values/themes.xml b/res/values/themes.xml
index 2948b6b3..9be64eb8 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -70,20 +70,49 @@
<item name="android:windowBackground">@android:color/transparent</item>
<item name="guidedStepBackground">@color/common_tv_background</item>
<item name="guidedActionsBackground">@color/common_tv_background</item>
+ <item name="guidedActionsSelectorDrawable">@drawable/dvr_selector_background</item>
<item name="guidanceTitleStyle">@style/TV.Dvr.GuidanceTitleStyle</item>
+ <item name="guidanceBreadcrumbStyle">@style/TV.Dvr.GuidanceBreadcrumbStyle</item>
<item name="guidanceDescriptionStyle">@style/TV.Dvr.GuidanceDescriptionStyle</item>
+ <item name="guidanceIconStyle">@style/TV.Dvr.GuidanceIconStyle</item>
<item name="guidedActionsListStyle">@style/TV.Dvr.GuidedActionsListStyle</item>
<item name="guidedActionItemContainerStyle">@style/TV.Dvr.GuidedActionItemContainerStyle</item>
<item name="guidedActionContentWidthWeight">@string/lb_guidedactions_width_weight</item>
</style>
- <style name="Theme.TV.Onboarding" parent="Theme.LeanbackBase">
- <item name="onboardingHeaderStyle">@style/Widget.Leanback.OnboardingHeaderStyle</item>
- <item name="onboardingTitleStyle">@style/Widget.Leanback.OnboardingTitleStyle</item>
- <item name="onboardingDescriptionStyle">@style/Widget.Leanback.OnboardingDescriptionStyle</item>
- <item name="onboardingNavigatorContainerStyle">@style/Widget.Leanback.OnboardingNavigatorContainerStyle</item>
- <item name="onboardingPageIndicatorStyle">@style/Widget.Leanback.OnboardingPageIndicatorStyle</item>
- <item name="onboardingStartButtonStyle">@style/Widget.Leanback.OnboardingStartButtonStyle</item>
- <item name="onboardingLogoStyle">@style/Widget.Leanback.OnboardingLogoStyle</item>
+ <style name="Theme.TV.Dvr.GuidedStep.Twoline.Action" parent = "Theme.TV.Dvr.GuidedStep">
+ <item name="guidedActionItemContainerStyle">@style/TV.Dvr.GuidedActionItemContainerStyle.Twoline.Action</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Conflict.GuidedStep" parent="Theme.TV.Dvr.GuidedStep">
+ <item name="guidanceTitleStyle">@style/TV.Dvr.Conflict.GuidanceTitleStyle</item>
+ <item name="guidedActionsListStyle">@style/TV.Dvr.Conflict.GuidedActionsListStyle</item>
+ <item name="guidedStepKeyline">@string/dvr_conflict_guidedstep_keyline</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Settings.GuidedStep" parent="Theme.TV.GuidedStep">
+ <!-- button actions width and button action item height is programatically implemented
+ in GuidedButtonActionsStylist.java -->
+ <item name="guidedSubActionsListStyle">@style/TV.Dvr.Settings.GuidedSubActionsListStyle</item>
+ <item name="guidedActionsBackgroundDark">@color/setup_sub_actions_background</item>
+ <item name="guidedButtonActionsListStyle">@style/TV.Dvr.Settings.GuidedButtonActionsListStyle</item>
+ <item name="guidedActionContentWidthWeightTwoPanels">@string/dvr_settings_guidedactions_width_weight</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Settings.Priority.GuidedStep" parent="Theme.TV.Dvr.Settings.GuidedStep">
+ <item name="guidedActionItemContainerStyle">@style/TV.Dvr.Settings.Priority.GuidedActionItemContainerStyle</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Series.Deletion.GuidedStep" parent="Theme.TV.Dvr.Settings.GuidedStep">
+ <item name="guidedActionItemCheckmarkStyle">@style/TV.Dvr.Series.Deletion.guidedActionItemCheckmarkStyle</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Series.Settings.GuidedStep" parent="Theme.TV.Dvr.Settings.GuidedStep">
+ <item name="android:windowBackground">@color/setup_background</item>
+ <item name="android:windowIsTranslucent">true</item>
+ </style>
+
+ <style name="Theme.TV.Dvr.Browse.Details" parent="Theme.Leanback.Details">
+ <item name="detailsDescriptionTitleStyle">@style/TV.Dvr.Browse.DetailsDescriptionTitleStyle</item>
</style>
</resources>
diff --git a/res/xml/remote_config_defaults.xml b/res/xml/remote_config_defaults.xml
new file mode 100644
index 00000000..742bff21
--- /dev/null
+++ b/res/xml/remote_config_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<defaultsMap>
+ <entry>
+ <key>live_channels_epg_host_and_port</key>
+ <value>datamixer-pa.googleapis.com:443</value>
+ </entry>
+</defaultsMap> \ No newline at end of file
diff --git a/usbtuner/src/com/google/android/exoplayer/MediaFormatUtil.java b/src/com/android/exoplayer/MediaFormatUtil.java
index 5a5713e3..d7a981f6 100644
--- a/usbtuner/src/com/google/android/exoplayer/MediaFormatUtil.java
+++ b/src/com/android/exoplayer/MediaFormatUtil.java
@@ -17,6 +17,8 @@ package com.google.android.exoplayer;
import android.support.annotation.Nullable;
+import com.google.android.exoplayer.util.MimeTypes;
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -29,7 +31,6 @@ public class MediaFormatUtil {
* {@link android.media.MediaFormat} should be converted to be used with ExoPlayer.
*/
public static MediaFormat createMediaFormat(android.media.MediaFormat format) {
- // TODO: Add test for this method.
String mimeType = format.getString(android.media.MediaFormat.KEY_MIME);
String language = getOptionalStringV16(format, android.media.MediaFormat.KEY_LANGUAGE);
int maxInputSize =
@@ -52,41 +53,23 @@ public class MediaFormatUtil {
}
long durationUs = format.containsKey(android.media.MediaFormat.KEY_DURATION)
? format.getLong(android.media.MediaFormat.KEY_DURATION) : C.UNKNOWN_TIME_US;
+ int pcmEncoding = MimeTypes.AUDIO_RAW.equals(mimeType) ? C.ENCODING_PCM_16BIT
+ : MediaFormat.NO_VALUE;
MediaFormat mediaFormat = new MediaFormat(null, mimeType, MediaFormat.NO_VALUE,
maxInputSize, durationUs, width, height, rotationDegrees, MediaFormat.NO_VALUE,
channelCount, sampleRate, language, MediaFormat.OFFSET_SAMPLE_RELATIVE,
- initializationData, false, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, encoderDelay,
- encoderPadding);
+ initializationData, false, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, pcmEncoding,
+ encoderDelay, encoderPadding, null, MediaFormat.NO_VALUE);
mediaFormat.setFrameworkFormatV16(format);
return mediaFormat;
}
- /**
- * Creates {@link MediaFormat} for audio track.
- */
- public static MediaFormat createAudioMediaFormat(String mimeType, long durationUs,
- int channelCount, int sampleRate) {
- return MediaFormat.createAudioFormat(null, mimeType, MediaFormat.NO_VALUE,
- MediaFormat.NO_VALUE, durationUs, channelCount, sampleRate, null, "");
- }
-
- /**
- * Creates {@link MediaFormat} for closed caption track.
- */
- public static MediaFormat createTextMediaFormat(String mimeType, long durationUs) {
- return new MediaFormat(null, mimeType, 0, MediaFormat.NO_VALUE, durationUs,
- MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE,
- MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, "",
- MediaFormat.OFFSET_SAMPLE_RELATIVE, null, false, MediaFormat.NO_VALUE,
- MediaFormat.NO_VALUE, MediaFormat.NO_VALUE, MediaFormat.NO_VALUE);
- }
-
@Nullable
- private static final String getOptionalStringV16(android.media.MediaFormat format, String key) {
+ private static String getOptionalStringV16(android.media.MediaFormat format, String key) {
return format.containsKey(key) ? format.getString(key) : null;
}
- private static final int getOptionalIntegerV16(android.media.MediaFormat format, String key) {
+ private static int getOptionalIntegerV16(android.media.MediaFormat format, String key) {
return format.containsKey(key) ? format.getInteger(key) : MediaFormat.NO_VALUE;
}
diff --git a/usbtuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java b/src/com/android/exoplayer/MediaSoftwareCodecUtil.java
index 4b605fbb..8c2509d4 100644
--- a/usbtuner/src/com/google/android/exoplayer/MediaSoftwareCodecUtil.java
+++ b/src/com/android/exoplayer/MediaSoftwareCodecUtil.java
@@ -15,8 +15,6 @@
*/
package com.google.android.exoplayer;
-import com.google.android.exoplayer.util.MimeTypes;
-
import android.annotation.TargetApi;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
@@ -24,6 +22,8 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
+import com.google.android.exoplayer.util.MimeTypes;
+
import java.util.HashMap;
/**
@@ -61,8 +61,7 @@ public class MediaSoftwareCodecUtil {
if (info == null) {
return null;
}
- return new DecoderInfo(info.first, info.second.isFeatureSupported(
- MediaCodecInfo.CodecCapabilities.FEATURE_AdaptivePlayback));
+ return new DecoderInfo(info.first, info.second);
}
/**
@@ -112,8 +111,7 @@ public class MediaSoftwareCodecUtil {
if (!info.isEncoder() && codecName.startsWith("OMX.google.")
&& (secureDecodersExplicit || !codecName.endsWith(".secure"))) {
String[] supportedTypes = info.getSupportedTypes();
- for (int j = 0; j < supportedTypes.length; j++) {
- String supportedType = supportedTypes[j];
+ for (String supportedType : supportedTypes) {
if (supportedType.equalsIgnoreCase(mimeType)) {
MediaCodecInfo.CodecCapabilities capabilities =
info.getCapabilitiesForType(supportedType);
@@ -132,7 +130,7 @@ public class MediaSoftwareCodecUtil {
// Only cache this variant. If both insecure and secure decoders are
// available, they should both be listed separately.
sSwCodecs.put(
- key.secure == secure ? key : new CodecKey(mimeType, secure),
+ key.secure == secure ? key: new CodecKey(mimeType, secure),
Pair.create(codecName, capabilities));
}
if (sSwCodecs.containsKey(key)) {
@@ -151,26 +149,26 @@ public class MediaSoftwareCodecUtil {
/**
* Returns the number of codecs in the list.
*/
- public int getCodecCount();
+ int getCodecCount();
/**
* Returns the info at the specified index in the list.
*
* @param index The index.
*/
- public MediaCodecInfo getCodecInfoAt(int index);
+ MediaCodecInfo getCodecInfoAt(int index);
/**
* Returns whether secure decoders are explicitly listed, if present.
*/
- public boolean secureDecodersExplicit();
+ boolean secureDecodersExplicit();
/**
* Returns true if secure playback is supported for the given
* {@link android.media.MediaCodecInfo.CodecCapabilities}, which should
* have been obtained from a {@link MediaCodecInfo} obtained from this list.
*/
- public boolean isSecurePlaybackSupported(String mimeType,
+ boolean isSecurePlaybackSupported(String mimeType,
MediaCodecInfo.CodecCapabilities capabilities);
}
diff --git a/usbtuner/src/com/google/android/exoplayer/text/SubtitleView.java b/src/com/android/exoplayer/text/SubtitleView.java
index b21d6be3..b1161f22 100644
--- a/usbtuner/src/com/google/android/exoplayer/text/SubtitleView.java
+++ b/src/com/android/exoplayer/text/SubtitleView.java
@@ -35,9 +35,11 @@ import android.view.View;
import com.google.android.exoplayer.util.Util;
+import java.util.ArrayList;
+
/**
* Since this class does not exist in recent version of ExoPlayer and used by
- * {@link com.android.usbtuner.cc.CaptionWindowLayout}, this class is copied from
+ * {@link com.google.android.tv.tuner.cc.CaptionWindowLayout}, this class is copied from
* older version of ExoPlayer.
* A view for rendering a single caption.
*/
@@ -61,8 +63,8 @@ public class SubtitleView extends View {
private final float mShadowRadius;
private final float mShadowOffset;
- private TextPaint mTextPaint;
- private Paint mPaint;
+ private final TextPaint mTextPaint;
+ private final Paint mPaint;
private CharSequence mText;
@@ -76,9 +78,11 @@ public class SubtitleView extends View {
private StaticLayout mLayout;
private Alignment mAlignment;
- private float mSpacingMult;
- private float mSpacingAdd;
+ private final float mSpacingMult;
+ private final float mSpacingAdd;
private int mInnerPaddingX;
+ private float mWhiteSpaceWidth;
+ private ArrayList<Integer> mPrefixSpaces = new ArrayList<>();
public SubtitleView(Context context) {
this(context, null);
@@ -149,6 +153,7 @@ public class SubtitleView extends View {
if (mTextPaint.getTextSize() != size) {
mTextPaint.setTextSize(size);
mInnerPaddingX = (int) (size * INNER_PADDING_RATIO + 0.5f);
+ mWhiteSpaceWidth -= mInnerPaddingX * 2;
forceUpdate(true);
}
}
@@ -177,6 +182,14 @@ public class SubtitleView extends View {
forceUpdate(true);
}
+ public void setPrefixSpaces(ArrayList<Integer> prefixSpaces) {
+ mPrefixSpaces = prefixSpaces;
+ }
+
+ public void setWhiteSpaceWidth(float whiteSpaceWidth) {
+ mWhiteSpaceWidth = whiteSpaceWidth;
+ }
+
private void setTypeface(Typeface typeface) {
if (mTextPaint.getTypeface() != typeface) {
mTextPaint.setTypeface(typeface);
@@ -268,7 +281,11 @@ public class SubtitleView extends View {
paint.setStyle(Style.FILL);
for (int i = 0; i < lineCount; i++) {
- bounds.left = layout.getLineLeft(i) - innerPaddingX;
+ float spacesPadding = 0.0f;
+ if (i < mPrefixSpaces.size()) {
+ spacesPadding += mPrefixSpaces.get(i) * mWhiteSpaceWidth;
+ }
+ bounds.left = layout.getLineLeft(i) - innerPaddingX + spacesPadding;
bounds.right = layout.getLineRight(i) + innerPaddingX;
bounds.top = previousBottom;
bounds.bottom = layout.getLineBottom(i);
diff --git a/src/com/android/tv/ApplicationSingletons.java b/src/com/android/tv/ApplicationSingletons.java
index 5198f7fd..fd125d52 100644
--- a/src/com/android/tv/ApplicationSingletons.java
+++ b/src/com/android/tv/ApplicationSingletons.java
@@ -18,11 +18,15 @@ package com.android.tv;
import com.android.tv.analytics.Analytics;
import com.android.tv.analytics.Tracker;
+import com.android.tv.config.RemoteConfig;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ProgramDataManager;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.DvrSessionManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.util.AccountHelper;
import com.android.tv.util.TvInputManagerHelper;
/**
@@ -36,9 +40,15 @@ public interface ApplicationSingletons {
DvrDataManager getDvrDataManager();
+ DvrStorageStatusManager getDvrStorageStatusManager();
+
+ DvrScheduleManager getDvrScheduleManager();
+
DvrManager getDvrManager();
- DvrSessionManager getDvrSessionManger();
+ DvrWatchedPositionManager getDvrWatchedPositionManager();
+
+ InputSessionManager getInputSessionManager();
ProgramDataManager getProgramDataManager();
@@ -47,4 +57,8 @@ public interface ApplicationSingletons {
TvInputManagerHelper getTvInputManagerHelper();
MainActivityWrapper getMainActivityWrapper();
+
+ AccountHelper getAccountHelper();
+
+ RemoteConfig getRemoteConfig();
}
diff --git a/src/com/android/tv/Features.java b/src/com/android/tv/Features.java
index 6a78b632..7e8e3689 100644
--- a/src/com/android/tv/Features.java
+++ b/src/com/android/tv/Features.java
@@ -18,17 +18,18 @@ 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.support.v4.os.BuildCompat;
import com.android.tv.common.feature.Feature;
import com.android.tv.common.feature.GServiceFeature;
-import com.android.tv.common.feature.PackageVersionFeature;
import com.android.tv.common.feature.PropertyFeature;
import com.android.tv.util.PermissionUtils;
@@ -56,52 +57,56 @@ public final class Features {
public static final Feature EPG_SEARCH =
new PropertyFeature("feature_tv_use_epg_search", false);
- public static final Feature USB_TUNER = new Feature() {
-
- /**
- * 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
- * After release, change class to this to just be
- * {@link BuildCompat#isAtLeastN()}.
- */
+ public static final Feature TUNER = new Feature() {
@Override
public boolean isEnabled(Context context) {
+
+ // 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
+ // After release, change class to this to just be {@link BuildCompat#isAtLeastN()}.
return Build.VERSION.SDK_INT > Build.VERSION_CODES.M || BuildCompat.isAtLeastN();
}
};
- private static final String PLAY_STORE_PACKAGE_NAME = "com.android.vending";
- private static final int PLAY_STORE_ZIMA_VERSION_CODE = 80441186;
- private static final Feature PLAY_STORE_LINK =
- new PackageVersionFeature(PLAY_STORE_PACKAGE_NAME, PLAY_STORE_ZIMA_VERSION_CODE);
-
- public static final Feature ONBOARDING_PLAY_STORE = PLAY_STORE_LINK;
-
- /**
- * A flag which indicates that the on-boarding experience is used or not.
- *
- * <p>See <a href="http://b/24070322">b/24070322</a>
- */
- public static final Feature ONBOARDING_EXPERIENCE = ONBOARDING_PLAY_STORE;
-
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 = AND(ONBOARDING_EXPERIENCE,
+ 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);
}
- }));
+ });
- @VisibleForTesting
- public static Feature TEST_FEATURE = new PropertyFeature("test_feature", false);
+ public static final Feature PICTURE_IN_PICTURE = new Feature() {
+ private Boolean mEnabled;
- public static final Feature FETCH_EPG = new PropertyFeature("live_channels_fetch_epg", false);
+ @Override
+ public boolean isEnabled(Context context) {
+ if (mEnabled == null) {
+ mEnabled = 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 = new PropertyFeature("test_feature", false);
private Features() {
}
diff --git a/src/com/android/tv/InputSessionManager.java b/src/com/android/tv/InputSessionManager.java
new file mode 100644
index 00000000..e4b0f456
--- /dev/null
+++ b/src/com/android/tv/InputSessionManager.java
@@ -0,0 +1,549 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvRecordingClient;
+import android.media.tv.TvRecordingClient.RecordingCallback;
+import android.media.tv.TvTrackInfo;
+import android.media.tv.TvView;
+import android.media.tv.TvView.TvInputCallback;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Channel;
+import com.android.tv.ui.TunableTvView;
+import com.android.tv.ui.TunableTvView.OnTuneListener;
+import com.android.tv.util.TvInputManagerHelper;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * Manages input sessions.
+ * Responsible for:
+ * <ul>
+ * <li>Manage {@link TvView} sessions and recording sessions</li>
+ * <li>Manage capabilities (conflict)</li>
+ * </ul>
+ * <p>
+ * As TvView's methods should be called on the main thread and the {@link RecordingSession} should
+ * look at the state of the {@link TvViewSession} when it calls the framework methods, the framework
+ * calls in RecordingSession are made on the main thread not to introduce the multi-thread problems.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class InputSessionManager {
+ private static final String TAG = "InputSessionManager";
+ private static final boolean DEBUG = false;
+
+ private final Context mContext;
+ private final TvInputManagerHelper mInputManager;
+ private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
+ private final Set<TvViewSession> mTvViewSessions = new ArraySet<>();
+ private final Set<RecordingSession> mRecordingSessions =
+ Collections.synchronizedSet(new ArraySet<>());
+ private final Set<OnTvViewChannelChangeListener> mOnTvViewChannelChangeListeners =
+ new ArraySet<>();
+
+ public InputSessionManager(Context context) {
+ mContext = context.getApplicationContext();
+ mInputManager = TvApplication.getSingletons(context).getTvInputManagerHelper();
+ }
+
+ /**
+ * Creates the session for {@link TvView}.
+ * <p>
+ * Do not call {@link TvView#setCallback} after the session is created.
+ */
+ @MainThread
+ @NonNull
+ public TvViewSession createTvViewSession(TvView tvView, TunableTvView tunableTvView,
+ TvInputCallback callback) {
+ TvViewSession session = new TvViewSession(tvView, tunableTvView, callback);
+ mTvViewSessions.add(session);
+ if (DEBUG) Log.d(TAG, "TvView session created: " + session);
+ return session;
+ }
+
+ /**
+ * Releases the {@link TvView} session.
+ */
+ @MainThread
+ public void releaseTvViewSession(TvViewSession session) {
+ mTvViewSessions.remove(session);
+ session.reset();
+ if (DEBUG) Log.d(TAG, "TvView session released: " + session);
+ }
+
+ /**
+ * Creates the session for recording.
+ */
+ @NonNull
+ public RecordingSession createRecordingSession(String inputId, String tag,
+ RecordingCallback callback, Handler handler, long endTimeMs) {
+ RecordingSession session = new RecordingSession(inputId, tag, callback, handler, endTimeMs);
+ mRecordingSessions.add(session);
+ if (DEBUG) Log.d(TAG, "Recording session created: " + session);
+ return session;
+ }
+
+ /**
+ * Releases the recording session.
+ */
+ public void releaseRecordingSession(RecordingSession session) {
+ mRecordingSessions.remove(session);
+ session.release();
+ if (DEBUG) Log.d(TAG, "Recording session released: " + session);
+ }
+
+ /**
+ * Adds the {@link OnTvViewChannelChangeListener}.
+ */
+ @MainThread
+ public void addOnTvViewChannelChangeListener(OnTvViewChannelChangeListener listener) {
+ mOnTvViewChannelChangeListeners.add(listener);
+ }
+
+ /**
+ * Removes the {@link OnTvViewChannelChangeListener}.
+ */
+ @MainThread
+ public void removeOnTvViewChannelChangeListener(OnTvViewChannelChangeListener listener) {
+ mOnTvViewChannelChangeListeners.remove(listener);
+ }
+
+ @MainThread
+ void notifyTvViewChannelChange(Uri channelUri) {
+ for (OnTvViewChannelChangeListener l : mOnTvViewChannelChangeListeners) {
+ l.onTvViewChannelChange(channelUri);
+ }
+ }
+
+ /**
+ * Returns the current {@link TvView} channel.
+ */
+ @MainThread
+ public Uri getCurrentTvViewChannelUri() {
+ for (TvViewSession session : mTvViewSessions) {
+ if (session.mTuned) {
+ return session.mChannelUri;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Retruns the earliest end time of recording sessions in progress of the certain TV input.
+ */
+ @MainThread
+ public Long getEarliestRecordingSessionEndTimeMs(String inputId) {
+ long timeMs = Long.MAX_VALUE;
+ synchronized (mRecordingSessions) {
+ for (RecordingSession session : mRecordingSessions) {
+ if (session.mTuned && TextUtils.equals(inputId, session.mInputId)) {
+ if (session.mEndTimeMs < timeMs) {
+ timeMs = session.mEndTimeMs;
+ }
+ }
+ }
+ }
+ return timeMs == Long.MAX_VALUE ? null : timeMs;
+ }
+
+ @MainThread
+ int getTunedTvViewSessionCount(String inputId) {
+ int tunedCount = 0;
+ for (TvViewSession session : mTvViewSessions) {
+ if (session.mTuned && Objects.equals(inputId, session.mInputId)) {
+ ++tunedCount;
+ }
+ }
+ return tunedCount;
+ }
+
+ @MainThread
+ boolean isTunedForTvView(Uri channelUri) {
+ for (TvViewSession session : mTvViewSessions) {
+ if (session.mTuned && Objects.equals(channelUri, session.mChannelUri)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int getTunedRecordingSessionCount(String inputId) {
+ synchronized (mRecordingSessions) {
+ int tunedCount = 0;
+ for (RecordingSession session : mRecordingSessions) {
+ if (session.mTuned && Objects.equals(inputId, session.mInputId)) {
+ ++tunedCount;
+ }
+ }
+ return tunedCount;
+ }
+ }
+
+ boolean isTunedForRecording(Uri channelUri) {
+ synchronized (mRecordingSessions) {
+ for (RecordingSession session : mRecordingSessions) {
+ if (session.mTuned && Objects.equals(channelUri, session.mChannelUri)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * The session for {@link TvView}.
+ * <p>
+ * The methods which create or release session for the TV input should be called through this
+ * session.
+ */
+ @MainThread
+ public class TvViewSession {
+ private final TvView mTvView;
+ private final TunableTvView mTunableTvView;
+ private final TvInputCallback mCallback;
+ private Channel mChannel;
+ private String mInputId;
+ private Uri mChannelUri;
+ private Bundle mParams;
+ private OnTuneListener mOnTuneListener;
+ private boolean mTuned;
+ private boolean mNeedToBeRetuned;
+
+ TvViewSession(TvView tvView, TunableTvView tunableTvView, TvInputCallback callback) {
+ mTvView = tvView;
+ mTunableTvView = tunableTvView;
+ mCallback = callback;
+ mTvView.setCallback(new DelegateTvInputCallback(mCallback) {
+ @Override
+ public void onConnectionFailed(String inputId) {
+ if (DEBUG) Log.d(TAG, "TvViewSession: commection failed");
+ mTuned = false;
+ mNeedToBeRetuned = false;
+ super.onConnectionFailed(inputId);
+ notifyTvViewChannelChange(null);
+ }
+
+ @Override
+ public void onDisconnected(String inputId) {
+ if (DEBUG) Log.d(TAG, "TvViewSession: disconnected");
+ mTuned = false;
+ mNeedToBeRetuned = false;
+ super.onDisconnected(inputId);
+ notifyTvViewChannelChange(null);
+ }
+ });
+ }
+
+ /**
+ * Tunes to the channel.
+ * <p>
+ * As this is called only for the warming up, there's no need to be retuned.
+ */
+ public void tune(String inputId, Uri channelUri) {
+ if (DEBUG) {
+ Log.d(TAG, "warm-up tune: {input=" + inputId + ", channelUri=" + channelUri + "}");
+ }
+ mInputId = inputId;
+ mChannelUri = channelUri;
+ mTuned = true;
+ mNeedToBeRetuned = false;
+ mTvView.tune(inputId, channelUri);
+ notifyTvViewChannelChange(channelUri);
+ }
+
+ /**
+ * Tunes to the channel.
+ */
+ public void tune(Channel channel, Bundle params, OnTuneListener listener) {
+ if (DEBUG) {
+ Log.d(TAG, "tune: {session=" + this + ", channel=" + channel + ", params=" + params
+ + ", listener=" + listener + ", mTuned=" + mTuned + "}");
+ }
+ mChannel = channel;
+ mInputId = channel.getInputId();
+ mChannelUri = channel.getUri();
+ mParams = params;
+ mOnTuneListener = listener;
+ TvInputInfo input = mInputManager.getTvInputInfo(mInputId);
+ if (input == null || (input.canRecord() && !isTunedForRecording(mChannelUri)
+ && getTunedRecordingSessionCount(mInputId) >= input.getTunerCount())) {
+ if (DEBUG) {
+ if (input == null) {
+ Log.d(TAG, "Can't find input for input ID: " + mInputId);
+ } else {
+ Log.d(TAG, "No more tuners to tune for input: " + input);
+ }
+ }
+ mCallback.onConnectionFailed(mInputId);
+ // Release the previous session to not to hold the unnecessary session.
+ resetByRecording();
+ return;
+ }
+ mTuned = true;
+ mNeedToBeRetuned = false;
+ mTvView.tune(mInputId, mChannelUri, params);
+ notifyTvViewChannelChange(mChannelUri);
+ }
+
+ void retune() {
+ if (DEBUG) Log.d(TAG, "Retune requested.");
+ if (mNeedToBeRetuned) {
+ if (DEBUG) Log.d(TAG, "Retuning: {channel=" + mChannel + "}");
+ mTunableTvView.tuneTo(mChannel, mParams, mOnTuneListener);
+ mNeedToBeRetuned = false;
+ }
+ }
+
+ /**
+ * Plays a given recorded TV program.
+ *
+ * @see TvView#timeShiftPlay
+ */
+ public void timeShiftPlay(String inputId, Uri recordedProgramUri) {
+ mTuned = false;
+ mNeedToBeRetuned = false;
+ mTvView.timeShiftPlay(inputId, recordedProgramUri);
+ notifyTvViewChannelChange(null);
+ }
+
+ /**
+ * Resets this TvView.
+ */
+ public void reset() {
+ if (DEBUG) Log.d(TAG, "Reset TvView session");
+ mTuned = false;
+ mTvView.reset();
+ mNeedToBeRetuned = false;
+ notifyTvViewChannelChange(null);
+ }
+
+ void resetByRecording() {
+ mCallback.onVideoUnavailable(mInputId,
+ TunableTvView.VIDEO_UNAVAILABLE_REASON_NO_RESOURCE);
+ if (mTuned) {
+ if (DEBUG) Log.d(TAG, "Reset TvView session by recording");
+ mTunableTvView.resetByRecording();
+ reset();
+ }
+ mNeedToBeRetuned = true;
+ }
+ }
+
+ /**
+ * The session for recording.
+ * <p>
+ * The caller is responsible for releasing the session when the error occurs.
+ */
+ public class RecordingSession {
+ private final String mInputId;
+ private Uri mChannelUri;
+ private final RecordingCallback mCallback;
+ private final Handler mHandler;
+ private volatile long mEndTimeMs;
+ private TvRecordingClient mClient;
+ private boolean mTuned;
+
+ RecordingSession(String inputId, String tag, RecordingCallback callback,
+ Handler handler, long endTimeMs) {
+ mInputId = inputId;
+ mCallback = callback;
+ mHandler = handler;
+ mClient = new TvRecordingClient(mContext, tag, callback, handler);
+ mEndTimeMs = endTimeMs;
+ }
+
+ void release() {
+ if (DEBUG) Log.d(TAG, "Release of recording session requested.");
+ runOnHandler(mMainThreadHandler, new Runnable() {
+ @Override
+ public void run() {
+ if (DEBUG) Log.d(TAG, "Releasing of recording session.");
+ mTuned = false;
+ mClient.release();
+ mClient = null;
+ for (TvViewSession session : mTvViewSessions) {
+ if (DEBUG) {
+ Log.d(TAG, "Finding TvView sessions for retune: {tuned="
+ + session.mTuned + ", inputId=" + session.mInputId
+ + ", session=" + session + "}");
+ }
+ if (!session.mTuned && Objects.equals(session.mInputId, mInputId)) {
+ session.retune();
+ break;
+ }
+ }
+ }
+ });
+ }
+
+ /**
+ * Tunes to the channel for recording.
+ */
+ public void tune(String inputId, Uri channelUri) {
+ runOnHandler(mMainThreadHandler, new Runnable() {
+ @Override
+ public void run() {
+ int tunedRecordingSessionCount = getTunedRecordingSessionCount(inputId);
+ TvInputInfo input = mInputManager.getTvInputInfo(inputId);
+ if (input == null || !input.canRecord()
+ || input.getTunerCount() <= tunedRecordingSessionCount) {
+ runOnHandler(mHandler, new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onConnectionFailed(inputId);
+ }
+ });
+ return;
+ }
+ mTuned = true;
+ int tunedTuneSessionCount = getTunedTvViewSessionCount(inputId);
+ if (!isTunedForTvView(channelUri) && tunedTuneSessionCount > 0
+ && tunedRecordingSessionCount + tunedTuneSessionCount
+ >= input.getTunerCount()) {
+ for (TvViewSession session : mTvViewSessions) {
+ if (session.mTuned && Objects.equals(session.mInputId, inputId)
+ && !isTunedForRecording(session.mChannelUri)) {
+ session.resetByRecording();
+ break;
+ }
+ }
+ }
+ mChannelUri = channelUri;
+ mClient.tune(inputId, channelUri);
+ }
+ });
+ }
+
+ /**
+ * Starts recording.
+ */
+ public void startRecording(Uri programHintUri) {
+ mClient.startRecording(programHintUri);
+ }
+
+ /**
+ * Stops recording.
+ */
+ public void stopRecording() {
+ mClient.stopRecording();
+ }
+
+ /**
+ * Sets recording session's ending time.
+ */
+ public void setEndTimeMs(long endTimeMs) {
+ mEndTimeMs = endTimeMs;
+ }
+
+ private void runOnHandler(Handler handler, Runnable runnable) {
+ if (Looper.myLooper() == handler.getLooper()) {
+ runnable.run();
+ } else {
+ handler.post(runnable);
+ }
+ }
+ }
+
+ private static class DelegateTvInputCallback extends TvInputCallback {
+ private final TvInputCallback mDelegate;
+
+ DelegateTvInputCallback(TvInputCallback delegate) {
+ mDelegate = delegate;
+ }
+
+ @Override
+ public void onConnectionFailed(String inputId) {
+ mDelegate.onConnectionFailed(inputId);
+ }
+
+ @Override
+ public void onDisconnected(String inputId) {
+ mDelegate.onDisconnected(inputId);
+ }
+
+ @Override
+ public void onChannelRetuned(String inputId, Uri channelUri) {
+ mDelegate.onChannelRetuned(inputId, channelUri);
+ }
+
+ @Override
+ public void onTracksChanged(String inputId, List<TvTrackInfo> tracks) {
+ mDelegate.onTracksChanged(inputId, tracks);
+ }
+
+ @Override
+ public void onTrackSelected(String inputId, int type, String trackId) {
+ mDelegate.onTrackSelected(inputId, type, trackId);
+ }
+
+ @Override
+ public void onVideoSizeChanged(String inputId, int width, int height) {
+ mDelegate.onVideoSizeChanged(inputId, width, height);
+ }
+
+ @Override
+ public void onVideoAvailable(String inputId) {
+ mDelegate.onVideoAvailable(inputId);
+ }
+
+ @Override
+ public void onVideoUnavailable(String inputId, int reason) {
+ mDelegate.onVideoUnavailable(inputId, reason);
+ }
+
+ @Override
+ public void onContentAllowed(String inputId) {
+ mDelegate.onContentAllowed(inputId);
+ }
+
+ @Override
+ public void onContentBlocked(String inputId, TvContentRating rating) {
+ mDelegate.onContentBlocked(inputId, rating);
+ }
+
+ @Override
+ public void onTimeShiftStatusChanged(String inputId, int status) {
+ mDelegate.onTimeShiftStatusChanged(inputId, status);
+ }
+ }
+
+ /**
+ * Called when the {@link TvView} channel is changed.
+ */
+ public interface OnTvViewChannelChangeListener {
+ void onTvViewChannelChange(@Nullable Uri channelUri);
+ }
+}
diff --git a/src/com/android/tv/MainActivity.java b/src/com/android/tv/MainActivity.java
index 78fda42a..58850b5f 100644
--- a/src/com/android/tv/MainActivity.java
+++ b/src/com/android/tv/MainActivity.java
@@ -25,10 +25,10 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.res.Configuration;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
-import android.graphics.PixelFormat;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.media.AudioManager;
@@ -44,6 +44,7 @@ import android.media.tv.TvInputManager.TvInputCallback;
import android.media.tv.TvTrackInfo;
import android.media.tv.TvView.OnUnhandledInputEventListener;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -53,8 +54,8 @@ import android.provider.Settings;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.v4.os.BuildCompat;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
@@ -62,6 +63,7 @@ import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
@@ -80,7 +82,7 @@ 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.recording.RecordedProgram;
+import com.android.tv.common.ui.setup.OnActionClickListener;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
@@ -88,12 +90,16 @@ 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.PinDialogFragment;
import com.android.tv.dialog.SafeDismissDialogFragment;
-import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.ConflictChecker;
import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.DvrPlayActivity;
+import com.android.tv.dvr.DvrUiHelper;
import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.DvrStopRecordingFragment;
+import com.android.tv.dvr.ui.HalfSizedDialogFragment;
+import com.android.tv.experiments.Experiments;
import com.android.tv.menu.Menu;
import com.android.tv.onboarding.OnboardingActivity;
import com.android.tv.parental.ContentRatingsManager;
@@ -101,24 +107,28 @@ import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.receiver.AudioCapabilitiesReceiver;
import com.android.tv.recommendation.NotificationService;
import com.android.tv.search.ProgramGuideSearchFragment;
+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.AppLayerTvView;
import com.android.tv.ui.ChannelBannerView;
import com.android.tv.ui.InputBannerView;
import com.android.tv.ui.KeypadChannelSwitchView;
-import com.android.tv.ui.OverlayRootView;
import com.android.tv.ui.SelectInputView;
import com.android.tv.ui.SelectInputView.OnInputSelectedCallback;
import com.android.tv.ui.TunableTvView;
+import com.android.tv.ui.TunableTvView.BlockScreenType;
import com.android.tv.ui.TunableTvView.OnTuneListener;
import com.android.tv.ui.TvOverlayManager;
import com.android.tv.ui.TvViewUiManager;
import com.android.tv.ui.sidepanel.ClosedCaptionFragment;
import com.android.tv.ui.sidepanel.CustomizeChannelListFragment;
-import com.android.tv.ui.sidepanel.DebugOptionFragment;
+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.ui.sidepanel.SettingsFragment;
import com.android.tv.ui.sidepanel.SideFragment;
+import com.android.tv.util.AccountHelper;
import com.android.tv.util.CaptionSettings;
import com.android.tv.util.ImageCache;
import com.android.tv.util.ImageLoader;
@@ -133,9 +143,6 @@ import com.android.tv.util.SystemProperties;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.TvSettings;
import com.android.tv.util.TvSettings.PipSound;
-import com.android.usbtuner.UsbTunerPreferences;
-import com.android.usbtuner.setup.TunerSetupActivity;
-import com.android.usbtuner.tvinput.UsbTunerTvInputService;
import com.android.tv.util.TvTrackInfoUtils;
import com.android.tv.util.Utils;
@@ -146,12 +153,14 @@ import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* The main activity for the Live TV app.
*/
-public class MainActivity extends Activity implements AudioManager.OnAudioFocusChangeListener {
+public class MainActivity extends Activity implements AudioManager.OnAudioFocusChangeListener,
+ OnActionClickListener {
private static final String TAG = "MainActivity";
private static final boolean DEBUG = false;
@@ -177,12 +186,9 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
private static final int PERMISSIONS_REQUEST_READ_TV_LISTINGS = 1;
+ private static final int PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION = 2;
private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
- private static final String USB_TV_TUNER_INPUT_ID =
- "com.android.tv/com.android.usbtuner.tvinput.UsbTunerTvInputService";
- private static final String DVR_TEST_INPUT_ID = USB_TV_TUNER_INPUT_ID;
-
// Tracker screen names.
public static final String SCREEN_NAME = "Main";
private static final String SCREEN_BEHIND_NAME = "Behind";
@@ -201,8 +207,10 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
BLACKLIST_KEYCODE_TO_TIS.add(KeyEvent.KEYCODE_VOLUME_MUTE);
BLACKLIST_KEYCODE_TO_TIS.add(KeyEvent.KEYCODE_MUTE);
BLACKLIST_KEYCODE_TO_TIS.add(KeyEvent.KEYCODE_SEARCH);
+ BLACKLIST_KEYCODE_TO_TIS.add(KeyEvent.KEYCODE_WINDOW);
}
+
private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
private static final int REQUEST_CODE_START_SYSTEM_CAPTIONING_SETTINGS = 2;
@@ -226,10 +234,25 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
UPDATE_CHANNEL_BANNER_REASON_TUNE_FAST, UPDATE_CHANNEL_BANNER_REASON_UPDATE_INFO,
UPDATE_CHANNEL_BANNER_REASON_LOCK_OR_UNLOCK})
private @interface ChannelBannerUpdateReason {}
+ /**
+ * Updates channel banner because the channel banner is forced to show.
+ */
private static final int UPDATE_CHANNEL_BANNER_REASON_FORCE_SHOW = 1;
+ /**
+ * Updates channel banner because of tuning.
+ */
private static final int UPDATE_CHANNEL_BANNER_REASON_TUNE = 2;
+ /**
+ * Updates channel banner because of fast tuning.
+ */
private static final int UPDATE_CHANNEL_BANNER_REASON_TUNE_FAST = 3;
+ /**
+ * Updates channel banner because of info updating.
+ */
private static final int UPDATE_CHANNEL_BANNER_REASON_UPDATE_INFO = 4;
+ /**
+ * Updates channel banner because the current watched channel is locked or unlocked.
+ */
private static final int UPDATE_CHANNEL_BANNER_REASON_LOCK_OR_UNLOCK = 5;
private static final int TVVIEW_SET_MAIN_TIMEOUT_MS = 3000;
@@ -251,11 +274,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
private final DurationTimer mMainDurationTimer = new DurationTimer();
private final DurationTimer mTuneDurationTimer = new DurationTimer();
private DvrManager mDvrManager;
- private DvrDataManager mDvrDataManager;
+ private ConflictChecker mDvrConflictChecker;
+ private View mContentView;
private TunableTvView mTvView;
private TunableTvView mPipView;
- private OverlayRootView mOverlayRootView;
private Bundle mTuneParams;
private boolean mChannelBannerHiddenBySideFragment;
// TODO: Move the scene views into TvTransitionManager or TvOverlayManager.
@@ -295,8 +318,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
private boolean mVisibleBehind;
private boolean mAc3PassthroughSupported;
private boolean mShowNewSourcesFragment = true;
- private Uri mRecordingUri;
- private String mUsbTunerInputId;
+ private String mTunerInputId;
private boolean mOtherActivityLaunched;
private boolean mIsFilmModeSet;
@@ -332,6 +354,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
private String mSource;
private final Handler mHandler = new MainActivityHandler(this);
+ private final Set<OnActionClickListener> mOnActionClickListeners = new ArraySet<>();
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
@@ -390,12 +413,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
resumePipIfNeeded();
}
mKeypadChannelSwitchView.setChannels(mChannelTuner.getBrowsableChannelList());
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- mOverlayManager.getMenu().setChannelTuner(mChannelTuner);
- }
- });
}
@Override
@@ -422,15 +439,15 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
};
private ProgramGuideSearchFragment mSearchFragment;
- private TvInputCallback mTvInputCallback = new TvInputCallback() {
+ private final TvInputCallback mTvInputCallback = new TvInputCallback() {
@Override
public void onInputAdded(String inputId) {
- if (mUsbTunerInputId.equals(inputId)
- && UsbTunerPreferences.shouldShowSetupActivity(MainActivity.this)) {
+ if (Features.TUNER.isEnabled(MainActivity.this) && mTunerInputId.equals(inputId)
+ && TunerPreferences.shouldShowSetupActivity(MainActivity.this)) {
Intent intent = TunerSetupActivity.createSetupActivity(MainActivity.this);
startActivity(intent);
- UsbTunerPreferences.setShouldShowSetupActivity(MainActivity.this, false);
- SetupUtils.getInstance(MainActivity.this).markAsKnownInput(mUsbTunerInputId);
+ TunerPreferences.setShouldShowSetupActivity(MainActivity.this, false);
+ SetupUtils.getInstance(MainActivity.this).markAsKnownInput(mTunerInputId);
}
}
};
@@ -445,17 +462,14 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
@Override
protected void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG,"onCreate()");
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
- && !PermissionUtils.hasAccessAllEpg(this)) {
- Toast.makeText(this, R.string.msg_not_supported_device, Toast.LENGTH_LONG).show();
- finish();
- return;
- }
- boolean skipToShowOnboarding = getIntent().getAction() == Intent.ACTION_VIEW
- && TvContract.isChannelUriForPassthroughInput(getIntent().getData());
- if (Features.ONBOARDING_EXPERIENCE.isEnabled(this)
- && OnboardingUtils.needToShowOnboarding(this) && !skipToShowOnboarding
+
+ boolean isPassthroughInput = TvContract.isChannelUriForPassthroughInput(getIntent()
+ .getData());
+ boolean skipToShowOnboarding = Intent.ACTION_VIEW.equals(getIntent().getAction())
+ && isPassthroughInput;
+ if (OnboardingUtils.needToShowOnboarding(this) && !skipToShowOnboarding
&& !TvCommonUtils.isRunningInTest()) {
// TODO: The onboarding is turned off in test, because tests are broken by the
// onboarding. We need to enable the feature for tests later.
@@ -464,31 +478,15 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return;
}
- TvApplication tvApplication = (TvApplication) getApplication();
- tvApplication.getMainActivityWrapper().onMainActivityCreated(this);
- if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) {
- Toast.makeText(this, "Using Strict Mode for eng builds", Toast.LENGTH_SHORT).show();
- }
- mTracker = tvApplication.getTracker();
- mTvInputManagerHelper = tvApplication.getTvInputManagerHelper();
- mTvInputManagerHelper.addCallback(mTvInputCallback);
- mUsbTunerInputId = UsbTunerTvInputService.getInputId(this);
- mChannelDataManager = tvApplication.getChannelDataManager();
- mProgramDataManager = tvApplication.getProgramDataManager();
- mProgramDataManager.addOnCurrentProgramUpdatedListener(Channel.INVALID_ID,
- mOnCurrentProgramUpdatedListener);
- mProgramDataManager.setPrefetchEnabled(true);
- mChannelTuner = new ChannelTuner(mChannelDataManager, mTvInputManagerHelper);
- mChannelTuner.addListener(mChannelTunerListener);
- mChannelTuner.start();
- mPipInputManager = new PipInputManager(this, mTvInputManagerHelper, mChannelTuner);
- mPipInputManager.start();
- mMemoryManageables.add(mProgramDataManager);
- mMemoryManageables.add(ImageCache.getInstance());
- mMemoryManageables.add(TvContentRatingCache.getInstance());
- if (CommonFeatures.DVR.isEnabled(this) && BuildCompat.isAtLeastN()) {
- mDvrManager = tvApplication.getDvrManager();
- mDvrDataManager = tvApplication.getDvrDataManager();
+ // Check this permission for the EPG fetch.
+ // TODO: check {@link shouldShowRequestPermissionRationale}.
+ // While testing, no way to allow the permission when the dialog shows up. So we'd better
+ // not show the dialog.
+ if (!TvCommonUtils.isRunningInTest() && Utils.hasInternalTvInputs(this, true)
+ && checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(new String[] {android.Manifest.permission.ACCESS_COARSE_LOCATION},
+ PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION);
}
DisplayManager displayManager = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
@@ -499,9 +497,8 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
int screenHeight = size.y;
mDefaultRefreshRate = display.getRefreshRate();
- mOverlayRootView = (OverlayRootView) getLayoutInflater().inflate(
- R.layout.overlay_root_view, null, false);
setContentView(R.layout.activity_tv);
+ mContentView = findViewById(android.R.id.content);
mTvView = (TunableTvView) findViewById(R.id.main_tunable_tv_view);
int shrunkenTvViewHeight = getResources().getDimensionPixelSize(
R.dimen.shrunken_tvview_height);
@@ -529,6 +526,41 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return false;
}
});
+
+ long channelId = Utils.getLastWatchedChannelId(this);
+ String inputId = Utils.getLastWatchedTunerInputId(this);
+ if (!isPassthroughInput && inputId != null
+ && channelId != Channel.INVALID_ID) {
+ mTvView.warmUpInput(inputId, TvContract.buildChannelUri(channelId));
+ }
+
+ TvApplication tvApplication = (TvApplication) getApplication();
+ tvApplication.getMainActivityWrapper().onMainActivityCreated(this);
+ if (BuildConfig.ENG && SystemProperties.ALLOW_STRICT_MODE.getValue()) {
+ Toast.makeText(this, "Using Strict Mode for eng builds", Toast.LENGTH_SHORT).show();
+ }
+ mTracker = tvApplication.getTracker();
+ mTvInputManagerHelper = tvApplication.getTvInputManagerHelper();
+ if (Features.TUNER.isEnabled(this)) {
+ mTvInputManagerHelper.addCallback(mTvInputCallback);
+ }
+ mTunerInputId = TunerTvInputService.getInputId(this);
+ mChannelDataManager = tvApplication.getChannelDataManager();
+ mProgramDataManager = tvApplication.getProgramDataManager();
+ mProgramDataManager.addOnCurrentProgramUpdatedListener(Channel.INVALID_ID,
+ mOnCurrentProgramUpdatedListener);
+ mProgramDataManager.setPrefetchEnabled(true);
+ mChannelTuner = new ChannelTuner(mChannelDataManager, mTvInputManagerHelper);
+ mChannelTuner.addListener(mChannelTunerListener);
+ mChannelTuner.start();
+ mPipInputManager = new PipInputManager(this, mTvInputManagerHelper, mChannelTuner);
+ mPipInputManager.start();
+ mMemoryManageables.add(mProgramDataManager);
+ mMemoryManageables.add(ImageCache.getInstance());
+ mMemoryManageables.add(TvContentRatingCache.getInstance());
+ if (CommonFeatures.DVR.isEnabled(this)) {
+ mDvrManager = tvApplication.getDvrManager();
+ }
mTimeShiftManager = new TimeShiftManager(this, mTvView, mProgramDataManager, mTracker,
new OnCurrentProgramUpdatedListener() {
@Override
@@ -542,6 +574,8 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
updateChannelBannerAndShowIfNeeded(
UPDATE_CHANNEL_BANNER_REASON_FORCE_SHOW);
break;
+ case TimeShiftManager.TIME_SHIFT_ACTION_ID_PAUSE:
+ case TimeShiftManager.TIME_SHIFT_ACTION_ID_PLAY:
default:
updateChannelBannerAndShowIfNeeded(
UPDATE_CHANNEL_BANNER_REASON_UPDATE_INFO);
@@ -587,7 +621,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
@Override
- public void onPassthroughInputSelected(TvInputInfo input) {
+ public void onPassthroughInputSelected(@NonNull TvInputInfo input) {
Channel currentChannel = mChannelTuner.getCurrentChannel();
String currentInputId = currentChannel == null ? null : currentChannel.getInputId();
if (TextUtils.equals(input.getId(), currentInputId)) {
@@ -607,7 +641,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
});
mSearchFragment = new ProgramGuideSearchFragment();
- mOverlayManager = new TvOverlayManager(this, mChannelTuner,
+ mOverlayManager = new TvOverlayManager(this, mChannelTuner, mTvView,
mKeypadChannelSwitchView, mChannelBannerView, inputBannerView,
selectInputView, sceneContainer, mSearchFragment);
@@ -617,7 +651,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mMediaSession = new MediaSession(this, MEDIA_SESSION_TAG);
mMediaSession.setCallback(new MediaSession.Callback() {
@Override
- public boolean onMediaButtonEvent(Intent mediaButtonIntent) {
+ public boolean onMediaButtonEvent(@NonNull Intent mediaButtonIntent) {
// Consume the media button event here. Should not send it to other apps.
return true;
}
@@ -653,49 +687,54 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
// To avoid not updating Rating systems when changing language.
mTvInputManagerHelper.getContentRatingsManager().update();
-
- initForTest();
- }
-
- @Override
- public void onRequestPermissionsResult(int requestCode, String[] permissions,
- int[] grantResults) {
- if (requestCode == PERMISSIONS_REQUEST_READ_TV_LISTINGS) {
- if (grantResults != null && grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- // Start reload of dependent data
- mChannelDataManager.reload();
- mProgramDataManager.reload();
-
- // Restart live channels.
- Intent intent = getIntent();
- finish();
- startActivity(intent);
- } else {
- Toast.makeText(this, R.string.msg_read_tv_listing_permission_denied,
- Toast.LENGTH_LONG).show();
- finish();
- }
+ if (CommonFeatures.DVR.isEnabled(this)
+ && Features.SHOW_UPCOMING_CONFLICT_DIALOG.isEnabled(this)) {
+ mDvrConflictChecker = new ConflictChecker(this);
}
+ initForTest();
}
@Override
- public void onAttachedToWindow() {
- super.onAttachedToWindow();
- WindowManager.LayoutParams windowParams = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL, 0, PixelFormat.TRANSPARENT);
- windowParams.token = getWindow().getDecorView().getWindowToken();
- ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).addView(mOverlayRootView,
- windowParams);
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ float density = getResources().getDisplayMetrics().density;
+ mTvViewUiManager.onConfigurationChanged((int) (newConfig.screenWidthDp * density),
+ (int) (newConfig.screenHeightDp * density));
}
@Override
- public void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).removeView(mOverlayRootView);
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ switch (requestCode) {
+ case PERMISSIONS_REQUEST_READ_TV_LISTINGS:
+ if (grantResults.length > 0
+ && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ // Start reload of dependent data
+ mChannelDataManager.reload();
+ mProgramDataManager.reload();
+
+ // Restart live channels.
+ Intent intent = getIntent();
+ finish();
+ startActivity(intent);
+ } else {
+ Toast.makeText(this, R.string.msg_read_tv_listing_permission_denied,
+ Toast.LENGTH_LONG).show();
+ finish();
+ }
+ break;
+ case PERMISSIONS_REQUEST_ACCESS_COARSE_LOCATION:
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED
+ && Experiments.CLOUD_EPG.get()) {
+ EpgFetcher.getInstance(this).startImmediately();
+ } else {
+ EpgFetcher.getInstance(this).stop();
+ }
+ break;
+ }
}
- private int getDesiredBlockScreenType() {
+ @BlockScreenType private int getDesiredBlockScreenType() {
if (!mActivityResumed) {
return TunableTvView.BLOCK_SCREEN_TYPE_NO_UI;
}
@@ -727,6 +766,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
@Override
protected void onNewIntent(Intent 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;
+ }
mOverlayManager.getSideFragmentManager().hideAll(false);
if (!handleIntent(intent) && !mActivityStarted) {
// If the activity is stopped and not destroyed, finish the activity.
@@ -760,6 +804,8 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
protected void onResume() {
if (DEBUG) Log.d(TAG, "onResume()");
super.onResume();
+ // Refresh the remote config, it is throttled automatically.
+ TvApplication.getSingletons(this).getRemoteConfig().fetch(null);
if (!PermissionUtils.hasAccessAllEpg(this)
&& checkSelfPermission(PERMISSION_READ_TV_LISTINGS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -784,6 +830,16 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
// visible behind.
requestVisibleBehind(true);
}
+ if (Utils.hasRecordingFailedReason(getApplicationContext(),
+ TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE)) {
+ runAfterAttachedToWindow(new Runnable() {
+ @Override
+ public void run() {
+ DvrUiHelper.showDvrInsufficientSpaceErrorDialog(MainActivity.this);
+ }
+ });
+ }
+
if (mChannelTuner.areAllChannelsLoaded()) {
SetupUtils.getInstance(this).markNewChannelsBrowsable();
resumeTvIfNeeded();
@@ -822,11 +878,17 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
});
}
+ if (mDvrConflictChecker != null) {
+ mDvrConflictChecker.start();
+ }
}
@Override
protected void onPause() {
if (DEBUG) Log.d(TAG, "onPause()");
+ if (mDvrConflictChecker != null) {
+ mDvrConflictChecker.stop();
+ }
finishChannelChangeIfNeeded();
mActivityResumed = false;
mOverlayManager.hideOverlays(TvOverlayManager.FLAG_HIDE_OVERLAYS_DEFAULT);
@@ -882,7 +944,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
if (input == null) {
input = mTvInputManagerHelper.getTvInputInfo(mParentInputIdWhenScreenOff);
if (input == null) {
- SoftPreconditions.checkState(false, TAG, "Input disappear." + input);
+ SoftPreconditions.checkState(false, TAG, "Input disappear.");
finish();
} else {
mInitChannelUri =
@@ -929,16 +991,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
TAG, "startTV assumes that ChannelDataManager is already loaded.");
if (mTvView.isPlaying()) {
// TV has already started.
- if (channelUri == null) {
+ if (channelUri == null || channelUri.equals(mChannelTuner.getCurrentChannelUri())) {
// Simply adjust the volume without tune.
setVolumeByAudioFocusStatus();
return;
}
- if (channelUri.equals(mChannelTuner.getCurrentChannelUri())) {
- // The requested channel is already tuned.
- setVolumeByAudioFocusStatus();
- return;
- }
stopTv();
}
if (mChannelTuner.getCurrentChannel() != null) {
@@ -972,12 +1029,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mTvView.start(mTvInputManagerHelper);
setVolumeByAudioFocusStatus();
- if (mRecordingUri != null) {
- playRecording(mRecordingUri);
- mRecordingUri = null;
- } else {
- tune();
- }
+ tune();
}
@Override
@@ -1116,16 +1168,19 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return mOverlayManager;
}
+ /**
+ * Returns the {@link ConflictChecker}.
+ */
+ @Nullable
+ public ConflictChecker getDvrConflictChecker() {
+ return mDvrConflictChecker;
+ }
+
public Channel getCurrentChannel() {
- return mTvView.isRecordingPlayback() ? mTvView.getCurrentChannel()
- : mChannelTuner.getCurrentChannel();
+ return mChannelTuner.getCurrentChannel();
}
public long getCurrentChannelId() {
- if (mTvView.isRecordingPlayback()) {
- Channel channel = mTvView.getCurrentChannel();
- return channel == null ? Channel.INVALID_ID : channel.getId();
- }
return mChannelTuner.getCurrentChannelId();
}
@@ -1139,34 +1194,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
/**
* Returns the current program which the user is watching right now.<p>
*
- * If the time shifting is available, it can be a past program.
+ * It might be a live program. If the time shifting is available, it can be a past program, too.
*/
public Program getCurrentProgram() {
- return getCurrentProgram(true);
- }
-
- /**
- * Returns {@code true}, if this view is the recording playback mode.
- */
- public boolean isRecordingPlayback() {
- return mTvView.isRecordingPlayback();
- }
-
- /**
- * Returns the recording which is being played right now.
- */
- public RecordedProgram getPlayingRecordedProgram() {
- return mTvView.getPlayingRecordedProgram();
- }
-
- /**
- * Returns the current program which the user is watching right now.<p>
- *
- * @param applyTimeShifted If it is true and the time shifting is available, it can be
- * a past program.
- */
- public Program getCurrentProgram(boolean applyTimeShifted) {
- if (applyTimeShifted && mTimeShiftManager.isAvailable()) {
+ if (!isChannelChangeKeyDownReceived() && mTimeShiftManager.isAvailable()) {
+ // We shouldn't get current program from TimeShiftManager during channel tunning
return mTimeShiftManager.getCurrentProgram();
}
return mProgramDataManager.getCurrentProgram(getCurrentChannelId());
@@ -1185,7 +1217,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return System.currentTimeMillis();
}
- public Channel getBrowsableChannel() {
+ private Channel getBrowsableChannel() {
// TODO: mChannelMap could be dirty for a while when the browsablity of channels
// are changed. In that case, we shouldn't use the value from mChannelMap.
Channel curChannel = mChannelTuner.getCurrentChannel();
@@ -1228,7 +1260,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
public void showMerchantCollection() {
- startActivitySafe(OnboardingUtils.PLAY_STORE_INTENT);
+ startActivitySafe(OnboardingUtils.ONLINE_STORE_INTENT);
}
/**
@@ -1353,15 +1385,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
@Override
- public View findViewById(int id) {
- // In order to locate fragments in non-application window, we should override findViewById.
- // Internally, Activity.findViewById is called to attach a view of a fragment into its
- // container. Without the override, we'll get crash during the fragment attachment.
- View v = mOverlayRootView != null ? mOverlayRootView.findViewById(id) : null;
- return v == null ? super.findViewById(id) : v;
- }
-
- @Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (SystemProperties.LOG_KEYEVENT.getValue()) Log.d(TAG, "dispatchKeyEvent(" + event + ")");
// If an activity is closed on a back key down event, back key down events with none zero
@@ -1381,8 +1404,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
// When side panel is closing, it has the focus.
// Keep the focus, but just don't deliver the key events.
- if ((mOverlayRootView.hasFocusable()
- && !mOverlayManager.getSideFragmentManager().isHiding())
+ if ((mContentView.hasFocusable() && !mOverlayManager.getSideFragmentManager().isHiding())
|| mOverlayManager.getSideFragmentManager().isActive()) {
return super.dispatchKeyEvent(event);
}
@@ -1454,13 +1476,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
}
- if (CommonFeatures.DVR.isEnabled(this) && BuildCompat.isAtLeastN()) {
- mRecordingUri = intent.getParcelableExtra(Utils.EXTRA_KEY_RECORDING_URI);
- if (mRecordingUri != null) {
- return true;
- }
- }
-
// TODO: remove the checkState once N API is finalized.
SoftPreconditions.checkState(TvInputManager.ACTION_SETUP_INPUTS.equals(
"android.media.tv.action.SETUP_INPUTS"));
@@ -1709,7 +1724,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
/**
* Says {@code text} when accessibility is turned on.
*/
- public void sendAccessibilityText(String text) {
+ private void sendAccessibilityText(String text) {
if (mAccessibilityManager.isEnabled()) {
AccessibilityEvent event = AccessibilityEvent.obtain();
event.setClassName(getClass().getName());
@@ -1720,17 +1735,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
}
- private void playRecording(Uri recordingUri) {
- mTvView.playRecording(recordingUri, mOnTuneListener);
- mOnTuneListener.onPlayRecording();
- updateChannelBannerAndShowIfNeeded(UPDATE_CHANNEL_BANNER_REASON_TUNE);
- }
-
private void tune() {
if (DEBUG) Log.d(TAG, "tune()");
mTuneDurationTimer.start();
- lazyInitializeIfNeeded(LAZY_INITIALIZATION_DELAY);
+ lazyInitializeIfNeeded();
// Prerequisites to be able to tune.
if (mInputIdUnderSetup != null) {
@@ -1742,7 +1751,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
if (!mChannelTuner.isCurrentChannelPassthrough()) {
if (mTvInputManagerHelper.getTunerTvInputSize() == 0) {
Toast.makeText(this, R.string.msg_no_input, Toast.LENGTH_SHORT).show();
- // TODO: Direct the user to a Play Store landing page for TvInputService apps.
finish();
return;
}
@@ -1755,9 +1763,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
if (mChannelDataManager.getChannelCount() > 0) {
mOverlayManager.showIntroDialog();
- } else if (!Features.ONBOARDING_EXPERIENCE.isEnabled(this)) {
- mOverlayManager.showSetupFragment();
- return;
}
}
if (!TvCommonUtils.isRunningInTest() && mShowNewSourcesFragment
@@ -1821,23 +1826,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mLastAllowedRatingForCurrentChannel = null;
}
mHandler.removeMessages(MSG_UPDATE_CHANNEL_BANNER_BY_INFO_UPDATE);
- if (mAccessibilityManager.isEnabled()) {
- // For every tune, we need to inform the tuned channel or input to a user,
- // if Talkback is turned on.
- AccessibilityEvent event = AccessibilityEvent.obtain();
- event.setClassName(getClass().getName());
- event.setPackageName(getPackageName());
- event.setEventType(AccessibilityEvent.TYPE_ANNOUNCEMENT);
- if (TvContract.isChannelUriForPassthroughInput(channel.getUri())) {
- TvInputInfo input = mTvInputManagerHelper.getTvInputInfo(channel.getInputId());
- event.getText().add(Utils.loadLabel(this, input));
- } else if (TextUtils.isEmpty(channel.getDisplayName())) {
- event.getText().add(channel.getDisplayNumber());
- } else {
- event.getText().add(channel.getDisplayNumber() + " " + channel.getDisplayName());
- }
- mAccessibilityManager.sendAccessibilityEvent(event);
- }
+ // For every tune, we need to inform the tuned channel or input to a user,
+ // if Talkback is turned on.
+ sendAccessibilityText(!mChannelTuner.isCurrentChannelPassthrough() ?
+ Utils.loadLabel(this, mTvInputManagerHelper.getTvInputInfo(channel.getInputId()))
+ : channel.getDisplayText());
boolean success = mTvView.tuneTo(channel, mTuneParams, mOnTuneListener);
mOnTuneListener.onTune(channel, isUnderShrunkenTvView());
@@ -1870,20 +1863,35 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
updateMediaSession();
}
+ // Runs the runnable after the activity is attached to window to show the fragment transition
+ // animation.
+ // The runnable runs asynchronously to show the animation a little better even when system is
+ // busy at the moment it is called.
+ // If the activity is paused shortly, runnable may not be called because all the fragments
+ // should be closed when the activity is paused.
private void runAfterAttachedToWindow(final Runnable runnable) {
- if (mOverlayRootView.isLaidOut()) {
- runnable.run();
- } else {
- mOverlayRootView.addOnAttachStateChangeListener(new View.OnAttachStateChangeListener() {
- @Override
- public void onViewAttachedToWindow(View v) {
- mOverlayRootView.removeOnAttachStateChangeListener(this);
+ final Runnable runOnlyIfActivityIsResumed = new Runnable() {
+ @Override
+ public void run() {
+ if (mActivityResumed) {
runnable.run();
}
+ }
+ };
+ if (mContentView.isAttachedToWindow()) {
+ mHandler.post(runOnlyIfActivityIsResumed);
+ } else {
+ mContentView.getViewTreeObserver().addOnWindowAttachListener(
+ new ViewTreeObserver.OnWindowAttachListener() {
+ @Override
+ public void onWindowAttached() {
+ mContentView.getViewTreeObserver().removeOnWindowAttachListener(this);
+ mHandler.post(runOnlyIfActivityIsResumed);
+ }
- @Override
- public void onViewDetachedFromWindow(View v) { }
- });
+ @Override
+ public void onWindowDetached() { }
+ });
}
}
@@ -1905,82 +1913,108 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return;
}
- final Program program = getCurrentProgram();
- String cardTitleText = program == null ? null : program.getTitle();
+ final Program currentProgram = getCurrentProgram();
+ String cardTitleText = null;
+ String posterArtUri = null;
+ if (currentProgram != null) {
+ cardTitleText = currentProgram.getTitle();
+ posterArtUri = currentProgram.getPosterArtUri();
+ }
if (TextUtils.isEmpty(cardTitleText)) {
- cardTitleText = getCurrentChannel().getDisplayName();
+ cardTitleText = getCurrentChannelName();
}
updateMediaMetadata(cardTitleText, null);
setMediaSessionPlaybackState(true);
- if (program != null && program.getPosterArtUri() != null) {
- program.loadPosterArt(MainActivity.this, mNowPlayingCardWidth, mNowPlayingCardHeight,
- createProgramPosterArtCallback(MainActivity.this, program));
- } else {
- updateMediaMetadataWithAlternativeArt(program);
+ if (posterArtUri == null) {
+ posterArtUri = TvContract.buildChannelLogoUri(getCurrentChannelId()).toString();
}
-
+ updatePosterArt(getCurrentChannel(), currentProgram, cardTitleText, null, posterArtUri);
mMediaSession.setActive(true);
}
- private static ImageLoader.ImageLoaderCallback<MainActivity> createProgramPosterArtCallback(
- MainActivity mainActivity, final Program program) {
- return new ImageLoader.ImageLoaderCallback<MainActivity>(mainActivity) {
- @Override
- public void onBitmapLoaded(MainActivity mainActivity, @Nullable Bitmap posterArt) {
- if (program != mainActivity.getCurrentProgram()
- || mainActivity.getCurrentChannel() == null) {
- return;
- }
- mainActivity.updateProgramPosterArt(program, posterArt);
- }
- };
- }
-
- private void updateProgramPosterArt(Program program, @Nullable Bitmap posterArt) {
- if (getCurrentChannel() == null) {
- return;
- }
+ private void updatePosterArt(Channel currentChannel, Program currentProgram,
+ String cardTitleText, @Nullable Bitmap posterArt, @Nullable String posterArtUri) {
if (posterArt != null) {
- String cardTitleText = program == null ? null : program.getTitle();
- if (TextUtils.isEmpty(cardTitleText)) {
- cardTitleText = getCurrentChannel().getDisplayName();
- }
updateMediaMetadata(cardTitleText, posterArt);
+ } else if (posterArtUri != null) {
+ ImageLoader.loadBitmap(this, posterArtUri, mNowPlayingCardWidth, mNowPlayingCardHeight,
+ new ProgramPosterArtCallback(this, currentChannel,
+ currentProgram, cardTitleText));
} else {
- updateMediaMetadataWithAlternativeArt(program);
+ updateMediaMetadata(cardTitleText, R.drawable.default_now_card);
}
}
- private void updateMediaMetadata(String title, Bitmap posterArt) {
- MediaMetadata.Builder builder = new MediaMetadata.Builder();
- builder.putString(MediaMetadata.METADATA_KEY_TITLE, title);
- if (posterArt != null) {
- builder.putBitmap(MediaMetadata.METADATA_KEY_ART, posterArt);
+ private static class ProgramPosterArtCallback extends
+ ImageLoader.ImageLoaderCallback<MainActivity> {
+ private final Channel mChannel;
+ private final Program mProgram;
+ private final String mCardTitleText;
+
+ public ProgramPosterArtCallback(MainActivity mainActivity, Channel channel, Program program,
+ String cardTitleText) {
+ super(mainActivity);
+ mChannel = channel;
+ mProgram = program;
+ mCardTitleText = cardTitleText;
}
- mMediaSession.setMetadata(builder.build());
+
+ @Override
+ public void onBitmapLoaded(MainActivity mainActivity, @Nullable Bitmap posterArt) {
+ if (mainActivity.isNowPlayingProgram(mChannel, mProgram)) {
+ mainActivity.updatePosterArt(mChannel, mProgram, mCardTitleText, posterArt, null);
+ }
+ }
+ }
+
+ private boolean isNowPlayingProgram(Channel channel, Program program) {
+ return program == null ? (channel != null && getCurrentProgram() == null
+ && channel.equals(getCurrentChannel())) : program.equals(getCurrentProgram());
}
- private void updateMediaMetadataWithAlternativeArt(final Program program) {
+ private void updateMediaMetadata(final String title, final Bitmap posterArt) {
+ new AsyncTask<Void, Void, Void> () {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ builder.putString(MediaMetadata.METADATA_KEY_TITLE, title);
+ if (posterArt != null) {
+ builder.putBitmap(MediaMetadata.METADATA_KEY_ART, posterArt);
+ }
+ mMediaSession.setMetadata(builder.build());
+ return null;
+ }
+ }.execute();
+ }
+
+ private void updateMediaMetadata(final String title, final int imageResId) {
+ new AsyncTask<Void, Void, Void> () {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ builder.putString(MediaMetadata.METADATA_KEY_TITLE, title);
+ Bitmap posterArt = BitmapFactory.decodeResource(getResources(), imageResId);
+ if (posterArt != null) {
+ builder.putBitmap(MediaMetadata.METADATA_KEY_ART, posterArt);
+ }
+ mMediaSession.setMetadata(builder.build());
+ return null;
+ }
+ }.execute();
+ }
+
+ private String getCurrentChannelName() {
Channel channel = getCurrentChannel();
- if (channel == null || program != getCurrentProgram()) {
- return;
+ if (channel == null) {
+ return "";
}
-
- String cardTitleText;
if (channel.isPassthrough()) {
TvInputInfo input = getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
- cardTitleText = Utils.loadLabel(this, input);
+ return Utils.loadLabel(this, input);
} else {
- cardTitleText = program == null ? null : program.getTitle();
- if (TextUtils.isEmpty(cardTitleText)) {
- cardTitleText = channel.getDisplayName();
- }
+ return channel.getDisplayName();
}
-
- Bitmap posterArt = BitmapFactory.decodeResource(
- getResources(), R.drawable.default_now_card);
- updateMediaMetadata(cardTitleText, posterArt);
}
private void setMediaSessionPlaybackState(boolean isPlaying) {
@@ -2055,7 +2089,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
private void updateChannelBannerAndShowIfNeeded(@ChannelBannerUpdateReason int reason) {
if(DEBUG) Log.d(TAG, "updateChannelBannerAndShowIfNeeded(reason=" + reason + ")");
- if (!mChannelTuner.isCurrentChannelPassthrough() || mTvView.isRecordingPlayback()) {
+ if (!mChannelTuner.isCurrentChannelPassthrough()) {
int lockType = ChannelBannerView.LOCK_NONE;
if (mTvView.isScreenBlocked()) {
lockType = ChannelBannerView.LOCK_CHANNEL_INFO;
@@ -2261,6 +2295,13 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
@Override
protected void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy()");
+ SideFragment.releasePreloadedRecycledViews();
+ if (mTvView != null) {
+ mTvView.release();
+ }
+ if (mPipView != null) {
+ mPipView.release();
+ }
if (mChannelTuner != null) {
mChannelTuner.removeListener(mChannelTunerListener);
mChannelTuner.stop();
@@ -2299,7 +2340,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mChannelStatusRecurringRunner.stop();
mChannelStatusRecurringRunner = null;
}
- if (mTvInputManagerHelper != null) {
+ if (mTvInputManagerHelper != null && Features.TUNER.isEnabled(this)) {
mTvInputManagerHelper.removeCallback(mTvInputCallback);
}
super.onDestroy();
@@ -2333,9 +2374,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
case KeyEvent.KEYCODE_DPAD_UP:
if (event.getRepeatCount() == 0
&& mChannelTuner.getBrowsableChannelCount() > 0) {
- moveToAdjacentChannel(true, false);
+ // message sending should be done before moving channel, because we use the
+ // existence of message to decide if users are switching channel.
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHANNEL_UP_PRESSED,
System.currentTimeMillis()), CHANNEL_CHANGE_INITIAL_DELAY_MILLIS);
+ moveToAdjacentChannel(true, false);
mTracker.sendChannelUp();
}
return true;
@@ -2343,9 +2386,11 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
case KeyEvent.KEYCODE_DPAD_DOWN:
if (event.getRepeatCount() == 0
&& mChannelTuner.getBrowsableChannelCount() > 0) {
- moveToAdjacentChannel(false, false);
+ // message sending should be done before moving channel, because we use the
+ // existence of message to decide if users are switching channel.
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CHANNEL_DOWN_PRESSED,
System.currentTimeMillis()), CHANNEL_CHANGE_INITIAL_DELAY_MILLIS);
+ moveToAdjacentChannel(false, false);
mTracker.sendChannelDown();
}
return true;
@@ -2362,14 +2407,13 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
* A KEYCODE_MEDIA_AUDIO_TRACK
* D debug: show debug options
* E updateChannelBannerAndShowIfNeeded
+ * G debug: refresh cloud epg
* I KEYCODE_TV_INPUT
* O debug: show display mode option
* P debug: togglePipView
* S KEYCODE_CAPTIONS: select subtitle
* W debug: toggle screen size
* V KEYCODE_MEDIA_RECORD debug: record the current channel for 30 sec
- * X KEYCODE_BUTTON_X KEYCODE_PROG_BLUE debug: record current channel for a few minutes
- * Y KEYCODE_BUTTON_Y KEYCODE_PROG_GREEN debug: Play a recording
*/
if (SystemProperties.LOG_KEYEVENT.getValue()) {
Log.d(TAG, "onKeyUp(" + keyCode + ", " + event + ")");
@@ -2428,6 +2472,13 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
switch (keyCode) {
case KeyEvent.KEYCODE_DPAD_RIGHT:
+ if (!mTvView.isVideoAvailable()
+ && mTvView.getVideoUnavailableReason()
+ == TunableTvView.VIDEO_UNAVAILABLE_REASON_NO_RESOURCE) {
+ DvrUiHelper.startSchedulesActivityForTuneConflict(this,
+ mChannelTuner.getCurrentChannel());
+ return true;
+ }
if (!PermissionUtils.hasModifyParentalControls(this)) {
// TODO: support this feature for non-system LC app. b/23939816
return true;
@@ -2464,7 +2515,9 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
false);
}
return true;
-
+ case KeyEvent.KEYCODE_WINDOW:
+ enterPictureInPictureMode();
+ return true;
case KeyEvent.KEYCODE_ENTER:
case KeyEvent.KEYCODE_NUMPAD_ENTER:
case KeyEvent.KEYCODE_E:
@@ -2481,8 +2534,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
updateChannelBannerAndShowIfNeeded(UPDATE_CHANNEL_BANNER_REASON_FORCE_SHOW);
}
if (keyCode != KeyEvent.KEYCODE_E) {
- mOverlayManager.showMenu(mTvView.isRecordingPlayback()
- ? Menu.REASON_RECORDING_PLAYBACK : Menu.REASON_NONE);
+ mOverlayManager.showMenu(Menu.REASON_NONE);
}
return true;
case KeyEvent.KEYCODE_CHANNEL_UP:
@@ -2515,9 +2567,62 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
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();
+ } else {
+ if (!DvrUiHelper.checkStorageStatusAndShowErrorMessage(this,
+ currentChannel.getInputId())) {
+ return true;
+ }
+ Program program = mProgramDataManager
+ .getCurrentProgram(currentChannel.getId());
+ if (program == null) {
+ DvrUiHelper
+ .showChannelRecordDurationOptions(this, currentChannel);
+ } else if (DvrUiHelper.handleCreateSchedule(this, program)) {
+ String msg = getString(
+ R.string.dvr_msg_current_program_scheduled,
+ program.getTitle(), Utils.toTimeString(
+ program.getEndTimeUtcMillis(), false));
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
+ }
+ }
+ } 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;
+ }
}
}
- if (SystemProperties.USE_DEBUG_KEYS.getValue()) {
+ if (keyCode == KeyEvent.KEYCODE_WINDOW) {
+ // Consumes the PIP button to prevent entering PIP mode
+ // in case that TV isn't showing properly (e.g. no browsable channel)
+ return true;
+ }
+ if (SystemProperties.USE_DEBUG_KEYS.getValue() || BuildConfig.ENG) {
switch (keyCode) {
case KeyEvent.KEYCODE_W: {
mDebugNonFullSizeScreen = !mDebugNonFullSizeScreen;
@@ -2551,57 +2656,9 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mOverlayManager.getSideFragmentManager().show(new DisplayModeFragment());
return true;
}
-
case KeyEvent.KEYCODE_D:
- mOverlayManager.getSideFragmentManager().show(new DebugOptionFragment());
- return true;
-
- case KeyEvent.KEYCODE_MEDIA_RECORD: // TODO(DVR) handle with debug_keys set
- case KeyEvent.KEYCODE_V: {
- DvrManager dvrManager = TvApplication.getSingletons(this).getDvrManager();
- long startTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(5);
- long endTime = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(35);
- dvrManager.addSchedule(getCurrentChannel(), startTime, endTime);
+ mOverlayManager.getSideFragmentManager().show(new DeveloperOptionFragment());
return true;
- }
- case KeyEvent.KEYCODE_PROG_BLUE:
- case KeyEvent.KEYCODE_BUTTON_X:
- case KeyEvent.KEYCODE_X: {
- if (CommonFeatures.DVR.isEnabled(this)) {
- Channel channel = mTvView.getCurrentChannel();
- long channelId = channel.getId();
- Program p = mProgramDataManager.getCurrentProgram(channelId);
- if (p == null) {
- long now = System.currentTimeMillis();
- mDvrManager
- .addSchedule(channel, now, now + TimeUnit.MINUTES.toMillis(1));
- } else {
- mDvrManager.addSchedule(p,
- mDvrManager.getScheduledRecordingsThatConflict(p));
- }
- return true;
- }
- }
- case KeyEvent.KEYCODE_PROG_YELLOW:
- case KeyEvent.KEYCODE_BUTTON_Y:
- case KeyEvent.KEYCODE_Y: {
- if (CommonFeatures.DVR.isEnabled(this) && BuildCompat.isAtLeastN()) {
- // TODO(DVR) only get finished recordings.
- List<RecordedProgram> recordedPrograms = mDvrDataManager
- .getRecordedPrograms();
- Log.d(TAG, "Found " + recordedPrograms.size() + " recordings");
- if (recordedPrograms.isEmpty()) {
- Toast.makeText(this, "No finished recording to play", Toast.LENGTH_LONG)
- .show();
- } else {
- RecordedProgram r = recordedPrograms.get(0);
- Intent intent = new Intent(this, DvrPlayActivity.class);
- intent.putExtra(ScheduledRecording.RECORDING_ID_EXTRA, r.getId());
- startActivity(intent);
- }
- return true;
- }
- }
}
}
return super.onKeyUp(keyCode, event);
@@ -2661,6 +2718,13 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
});
}
+ @Override
+ public void onWindowFocusChanged(boolean hasFocus) {
+ if (!hasFocus) {
+ finishChannelChangeIfNeeded();
+ }
+ }
+
public void togglePipView() {
enablePipView(!mPipEnabled, true);
mOverlayManager.getMenu().update();
@@ -2681,7 +2745,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
startPip(true);
}
- public void enablePipView(boolean enable, boolean fromUserInteraction) {
+ private void enablePipView(boolean enable, boolean fromUserInteraction) {
if (enable == mPipEnabled) {
return;
}
@@ -2774,7 +2838,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return mChannelTuner.isCurrentChannelPassthrough() && !mPipEnabled;
}
- public void tuneToLastWatchedChannelForTunerInput() {
+ private void tuneToLastWatchedChannelForTunerInput() {
if (!mChannelTuner.isCurrentChannelPassthrough()) {
return;
}
@@ -2930,14 +2994,13 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
@Override
- public void startActivity(Intent intent) {
- mOtherActivityLaunched = true;
- super.startActivity(intent);
- }
-
- @Override
public void startActivityForResult(Intent intent, int requestCode) {
mOtherActivityLaunched = true;
+ if (intent.getCategories() == null
+ || !intent.getCategories().contains(Intent.CATEGORY_HOME)) {
+ // Workaround b/30150267
+ requestVisibleBehind(false);
+ }
super.startActivityForResult(intent, requestCode);
}
@@ -2949,7 +3012,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return mTvView.getSelectedTrack(type);
}
- public void selectTrack(int type, TvTrackInfo track) {
+ private void selectTrack(int type, TvTrackInfo track) {
mTvView.selectTrack(type, track == null ? null : track.getId());
if (type == TvTrackInfo.TYPE_AUDIO) {
mTvOptionsManager.onMultiAudioChanged(track == null ? null :
@@ -3021,6 +3084,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
int stringId;
switch (info.getVideoUnavailableReason()) {
case TunableTvView.VIDEO_UNAVAILABLE_REASON_NOT_TUNED:
+ case TunableTvView.VIDEO_UNAVAILABLE_REASON_NO_RESOURCE:
case TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING:
case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING:
case TvInputManager.VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY:
@@ -3050,6 +3114,31 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
return mCaptionSettings;
}
+ /**
+ * Adds the {@link OnActionClickListener}.
+ */
+ public void addOnActionClickListener(OnActionClickListener listener) {
+ mOnActionClickListeners.add(listener);
+ }
+
+ /**
+ * Removes the {@link OnActionClickListener}.
+ */
+ public void removeOnActionClickListener(OnActionClickListener listener) {
+ mOnActionClickListeners.remove(listener);
+ }
+
+ @Override
+ public boolean onActionClick(String category, int actionId, Bundle params) {
+ // There should be only one action listener per an action.
+ for (OnActionClickListener l : mOnActionClickListeners) {
+ if (l.onActionClick(category, actionId, params)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
// 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() {
@@ -3061,7 +3150,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
}
// Lazy initialization
- private void lazyInitializeIfNeeded(long delay) {
+ private void lazyInitializeIfNeeded() {
// Already initialized.
if (mLazyInitialized) {
return;
@@ -3071,10 +3160,12 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
- initAnimations();
- initSideFragments();
+ if (mActivityStarted) {
+ initAnimations();
+ initSideFragments();
+ }
}
- }, delay);
+ }, LAZY_INITIALIZATION_DELAY);
}
private void initAnimations() {
@@ -3104,13 +3195,17 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
switch (msg.what) {
case MSG_CHANNEL_DOWN_PRESSED:
long startTime = (Long) msg.obj;
- mainActivity.moveToAdjacentChannel(false, true);
+ // message re-sending should be done before moving channel, because we use the
+ // existence of message to decide if users are switching channel.
sendMessageDelayed(Message.obtain(msg), getDelay(startTime));
+ mainActivity.moveToAdjacentChannel(false, true);
break;
case MSG_CHANNEL_UP_PRESSED:
startTime = (Long) msg.obj;
- mainActivity.moveToAdjacentChannel(true, true);
+ // message re-sending should be done before moving channel, because we use the
+ // existence of message to decide if users are switching channel.
sendMessageDelayed(Message.obtain(msg), getDelay(startTime));
+ mainActivity.moveToAdjacentChannel(true, true);
break;
case MSG_UPDATE_CHANNEL_BANNER_BY_INFO_UPDATE:
mainActivity.updateChannelBannerAndShowIfNeeded(
@@ -3142,13 +3237,6 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mWasUnderShrunkenTvView = wasUnderShrukenTvView;
}
- private void onPlayRecording() {
- mStreamInfoUpdateTimeThresholdMs =
- System.currentTimeMillis() + FIRST_STREAM_INFO_UPDATE_DELAY_MILLIS;
- mChannel = null;
- mWasUnderShrunkenTvView = false;
- }
-
@Override
public void onUnexpectedStop(Channel channel) {
stopTv();
@@ -3157,8 +3245,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
@Override
public void onTuneFailed(Channel channel) {
- Log.w(TAG, "Failed to tune to channel " + channel.getId()
- + "@" + channel.getInputId());
+ Log.w(TAG, "onTuneFailed(" + channel + ")");
if (mTvView.isFadedOut()) {
mTvView.removeFadeEffect();
}
@@ -3232,7 +3319,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
mUnlockAllowedRatingBeforeShrunken = isUnderShrunkenTvView();
mTvView.unblockContent(rating);
}
-
+ mChannelBannerView.setBlockingContentRating(rating);
updateChannelBannerAndShowIfNeeded(UPDATE_CHANNEL_BANNER_REASON_LOCK_OR_UNLOCK);
mTvViewUiManager.fadeInTvView();
}
@@ -3242,6 +3329,7 @@ public class MainActivity extends Activity implements AudioManager.OnAudioFocusC
if (!isUnderShrunkenTvView()) {
mUnlockAllowedRatingBeforeShrunken = false;
}
+ mChannelBannerView.setBlockingContentRating(null);
updateChannelBannerAndShowIfNeeded(UPDATE_CHANNEL_BANNER_REASON_LOCK_OR_UNLOCK);
}
}
diff --git a/src/com/android/tv/MainActivityWrapper.java b/src/com/android/tv/MainActivityWrapper.java
index 82e96d14..01733255 100644
--- a/src/com/android/tv/MainActivityWrapper.java
+++ b/src/com/android/tv/MainActivityWrapper.java
@@ -19,7 +19,6 @@ package com.android.tv;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.UiThread;
import android.util.ArraySet;
import com.android.tv.data.Channel;
@@ -54,7 +53,6 @@ public final class MainActivityWrapper {
/**
* Sets the currently created main activity instance.
*/
- @UiThread
public void onMainActivityCreated(@NonNull MainActivity activity) {
mActivity = activity;
}
@@ -62,7 +60,6 @@ public final class MainActivityWrapper {
/**
* Unsets the main activity instance.
*/
- @UiThread
public void onMainActivityDestroyed(@NonNull MainActivity activity) {
if (mActivity != activity) {
mActivity = null;
@@ -104,7 +101,6 @@ public final class MainActivityWrapper {
/**
* Adds OnCurrentChannelChangeListener.
*/
- @UiThread
public void addOnCurrentChannelChangeListener(OnCurrentChannelChangeListener listener) {
mListeners.add(listener);
}
@@ -112,7 +108,6 @@ public final class MainActivityWrapper {
/**
* Removes OnCurrentChannelChangeListener.
*/
- @UiThread
public void removeOnCurrentChannelChangeListener(OnCurrentChannelChangeListener listener) {
mListeners.remove(listener);
}
diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java
index e6373505..8a263a26 100644
--- a/src/com/android/tv/SetupPassthroughActivity.java
+++ b/src/com/android/tv/SetupPassthroughActivity.java
@@ -25,8 +25,11 @@ import android.util.Log;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvCommonConstants;
+import com.android.tv.data.epg.EpgFetcher;
+import com.android.tv.experiments.Experiments;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
+import com.android.tv.util.Utils;
/**
* An activity to launch a TV input setup activity.
@@ -74,7 +77,25 @@ public class SetupPassthroughActivity extends Activity {
Bundle extras = intent.getExtras();
extras.remove(TvCommonConstants.EXTRA_SETUP_INTENT);
setupIntent.putExtras(extras);
- startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY);
+ try {
+ startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "Can't find activity: " + setupIntent.getComponent());
+ finish();
+ return;
+ }
+ if (Utils.isInternalTvInput(this, mTvInputInfo.getId()) && Experiments.CLOUD_EPG.get()) {
+ EpgFetcher.getInstance(this).stop();
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mTvInputInfo != null && Utils.isInternalTvInput(this, mTvInputInfo.getId())
+ && Experiments.CLOUD_EPG.get()) {
+ EpgFetcher.getInstance(this).start();
+ }
+ super.onDestroy();
}
@Override
diff --git a/src/com/android/tv/TimeShiftManager.java b/src/com/android/tv/TimeShiftManager.java
index a231c29d..2d6d45c4 100644
--- a/src/com/android/tv/TimeShiftManager.java
+++ b/src/com/android/tv/TimeShiftManager.java
@@ -16,6 +16,7 @@
package com.android.tv;
+import android.annotation.SuppressLint;
import android.content.ContentResolver;
import android.content.Context;
import android.os.Handler;
@@ -30,7 +31,6 @@ import android.util.Range;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.WeakHandler;
-import com.android.tv.common.recording.RecordedProgram;
import com.android.tv.data.Channel;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
import com.android.tv.data.Program;
@@ -38,6 +38,7 @@ import com.android.tv.data.ProgramDataManager;
import com.android.tv.ui.TunableTvView;
import com.android.tv.ui.TunableTvView.TimeShiftListener;
import com.android.tv.util.AsyncDbTask;
+import com.android.tv.util.TimeShiftUtils;
import com.android.tv.util.Utils;
import java.lang.annotation.Retention;
@@ -77,10 +78,6 @@ public class TimeShiftManager {
public static final int PLAY_SPEED_4X = 4;
public static final int PLAY_SPEED_5X = 5;
- private static final int SHORT_PROGRAM_THRESHOLD_MILLIS = 46 * 60 * 1000; // 46 mins.
- private static final int[] SHORT_PROGRAM_SPEED_FACTORS = new int[] {2, 4, 12, 48};
- private static final int[] LONG_PROGRAM_SPEED_FACTORS = new int[] {2, 8, 32, 128};
-
@Retention(RetentionPolicy.SOURCE)
@IntDef({PLAY_DIRECTION_FORWARD, PLAY_DIRECTION_BACKWARD})
public @interface PlayDirection{}
@@ -109,6 +106,9 @@ public class TimeShiftManager {
private static final long PREFETCH_TIME_OFFSET_FROM_PROGRAM_END = TimeUnit.MINUTES.toMillis(1);
private static final long PREFETCH_DURATION_FOR_NEXT = TimeUnit.HOURS.toMillis(2);
+ private static final long ALLOWED_START_TIME_OFFSET = TimeUnit.DAYS.toMillis(14);
+ private static final long TWO_WEEKS_MS = TimeUnit.DAYS.toMillis(14);
+
@VisibleForTesting
static final long REQUEST_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(3);
@@ -143,9 +143,9 @@ public class TimeShiftManager {
* 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 must be three times longer than {@link #REQUEST_CURRENT_POSITION_INTERVAL} at least.
+ * It's the same {@link #REQUEST_CURRENT_POSITION_INTERVAL}.
*/
- private static final long RECORDING_BOUNDARY_THRESHOLD = 3 * REQUEST_CURRENT_POSITION_INTERVAL;
+ private static final long RECORDING_BOUNDARY_THRESHOLD = REQUEST_CURRENT_POSITION_INTERVAL;
private final PlayController mPlayController;
private final ProgramManager mProgramManager;
@@ -178,12 +178,6 @@ public class TimeShiftManager {
mProgramManager = new ProgramManager(programDataManager);
mTracker = tracker;
mOnCurrentProgramUpdatedListener = onCurrentProgramUpdatedListener;
- tvView.setOnScreenBlockedListener(new TunableTvView.OnScreenBlockingChangedListener() {
- @Override
- public void onScreenBlockingChanged(boolean blocked) {
- mPlayController.onAvailabilityChanged();
- }
- });
}
/**
@@ -448,6 +442,8 @@ public class TimeShiftManager {
}
private void updateCurrentProgram() {
+ SoftPreconditions.checkState(isAvailable(), TAG, "Time shift is not available");
+ SoftPreconditions.checkState(mCurrentPositionMediator.mCurrentPositionMs != INVALID_TIME);
Program currentProgram = getProgramAt(mCurrentPositionMediator.mCurrentPositionMs);
if (!Program.isValid(currentProgram)) {
currentProgram = null;
@@ -467,13 +463,6 @@ public class TimeShiftManager {
}
/**
- * Checks whether the TV is playing the recorded content.
- */
- public boolean isRecordingPlayback() {
- return mPlayController.mRecordingPlayback;
- }
-
- /**
* Returns {@code true} if the trick play is available and it's playing to the forward direction
* with normal speed, otherwise {@code false}.
*/
@@ -506,9 +495,9 @@ public class TimeShiftManager {
}
void onAvailabilityChanged() {
+ mCurrentPositionMediator.initialize(mPlayController.mRecordStartTimeMs);
mProgramManager.onAvailabilityChanged(mPlayController.mAvailable,
- mPlayController.mRecordingPlayback ? null : mPlayController.getCurrentChannel(),
- mPlayController.mRecordStartTimeMs);
+ mPlayController.getCurrentChannel(), mPlayController.mRecordStartTimeMs);
updateActions();
// Availability change notification should be always sent
// even if mNotificationEnabled is false.
@@ -564,28 +553,19 @@ public class TimeShiftManager {
}
private int getPlaybackSpeed() {
- int[] playbackSpeedList;
- if (getCurrentProgram() == null || getCurrentProgram().getEndTimeUtcMillis()
- - getCurrentProgram().getStartTimeUtcMillis() > SHORT_PROGRAM_THRESHOLD_MILLIS) {
- playbackSpeedList = LONG_PROGRAM_SPEED_FACTORS;
+ if (mPlayController.mDisplayedPlaySpeed == PLAY_SPEED_1X) {
+ return 1;
} else {
- playbackSpeedList = SHORT_PROGRAM_SPEED_FACTORS;
- }
- switch (mPlayController.mDisplayedPlaySpeed) {
- case PLAY_SPEED_1X:
- return 1;
- case PLAY_SPEED_2X:
- return playbackSpeedList[0];
- case PLAY_SPEED_3X:
- return playbackSpeedList[1];
- case PLAY_SPEED_4X:
- return playbackSpeedList[2];
- case PLAY_SPEED_5X:
- return playbackSpeedList[3];
- default:
+ long durationMs =
+ (getCurrentProgram() == null ? 0 : getCurrentProgram().getDurationMillis());
+ if (mPlayController.mDisplayedPlaySpeed > PLAY_SPEED_5X) {
Log.w(TAG, "Unknown displayed play speed is chosen : "
+ mPlayController.mDisplayedPlaySpeed);
- return 1;
+ return TimeShiftUtils.getMaxPlaybackSpeed(durationMs);
+ } else {
+ return TimeShiftUtils.getPlaybackSpeed(
+ mPlayController.mDisplayedPlaySpeed - PLAY_SPEED_2X, durationMs);
+ }
}
}
@@ -595,6 +575,7 @@ public class TimeShiftManager {
private class PlayController {
private final TunableTvView mTvView;
+ private long mAvailablityChangedTimeMs;
private long mRecordStartTimeMs;
private long mRecordEndTimeMs;
@@ -603,7 +584,6 @@ public class TimeShiftManager {
@PlayDirection private int mPlayDirection = PLAY_DIRECTION_FORWARD;
private int mPlaybackSpeed;
private boolean mAvailable;
- private boolean mRecordingPlayback;
/**
* Indicates that the trick play is not playing the current time position.
@@ -619,11 +599,25 @@ public class TimeShiftManager {
mTvView.setTimeShiftListener(new TimeShiftListener() {
@Override
public void onAvailabilityChanged() {
+ if (DEBUG) {
+ Log.d(TAG, "onAvailabilityChanged(available="
+ + mTvView.isTimeShiftAvailable() + ")");
+ }
PlayController.this.onAvailabilityChanged();
}
@Override
public void onRecordStartTimeChanged(long recordStartTimeMs) {
+ if (!SoftPreconditions.checkState(mAvailable, TAG,
+ "Trick play is not available.")) {
+ return;
+ }
+ if (recordStartTimeMs < mAvailablityChangedTimeMs - ALLOWED_START_TIME_OFFSET) {
+ Log.e(TAG, "The start time is too earlier than the time of availability: {"
+ + "startTime: " + recordStartTimeMs + ", availability: "
+ + mAvailablityChangedTimeMs);
+ return;
+ }
if (mRecordStartTimeMs == recordStartTimeMs) {
return;
}
@@ -649,7 +643,7 @@ public class TimeShiftManager {
}
void onAvailabilityChanged() {
- boolean newAvailable = mTvView.isTimeShiftAvailable() && !mTvView.isScreenBlocked();
+ boolean newAvailable = mTvView.isTimeShiftAvailable();
if (mAvailable == newAvailable) {
return;
}
@@ -661,27 +655,22 @@ public class TimeShiftManager {
mDisplayedPlaySpeed = PLAY_SPEED_1X;
mPlaybackSpeed = 1;
mPlayDirection = PLAY_DIRECTION_FORWARD;
- mRecordingPlayback = mTvView.isRecordingPlayback();
- if (mRecordingPlayback) {
- RecordedProgram recordedProgram = mTvView.getPlayingRecordedProgram();
- SoftPreconditions.checkNotNull(recordedProgram);
- mIsPlayOffsetChanged = true;
- mRecordStartTimeMs = 0;
- mRecordEndTimeMs = recordedProgram.getDurationMillis();
- } else {
- mIsPlayOffsetChanged = false;
- mRecordStartTimeMs = System.currentTimeMillis();
- mRecordEndTimeMs = CURRENT_TIME;
- }
- mCurrentPositionMediator.initialize(mRecordStartTimeMs);
mHandler.removeMessages(MSG_GET_CURRENT_POSITION);
if (mAvailable) {
+ mAvailablityChangedTimeMs = System.currentTimeMillis();
+ mIsPlayOffsetChanged = false;
+ mRecordStartTimeMs = mAvailablityChangedTimeMs;
+ mRecordEndTimeMs = CURRENT_TIME;
// When the media availability message has come.
mPlayController.setPlayStatus(PLAY_STATUS_PLAYING);
mHandler.sendEmptyMessageDelayed(MSG_GET_CURRENT_POSITION,
REQUEST_CURRENT_POSITION_INTERVAL);
} else {
+ mAvailablityChangedTimeMs = INVALID_TIME;
+ mIsPlayOffsetChanged = false;
+ mRecordStartTimeMs = INVALID_TIME;
+ mRecordEndTimeMs = INVALID_TIME;
// When the tune command is sent.
mPlayController.setPlayStatus(PLAY_STATUS_PAUSED);
}
@@ -806,6 +795,7 @@ public class TimeShiftManager {
}
}
+ @SuppressLint("SwitchIntDef")
private void increaseDisplayedPlaySpeed() {
switch (mDisplayedPlaySpeed) {
case PLAY_SPEED_1X:
@@ -867,7 +857,7 @@ public class TimeShiftManager {
mPrograms.clear();
mEmptyFetchCount = 0;
mChannel = channel;
- if (channel == null || channel.isPassthrough()) {
+ if (channel == null || channel.isPassthrough() || currentPositionMs == INVALID_TIME) {
return;
}
if (available) {
@@ -913,32 +903,14 @@ public class TimeShiftManager {
if (mProgramLoadTask == null || mProgramLoadTask.isCancelled()) {
startNext();
} else {
- switch (mProgramLoadTask.getStatus()) {
- case PENDING:
- if (mProgramLoadTask.overlaps(mProgramLoadQueue)) {
- if (mProgramLoadTask.cancel(true)) {
- mProgramLoadQueue.add(mProgramLoadTask.getPeriod());
- mProgramLoadTask = null;
- startNext();
- }
- }
- break;
- case RUNNING:
- // Remove pending task fully satisfied by the current
- Range<Long> current = mProgramLoadTask.getPeriod();
- Iterator<Range<Long>> i = mProgramLoadQueue.iterator();
- while (i.hasNext()) {
- Range<Long> r = i.next();
- if (current.contains(r)) {
- i.remove();
- }
- }
- break;
- case FINISHED:
- // The task should have already cleared it self, clear and restart anyways.
- Log.w(TAG, mProgramLoadTask + " is finished, but was not cleared");
- startNext();
- break;
+ // Remove pending task fully satisfied by the current
+ Range<Long> current = mProgramLoadTask.getPeriod();
+ Iterator<Range<Long>> i = mProgramLoadQueue.iterator();
+ while (i.hasNext()) {
+ Range<Long> r = i.next();
+ if (current.contains(r)) {
+ i.remove();
+ }
}
}
}
@@ -1025,10 +997,9 @@ public class TimeShiftManager {
}
private void removeDummyPrograms() {
- for (int i = 0; i < mPrograms.size(); ++i) {
- Program program = mPrograms.get(i);
- if (!program.isValid()) {
- mPrograms.remove(i--);
+ for (Iterator<Program> it = mPrograms.listIterator(); it.hasNext(); ) {
+ if (!it.next().isValid()) {
+ it.remove();
}
}
}
@@ -1068,6 +1039,10 @@ public class TimeShiftManager {
// to show the time-line duration of {@link MAX_DUMMY_PROGRAM_DURATION} at most
// for a dummy program.
private List<Program> createDummyPrograms(long startTimeMs, long endTimeMs) {
+ SoftPreconditions.checkArgument(endTimeMs - startTimeMs <= TWO_WEEKS_MS, TAG,
+ "createDummyProgram: long duration of dummy programs are requested ("
+ + Utils.toTimeString(startTimeMs) + ", "
+ + Utils.toTimeString(endTimeMs));
if (startTimeMs >= endTimeMs) {
return Collections.emptyList();
}
@@ -1162,7 +1137,7 @@ public class TimeShiftManager {
if (DEBUG) Log.d(TAG, "Scheduling with " + delay + "(ms) delays.");
}
- // Prefecth programs within PREFETCH_DURATION_FOR_NEXT from now.
+ // Prefetch programs within PREFETCH_DURATION_FOR_NEXT from now.
private void prefetchPrograms() {
long startTimeMs;
Program lastValidProgram = getLastValidProgram();
@@ -1185,7 +1160,7 @@ public class TimeShiftManager {
private class LoadProgramsForCurrentChannelTask
extends AsyncDbTask.LoadProgramsForChannelTask {
- public LoadProgramsForCurrentChannelTask(ContentResolver contentResolver,
+ LoadProgramsForCurrentChannelTask(ContentResolver contentResolver,
Range<Long> period) {
super(contentResolver, mChannel.getId(), period);
}
@@ -1252,7 +1227,9 @@ public class TimeShiftManager {
}
private void startNextLoadingIfNeeded() {
- mProgramLoadTask = null;
+ if (mProgramLoadTask == this) {
+ mProgramLoadTask = null;
+ }
// Need to post to handler, because the task is still running.
mHandler.post(new Runnable() {
@Override
@@ -1262,7 +1239,7 @@ public class TimeShiftManager {
});
}
- public boolean overlaps(Queue<Range<Long>> programLoadQueue) {
+ boolean overlaps(Queue<Range<Long>> programLoadQueue) {
for (Range<Long> r : programLoadQueue) {
if (mPeriod.contains(r.getLower()) || mPeriod.contains(r.getUpper())) {
return true;
@@ -1281,7 +1258,9 @@ public class TimeShiftManager {
void initialize(long timeMs) {
mSeekRequestTimeMs = INVALID_TIME;
mCurrentPositionMs = timeMs;
- TimeShiftManager.this.onCurrentPositionChanged();
+ if (timeMs != INVALID_TIME) {
+ TimeShiftManager.this.onCurrentPositionChanged();
+ }
}
void onSeekRequested(long seekTimeMs) {
@@ -1357,7 +1336,7 @@ public class TimeShiftManager {
}
private static class TimeShiftHandler extends WeakHandler<TimeShiftManager> {
- public TimeShiftHandler(TimeShiftManager ref) {
+ TimeShiftHandler(TimeShiftManager ref) {
super(ref);
}
diff --git a/src/com/android/tv/TvApplication.java b/src/com/android/tv/TvApplication.java
index ef105c94..0e18a259 100644
--- a/src/com/android/tv/TvApplication.java
+++ b/src/com/android/tv/TvApplication.java
@@ -22,9 +22,9 @@ import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputManager.TvInputCallback;
@@ -32,7 +32,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.Nullable;
-import android.support.v4.os.BuildCompat;
+import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
@@ -42,37 +42,47 @@ 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.ui.setup.animation.SetupAnimationHelper;
+import com.android.tv.config.DefaultConfigManager;
+import com.android.tv.config.RemoteConfig;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ProgramDataManager;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManagerImpl;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrRecordingService;
-import com.android.tv.dvr.DvrSessionManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrStorageStatusManager;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+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.SetupUtils;
import com.android.tv.util.SystemProperties;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
-import com.android.usbtuner.UsbTunerPreferences;
-import com.android.usbtuner.setup.TunerSetupActivity;
-import com.android.usbtuner.tvinput.UsbTunerTvInputService;
import java.util.List;
public class TvApplication extends Application implements ApplicationSingletons {
private static final String TAG = "TvApplication";
private static final boolean DEBUG = false;
+ private RemoteConfig mRemoteConfig;
/**
- * Returns the @{@link ApplicationSingletons} using the application context.
+ * Broadcast Action: The user has updated LC to a new version that supports tuner input.
+ * {@link TunerInputController} will recevice this intent to check the existence of tuner
+ * input when the new version is first launched.
*/
- public static ApplicationSingletons getSingletons(Context context) {
- return (ApplicationSingletons) context.getApplicationContext();
- }
+ 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 String mVersionName = "";
private final MainActivityWrapper mMainActivityWrapper = new MainActivityWrapper();
@@ -84,14 +94,30 @@ public class TvApplication extends Application implements ApplicationSingletons
private ChannelDataManager mChannelDataManager;
private ProgramDataManager mProgramDataManager;
private DvrManager mDvrManager;
+ private DvrScheduleManager mDvrScheduleManager;
private DvrDataManager mDvrDataManager;
+ private DvrStorageStatusManager mDvrStorageStatusManager;
+ private DvrWatchedPositionManager mDvrWatchedPositionManager;
@Nullable
- private DvrSessionManager mDvrSessionManager;
+ private InputSessionManager mInputSessionManager;
+ private AccountHelper mAccountHelper;
+ // When this variable is null, we don't know in which process TvApplication runs.
+ private Boolean mRunningInMainProcess;
@Override
public void onCreate() {
super.onCreate();
- SharedPreferencesUtils.initialize(this);
+ SharedPreferencesUtils.initialize(this, new Runnable() {
+ @Override
+ public void run() {
+ if (mRunningInMainProcess != null && mRunningInMainProcess) {
+ checkTunerServiceOnFirstLaunch();
+ }
+ }
+ });
+ // 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;
@@ -100,17 +126,21 @@ public class TvApplication extends Application implements ApplicationSingletons
mVersionName = "";
}
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.setThreadPolicy(
- new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog().build());
- StrictMode.VmPolicy.Builder vmPolicyBuilder = new StrictMode.VmPolicy.Builder()
- .detectAll().penaltyLog();
- if (BuildConfig.ENG && SystemProperties.ALLOW_DEATH_PENALTY.getValue() &&
- !TvCommonUtils.isRunningInTest()) {
- // TODO turn on death penalty for tests when they stop leaking MainActivity
+ StrictMode.ThreadPolicy.Builder threadPolicyBuilder =
+ new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog();
+ StrictMode.VmPolicy.Builder vmPolicyBuilder =
+ new StrictMode.VmPolicy.Builder().detectAll().penaltyLog();
+ if (!TvCommonUtils.isRunningInTest()) {
+ threadPolicyBuilder.penaltyDialog();
+ // Turn off death penalty for tests b/23355898
+ vmPolicyBuilder.penaltyDeath();
}
+ StrictMode.setThreadPolicy(threadPolicyBuilder.build());
StrictMode.setVmPolicy(vmPolicyBuilder.build());
}
if (BuildConfig.ENG && !SystemProperties.ALLOW_ANALYTICS_IN_ENG.getValue()) {
@@ -121,27 +151,63 @@ public class TvApplication extends Application implements ApplicationSingletons
mTracker = mAnalytics.getDefaultTracker();
mTvInputManagerHelper = new TvInputManagerHelper(this);
mTvInputManagerHelper.start();
- mTvInputManagerHelper.addCallback(new TvInputCallback() {
- @Override
- public void onInputAdded(String inputId) {
- handleInputCountChanged();
- }
-
- @Override
- public void onInputRemoved(String inputId) {
- handleInputCountChanged();
- }
- });
- if (CommonFeatures.DVR.isEnabled(this) && BuildCompat.isAtLeastN()) {
- mDvrManager = new DvrManager(this);
- //NOTE: DvrRecordingService just keeps running.
- DvrRecordingService.startService(this);
- }
// 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.
SetupAnimationHelper.initialize(this);
- if (DEBUG) Log.i(TAG, "Started Live TV " + mVersionName);
+ Log.i(TAG, "Started Live TV " + mVersionName);
+ }
+
+ private void setCurrentRunningProcess(boolean isMainProcess) {
+ if (mRunningInMainProcess != null) {
+ SoftPreconditions.checkState(isMainProcess == mRunningInMainProcess);
+ return;
+ }
+ mRunningInMainProcess = isMainProcess;
+ if (CommonFeatures.DVR.isEnabled(this)) {
+ mDvrStorageStatusManager = new DvrStorageStatusManager(this, mRunningInMainProcess);
+ }
+ if (mRunningInMainProcess) {
+ mTvInputManagerHelper.addCallback(new TvInputCallback() {
+ @Override
+ public void onInputAdded(String inputId) {
+ if (Features.TUNER.isEnabled(TvApplication.this) && TextUtils.equals(inputId,
+ TunerTvInputService.getInputId(TvApplication.this))) {
+ TunerInputInfoUtils.updateTunerInputInfo(TvApplication.this);
+ }
+ handleInputCountChanged();
+ }
+
+ @Override
+ public void onInputRemoved(String inputId) {
+ handleInputCountChanged();
+ }
+ });
+ 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(this);
+ }
+ if (CommonFeatures.DVR.isEnabled(this)) {
+ mDvrScheduleManager = new DvrScheduleManager(this);
+ mDvrManager = new DvrManager(this);
+ //NOTE: DvrRecordingService just keeps running.
+ DvrRecordingService.startService(this);
+ }
+ }
+ }
+
+ private void checkTunerServiceOnFirstLaunch() {
+ SharedPreferences sharedPreferences = this.getSharedPreferences(
+ SharedPreferencesUtils.SHARED_PREF_FEATURES, Context.MODE_PRIVATE);
+ boolean isFirstLaunch = sharedPreferences.getBoolean(PREFERENCE_IS_FIRST_LAUNCH, true);
+ if (isFirstLaunch) {
+ if (DEBUG) Log.d(TAG, "Congratulations, it's the first launch!");
+ sendBroadcast(new Intent(ACTION_APPLICATION_FIRST_LAUNCHED));
+ SharedPreferences.Editor editor = sharedPreferences.edit();
+ editor.putBoolean(PREFERENCE_IS_FIRST_LAUNCH, false);
+ editor.apply();
+ }
}
/**
@@ -152,13 +218,32 @@ public class TvApplication extends Application implements ApplicationSingletons
return mDvrManager;
}
+ /**
+ * Returns the {@link DvrScheduleManager}.
+ */
+ @Override
+ public DvrScheduleManager getDvrScheduleManager() {
+ return mDvrScheduleManager;
+ }
+
+ /**
+ * Returns the {@link DvrWatchedPositionManager}.
+ */
+ @Override
+ public DvrWatchedPositionManager getDvrWatchedPositionManager() {
+ if (mDvrWatchedPositionManager == null) {
+ mDvrWatchedPositionManager = new DvrWatchedPositionManager(this);
+ }
+ return mDvrWatchedPositionManager;
+ }
+
@Override
@TargetApi(Build.VERSION_CODES.N)
- public DvrSessionManager getDvrSessionManger() {
- if (mDvrSessionManager == null) {
- mDvrSessionManager = new DvrSessionManager(this);
+ public InputSessionManager getInputSessionManager() {
+ if (mInputSessionManager == null) {
+ mInputSessionManager = new InputSessionManager(this);
}
- return mDvrSessionManager;
+ return mInputSessionManager;
}
/**
@@ -177,7 +262,6 @@ public class TvApplication extends Application implements ApplicationSingletons
return mTracker;
}
-
/**
* Returns {@link ChannelDataManager}.
*/
@@ -209,14 +293,23 @@ public class TvApplication extends Application implements ApplicationSingletons
@Override
public DvrDataManager getDvrDataManager() {
if (mDvrDataManager == null) {
- DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this, Clock.SYSTEM);
- mDvrDataManager = dvrDataManager;
- dvrDataManager.start();
+ DvrDataManagerImpl dvrDataManager = new DvrDataManagerImpl(this, Clock.SYSTEM);
+ mDvrDataManager = dvrDataManager;
+ dvrDataManager.start();
}
return mDvrDataManager;
}
/**
+ * Returns {@link DvrStorageStatusManager}.
+ */
+ @TargetApi(Build.VERSION_CODES.N)
+ @Override
+ public DvrStorageStatusManager getDvrStorageStatusManager() {
+ return mDvrStorageStatusManager;
+ }
+
+ /**
* Returns {@link TvInputManagerHelper}.
*/
@Override
@@ -233,6 +326,26 @@ public class TvApplication extends Application implements ApplicationSingletons
}
/**
+ * Returns the {@link AccountHelper}.
+ */
+ @Override
+ public AccountHelper getAccountHelper() {
+ if (mAccountHelper == null) {
+ mAccountHelper = new AccountHelper(getApplicationContext());
+ }
+ return mAccountHelper;
+ }
+
+ @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;
+ }
+
+ /**
* SelectInputActivity is set in {@link SelectInputActivity#onCreate} and cleared in
* {@link SelectInputActivity#onDestroy}.
*/
@@ -322,7 +435,7 @@ public class TvApplication extends Application implements ApplicationSingletons
* Checks the input counts and enable/disable TvActivity. Also updates the input list in
* {@link SetupUtils}.
*
- * @param calledByTunerServiceChanged true if it is called when UsbTunerTvInputService
+ * @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
@@ -340,7 +453,7 @@ public class TvApplication extends Application implements ApplicationSingletons
if (!skipTunerInputCheck) {
for (TvInputInfo input : inputs) {
if (calledByTunerServiceChanged && !tunerServiceEnabled
- && UsbTunerTvInputService.getInputId(this).equals(input.getId())) {
+ && TunerTvInputService.getInputId(this).equals(input.getId())) {
continue;
}
if (input.getType() == TvInputInfo.TYPE_TUNER) {
@@ -361,4 +474,29 @@ public class TvApplication extends Application implements ApplicationSingletons
}
SetupUtils.getInstance(TvApplication.this).onInputListUpdated(inputManager);
}
+
+ /**
+ * Returns the @{@link ApplicationSingletons} using the application context.
+ */
+ public static ApplicationSingletons getSingletons(Context context) {
+ return (ApplicationSingletons) context.getApplicationContext();
+ }
+
+ /**
+ * Sets true, if TvApplication is running on the main process. If TvApplication runs on
+ * tuner process or other process, it sets false.
+ *
+ * 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) {
+ 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/TvOptionsManager.java b/src/com/android/tv/TvOptionsManager.java
index f104e75d..7871cbe7 100644
--- a/src/com/android/tv/TvOptionsManager.java
+++ b/src/com/android/tv/TvOptionsManager.java
@@ -39,7 +39,8 @@ public class TvOptionsManager {
public static final int OPTION_SYSTEMWIDE_PIP = 3;
public static final int OPTION_MULTI_AUDIO = 4;
public static final int OPTION_MORE_CHANNELS = 5;
- public static final int OPTION_SETTINGS = 6;
+ public static final int OPTION_DEVELOPER = 6;
+ public static final int OPTION_SETTINGS = 7;
public static final int OPTION_PIP_INPUT = 100;
public static final int OPTION_PIP_SWAP = 101;
diff --git a/src/com/android/tv/dvr/ui/EmptyHolder.java b/src/com/android/tv/config/ConfigKeys.java
index 45cd3a36..7df033d2 100644
--- a/src/com/android/tv/dvr/ui/EmptyHolder.java
+++ b/src/com/android/tv/config/ConfigKeys.java
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package com.android.tv.dvr.ui;
+package com.android.tv.config;
/**
- * Special object meaning a row is empty;
+ * Static list of config keys.
*/
-final class EmptyHolder {
- static final EmptyHolder EMPTY_HOLDER = new EmptyHolder();
+public final class ConfigKeys {
- private EmptyHolder() {
+
+ private ConfigKeys() {
}
}
diff --git a/src/com/android/tv/config/DefaultConfigManager.java b/src/com/android/tv/config/DefaultConfigManager.java
new file mode 100644
index 00000000..f5a6e959
--- /dev/null
+++ b/src/com/android/tv/config/DefaultConfigManager.java
@@ -0,0 +1,55 @@
+/*
+ * 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.config;
+
+import android.content.Context;
+
+/**
+ * Stub Remote Config.
+ */
+public class DefaultConfigManager {
+ public static DefaultConfigManager createInstance(Context context) {
+ return new DefaultConfigManager();
+ }
+
+ private StubRemoteConfig mRemoteConfig = new StubRemoteConfig();
+
+ public RemoteConfig getRemoteConfig() {
+ return mRemoteConfig;
+ }
+
+ private static class StubRemoteConfig implements RemoteConfig {
+ @Override
+ public void fetch(OnRemoteConfigUpdatedListener listener) {
+
+ }
+
+ @Override
+ public String getString(String key) {
+ return null;
+ }
+
+ @Override
+ public boolean getBoolean(String key) {
+ return false;
+ }
+ }
+}
+
+
+
+
diff --git a/src/com/android/tv/config/RemoteConfig.java b/src/com/android/tv/config/RemoteConfig.java
new file mode 100644
index 00000000..0f7d2c53
--- /dev/null
+++ b/src/com/android/tv/config/RemoteConfig.java
@@ -0,0 +1,48 @@
+/*
+ * 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.config;
+
+/**
+ * Manages Live TV Configuration, allowing remote updates.
+ *
+ * <p>This is a thin wrapper around
+ * <a href="https://firebase.google.com/docs/remote-config/"></a>Firebase Remote Config</a>
+ */
+public interface RemoteConfig {
+
+ /**
+ * Notified on successful completion of a {@link #fetch)}
+ */
+ interface OnRemoteConfigUpdatedListener {
+ void onRemoteConfigUpdated();
+ }
+
+ /**
+ * Starts a fetch and notifies {@code listener} on successful completion.
+ */
+ void fetch(OnRemoteConfigUpdatedListener listener);
+
+ /**
+ * Gets value as a string corresponding to the specified key.
+ */
+ String getString(String key);
+
+ /**
+ * Gets value as a boolean corresponding to the specified key.
+ */
+ boolean getBoolean(String key);
+}
diff --git a/src/com/android/tv/config/RemoteConfigFeature.java b/src/com/android/tv/config/RemoteConfigFeature.java
new file mode 100644
index 00000000..502e6a9c
--- /dev/null
+++ b/src/com/android/tv/config/RemoteConfigFeature.java
@@ -0,0 +1,43 @@
+/*
+ * 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.config;
+
+import android.content.Context;
+
+import com.android.tv.TvApplication;
+import com.android.tv.common.feature.Feature;
+
+/**
+ * A {@link Feature} controlled by a {@link RemoteConfig} boolean.
+ */
+public class RemoteConfigFeature implements Feature {
+ private final String mKey;
+
+ /** Creates a {@link RemoteConfigFeature for the {@code key}. */
+ public static RemoteConfigFeature fromKey(String key) {
+ return new RemoteConfigFeature(key);
+ }
+
+ private RemoteConfigFeature(String key) {
+ mKey = key;
+ }
+
+ @Override
+ public boolean isEnabled(Context context) {
+ return TvApplication.getSingletons(context).getRemoteConfig().getBoolean(mKey);
+ }
+}
diff --git a/src/com/android/tv/data/BaseProgram.java b/src/com/android/tv/data/BaseProgram.java
new file mode 100644
index 00000000..f420de02
--- /dev/null
+++ b/src/com/android/tv/data/BaseProgram.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.data;
+
+import android.content.Context;
+
+import java.util.Comparator;
+
+/**
+ * Base class for {@link com.android.tv.data.Program} and
+ * {@link com.android.tv.dvr.RecordedProgram}.
+ */
+public abstract class BaseProgram {
+ /**
+ * Comparator used to compare {@link BaseProgram} according to its season and episodes number.
+ * If a program's season or episode number is null, it will be consider "smaller" than programs
+ * with season or episode numbers.
+ */
+ public static final Comparator<BaseProgram> EPISODE_COMPARATOR =
+ new EpisodeComparator(false);
+
+ /**
+ * Comparator used to compare {@link BaseProgram} according to its season and episodes number
+ * with season numbers in a reversed order. If a program's season or episode number is null, it
+ * will be consider "smaller" than programs with season or episode numbers.
+ */
+ public static final Comparator<BaseProgram> SEASON_REVERSED_EPISODE_COMPARATOR =
+ new EpisodeComparator(true);
+
+ private static class EpisodeComparator implements Comparator<BaseProgram> {
+ private final boolean mReversedSeason;
+
+ EpisodeComparator(boolean reversedSeason) {
+ mReversedSeason = reversedSeason;
+ }
+
+ @Override
+ public int compare(BaseProgram lhs, BaseProgram rhs) {
+ if (lhs == rhs) {
+ return 0;
+ }
+ int seasonNumberCompare =
+ numberCompare(lhs.getSeasonNumber(), rhs.getSeasonNumber());
+ if (seasonNumberCompare != 0) {
+ return mReversedSeason ? -seasonNumberCompare : seasonNumberCompare;
+ } else {
+ return numberCompare(lhs.getEpisodeNumber(), rhs.getEpisodeNumber());
+ }
+ }
+ }
+
+ /**
+ * Compares two strings represent season numbers or episode numbers of programs.
+ */
+ public static int numberCompare(String s1, String s2) {
+ if (s1 == s2) {
+ return 0;
+ } else if (s1 == null) {
+ return -1;
+ } else if (s2 == null) {
+ return 1;
+ } else if (s1.equals(s2)) {
+ return 0;
+ }
+ try {
+ return Integer.compare(Integer.parseInt(s1), Integer.parseInt(s2));
+ } catch (NumberFormatException e) {
+ return s1.compareTo(s2);
+ }
+ }
+
+ /**
+ * Returns ID of the program.
+ */
+ abstract public long getId();
+
+ /**
+ * Returns the title of the program.
+ */
+ abstract public String getTitle();
+
+ /**
+ * Returns the program's title withe its season and episode number.
+ */
+ abstract public String getTitleWithEpisodeNumber(Context context);
+
+ /**
+ * Returns the displayed title of the program episode.
+ */
+ abstract public String getEpisodeDisplayTitle(Context context);
+
+ /**
+ * Returns the description of the program.
+ */
+ abstract public String getDescription();
+
+ /**
+ * Returns the long description of the program.
+ */
+ abstract public String getLongDescription();
+
+ /**
+ * Returns the start time of the program in Milliseconds.
+ */
+ abstract public long getStartTimeUtcMillis();
+
+ /**
+ * Returns the end time of the program in Milliseconds.
+ */
+ abstract public long getEndTimeUtcMillis();
+
+ /**
+ * Returns the duration of the program in Milliseconds.
+ */
+ abstract public long getDurationMillis();
+
+ /**
+ * Returns the series ID.
+ */
+ abstract public String getSeriesId();
+
+ /**
+ * Returns the season number.
+ */
+ abstract public String getSeasonNumber();
+
+ /**
+ * Returns the episode number.
+ */
+ abstract public String getEpisodeNumber();
+
+ /**
+ * Returns URI of the program's poster.
+ */
+ abstract public String getPosterArtUri();
+
+ /**
+ * Returns URI of the program's thumbnail.
+ */
+ abstract public String getThumbnailUri();
+
+ /**
+ * Returns the array of the ID's of the canonical genres.
+ */
+ abstract public int[] getCanonicalGenreIds();
+
+ /**
+ * Returns channel's ID of the program.
+ */
+ abstract public long getChannelId();
+
+ /**
+ * Returns if the program is valid.
+ */
+ abstract public boolean isValid();
+
+ /**
+ * Generates the series ID for the other inputs than the tuner TV input.
+ */
+ public static String generateSeriesId(String packageName, String title) {
+ return packageName + "/" + title;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/data/Channel.java b/src/com/android/tv/data/Channel.java
index 86437ab2..30f84236 100644
--- a/src/com/android/tv/data/Channel.java
+++ b/src/com/android/tv/data/Channel.java
@@ -16,7 +16,6 @@
package com.android.tv.data;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -24,14 +23,12 @@ import android.database.Cursor;
import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.net.Uri;
-import android.os.Build;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.common.CollectionUtils;
import com.android.tv.common.TvCommonConstants;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.TvInputManagerHelper;
@@ -73,7 +70,7 @@ public final class Channel {
private static final int APP_LINK_TYPE_NOT_SET = 0;
private static final String INVALID_PACKAGE_NAME = "packageName";
- private static final String[] PROJECTION_BASE = {
+ public static final String[] PROJECTION = {
// Columns must match what is read in Channel.fromCursor()
TvContract.Channels._ID,
TvContract.Channels.COLUMN_PACKAGE_NAME,
@@ -85,12 +82,6 @@ public final class Channel {
TvContract.Channels.COLUMN_VIDEO_FORMAT,
TvContract.Channels.COLUMN_BROWSABLE,
TvContract.Channels.COLUMN_LOCKED,
- };
-
- // Additional fields added in MNC.
- @SuppressLint("InlinedApi")
- private static final String[] PROJECTION_ADDED_IN_MNC = {
- // Columns should match what is read in Channel.fromCursor()
TvContract.Channels.COLUMN_APP_LINK_TEXT,
TvContract.Channels.COLUMN_APP_LINK_COLOR,
TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
@@ -98,16 +89,6 @@ public final class Channel {
TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
};
- public static final String[] PROJECTION = createProjection();
-
- private static String[] createProjection() {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return CollectionUtils.concatAll(PROJECTION_BASE, PROJECTION_ADDED_IN_MNC);
- } else {
- return PROJECTION_BASE;
- }
- }
-
/**
* Creates {@code Channel} object from cursor.
*
@@ -128,13 +109,11 @@ public final class Channel {
channel.mVideoFormat = Utils.intern(cursor.getString(index++));
channel.mBrowsable = cursor.getInt(index++) == 1;
channel.mLocked = cursor.getInt(index++) == 1;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- channel.mAppLinkText = cursor.getString(index++);
- channel.mAppLinkColor = cursor.getInt(index++);
- channel.mAppLinkIconUri = cursor.getString(index++);
- channel.mAppLinkPosterArtUri = cursor.getString(index++);
- channel.mAppLinkIntentUri = cursor.getString(index++);
- }
+ channel.mAppLinkText = cursor.getString(index++);
+ channel.mAppLinkColor = cursor.getInt(index++);
+ channel.mAppLinkIconUri = cursor.getString(index++);
+ channel.mAppLinkPosterArtUri = cursor.getString(index++);
+ channel.mAppLinkIntentUri = cursor.getString(index++);
return channel;
}
@@ -171,11 +150,6 @@ public final class Channel {
private long mDvrId;
- /**
- * TODO(DVR): Need to fill the following data.
- */
- private boolean mRecordable;
-
private Channel() {
// Do nothing.
}
@@ -226,6 +200,15 @@ public final class Channel {
return mIsPassthrough;
}
+ /**
+ * Gets identification text for displaying or debugging.
+ * It's made from Channels' display number plus their display name.
+ */
+ public String getDisplayText() {
+ return TextUtils.isEmpty(mDisplayName) ? mDisplayNumber
+ : mDisplayNumber + " " + mDisplayName;
+ }
+
public String getAppLinkText() {
return mAppLinkText;
}
@@ -578,6 +561,8 @@ public final class Channel {
getUri().toString());
mAppLinkType = APP_LINK_TYPE_CHANNEL;
return;
+ } else {
+ Log.w(TAG, "No activity exists to handle : " + mAppLinkIntentUri);
}
} catch (URISyntaxException e) {
Log.w(TAG, "Unable to set app link for " + mAppLinkIntentUri, e);
@@ -650,8 +635,7 @@ public final class Channel {
result = ChannelNumber.compare(lhs.getDisplayNumber(), rhs.getDisplayNumber());
if (mDetectDuplicatesEnabled && result == 0) {
Log.w(TAG, "Duplicate channels detected! - \""
- + lhs.getDisplayNumber() + " " + lhs.getDisplayName() + "\" and \""
- + rhs.getDisplayNumber() + " " + rhs.getDisplayName() + "\"");
+ + lhs.getDisplayText() + "\" and \"" + rhs.getDisplayText() + "\"");
}
return result;
}
diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java
index 84a16111..6f9ea6d7 100644
--- a/src/com/android/tv/data/ChannelDataManager.java
+++ b/src/com/android/tv/data/ChannelDataManager.java
@@ -50,6 +50,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
/**
* The class to manage channel data.
@@ -72,7 +73,7 @@ public class ChannelDataManager {
private QueryAllChannelsTask mChannelsUpdateTask;
private final List<Runnable> mPostRunnablesAfterChannelUpdate = new ArrayList<>();
- private final Set<Listener> mListeners = new ArraySet<>();
+ private final Set<Listener> mListeners = new CopyOnWriteArraySet<>();
private final Map<Long, ChannelWrapper> mChannelWrapperMap = new HashMap<>();
private final Map<String, MutableInt> mChannelCountMap = new HashMap<>();
private final Channel.DefaultComparator mChannelComparator;
@@ -296,6 +297,16 @@ public class ChannelDataManager {
}
/**
+ * Checks if the channel exists in DB.
+ *
+ * <p>Note that the channels of the removed inputs can not be obtained from {@link #getChannel}.
+ * In that case this method is used to check if the channel exists in the DB.
+ */
+ public boolean doesChannelExistInDb(long channelId) {
+ return mChannelWrapperMap.get(channelId) != null;
+ }
+
+ /**
* Returns true if and only if there exists at least one channel and all channels are hidden.
*/
public boolean areAllChannelsHidden() {
@@ -360,22 +371,19 @@ public class ChannelDataManager {
}
public void notifyChannelBrowsableChanged() {
- // Copy the original collection to allow the callee to modify the listeners.
- for (Listener l : mListeners.toArray(new Listener[mListeners.size()])) {
+ for (Listener l : mListeners) {
l.onChannelBrowsableChanged();
}
}
private void notifyChannelListUpdated() {
- // Copy the original collection to allow the callee to modify the listeners.
- for (Listener l : mListeners.toArray(new Listener[mListeners.size()])) {
+ for (Listener l : mListeners) {
l.onChannelListUpdated();
}
}
private void notifyLoadFinished() {
- // Copy the original collection to allow the callee to modify the listeners.
- for (Listener l : mListeners.toArray(new Listener[mListeners.size()])) {
+ for (Listener l : mListeners) {
l.onLoadFinished();
}
}
diff --git a/src/com/android/tv/data/GenreItems.java b/src/com/android/tv/data/GenreItems.java
index b1110612..b12fd1aa 100644
--- a/src/com/android/tv/data/GenreItems.java
+++ b/src/com/android/tv/data/GenreItems.java
@@ -16,10 +16,8 @@
package com.android.tv.data;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.media.tv.TvContract.Programs.Genres;
-import android.os.Build;
import com.android.tv.R;
@@ -29,23 +27,7 @@ public class GenreItems {
*/
public static final int ID_ALL_CHANNELS = 0;
- private static final String[] CANONICAL_GENRES_L = {
- null, // All channels
- Genres.FAMILY_KIDS,
- Genres.SPORTS,
- Genres.SHOPPING,
- Genres.MOVIES,
- Genres.COMEDY,
- Genres.TRAVEL,
- Genres.DRAMA,
- Genres.EDUCATION,
- Genres.ANIMAL_WILDLIFE,
- Genres.NEWS,
- Genres.GAMING
- };
-
- @SuppressLint("InlinedApi")
- private static final String[] CANONICAL_GENRES_L_MR1 = {
+ private static final String[] CANONICAL_GENRES = {
null, // All channels
Genres.FAMILY_KIDS,
Genres.SPORTS,
@@ -66,25 +48,13 @@ public class GenreItems {
Genres.TECH_SCIENCE
};
- private static final String[] CANONICAL_GENRES = createGenres();
-
- private static String[] createGenres() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
- return CANONICAL_GENRES_L;
- } else {
- return CANONICAL_GENRES_L_MR1;
- }
- }
-
private GenreItems() { }
/**
* Returns array of all genre labels.
*/
public static String[] getLabels(Context context) {
- String[] items = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1
- ? context.getResources().getStringArray(R.array.genre_labels_l)
- : context.getResources().getStringArray(R.array.genre_labels_l_mr1);
+ String[] items = context.getResources().getStringArray(R.array.genre_labels);
if (items.length != CANONICAL_GENRES.length) {
throw new IllegalArgumentException("Genre data mismatch");
}
diff --git a/src/com/android/tv/data/InternalDataUtils.java b/src/com/android/tv/data/InternalDataUtils.java
new file mode 100644
index 00000000..6054f089
--- /dev/null
+++ b/src/com/android/tv/data/InternalDataUtils.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.data;
+
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.tv.data.Program.CriticScore;
+import com.android.tv.dvr.RecordedProgram;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.util.List;
+
+/**
+ * A utility class to parse and store data from the
+ * {@link android.media.tv.TvContract.Programs#COLUMN_INTERNAL_PROVIDER_DATA} field in the
+ * {@link android.media.tv.TvContract.Programs}.
+ */
+public final class InternalDataUtils {
+ private static final boolean DEBUG = false;
+ private static final String TAG = "InternalDataUtils";
+
+ private InternalDataUtils() {
+ //do nothing
+ }
+
+ /**
+ * Deserializes a byte array into objects to be stored in the Program class.
+ *
+ * <p> Series ID and critic scores are loaded from the bytes.
+ *
+ * @param bytes the bytes to be deserialized
+ * @param builder the builder for the Program class
+ */
+ public static void deserializeInternalProviderData(byte[] bytes, Program.Builder builder) {
+ if (bytes == null || bytes.length == 0) {
+ return;
+ }
+ try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
+ builder.setSeriesId((String) in.readObject());
+ builder.setCriticScores((List<CriticScore>) in.readObject());
+ } catch (NullPointerException e) {
+ Log.e(TAG, "no bytes to deserialize");
+ } catch (IOException e) {
+ Log.e(TAG, "Could not deserialize internal provider contents");
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "class not found in internal provider contents");
+ }
+ }
+
+ /**
+ * Convenience method for converting relevant data in Program class to a serialized blob type
+ * for storage in internal_provider_data field.
+ * @param program the program which contains the objects to be serialized
+ * @return serialized blob-type data
+ */
+ @Nullable
+ public static byte[] serializeInternalProviderData(Program program) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
+ if (!TextUtils.isEmpty(program.getSeriesId()) || program.getCriticScores() != null) {
+ out.writeObject(program.getSeriesId());
+ out.writeObject(program.getCriticScores());
+ return bos.toByteArray();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Could not serialize internal provider contents for program: "
+ + program.getTitle());
+ }
+ return null;
+ }
+
+ /**
+ * Deserializes a byte array into objects to be stored in the RecordedProgram class.
+ *
+ * <p> Series ID is loaded from the bytes.
+ *
+ * @param bytes the bytes to be deserialized
+ * @param builder the builder for the RecordedProgram class
+ */
+ public static void deserializeInternalProviderData(byte[] bytes,
+ RecordedProgram.Builder builder) {
+ if (bytes == null || bytes.length == 0) {
+ return;
+ }
+ try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bytes))) {
+ builder.setSeriesId((String) in.readObject());
+ } catch (NullPointerException e) {
+ Log.e(TAG, "no bytes to deserialize");
+ } catch (IOException e) {
+ Log.e(TAG, "Could not deserialize internal provider contents");
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "class not found in internal provider contents");
+ }
+ }
+
+ /**
+ * Serializes relevant objects in {@link android.media.tv.TvContract.Programs} to byte array.
+ * @return the serialized byte array
+ */
+ public static byte[] serializeInternalProviderData(RecordedProgram program) {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (ObjectOutputStream out = new ObjectOutputStream(bos)) {
+ if (!TextUtils.isEmpty(program.getSeriesId())) {
+ out.writeObject(program.getSeriesId());
+ return bos.toByteArray();
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Could not serialize internal provider contents for program: "
+ + program.getTitle());
+ }
+ return null;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/data/Lineup.java b/src/com/android/tv/data/Lineup.java
new file mode 100644
index 00000000..d0e9d7ba
--- /dev/null
+++ b/src/com/android/tv/data/Lineup.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.data;
+
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A class that represents a lineup.
+ */
+public class Lineup {
+ /**
+ * The ID of this lineup.
+ */
+ public final String id;
+
+ /**
+ * The type associated with this lineup.
+ */
+ public final int type;
+
+ /**
+ * The human readable name associated with this lineup.
+ */
+ public final String name;
+
+ /**
+ * Location this lineup can be found.
+ * This is a human readable description of a geographic location.
+ */
+ public final String location;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({LINEUP_CABLE, LINEUP_SATELLITE, LINEUP_BROADCAST_DIGITAL, LINEUP_BROADCAST_ANALOG,
+ LINEUP_IPTV, LINEUP_MVPD})
+ public @interface LineupType {}
+
+ /**
+ * Lineup type for cable.
+ */
+ public static final int LINEUP_CABLE = 0;
+
+ /**
+ * Lineup type for satelite.
+ */
+ public static final int LINEUP_SATELLITE = 1;
+
+ /**
+ * Lineup type for broadcast digital.
+ */
+ public static final int LINEUP_BROADCAST_DIGITAL = 2;
+
+ /**
+ * Lineup type for broadcast analog.
+ */
+ public static final int LINEUP_BROADCAST_ANALOG = 3;
+
+ /**
+ * Lineup type for IPTV.
+ */
+ public static final int LINEUP_IPTV = 4;
+
+ /**
+ * Indicates the lineup is either satelite, cable or IPTV but we are not sure which specific
+ * type.
+ */
+ public static final int LINEUP_MVPD = 5;
+
+ /**
+ * Creates a lineup.
+ */
+ public Lineup(String id, int type, String name, String location) {
+ this.id = id;
+ this.type = type;
+ this.name = name;
+ this.location = location;
+ }
+}
diff --git a/src/com/android/tv/data/ParcelableList.java b/src/com/android/tv/data/ParcelableList.java
new file mode 100644
index 00000000..78f444e4
--- /dev/null
+++ b/src/com/android/tv/data/ParcelableList.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.data;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A convenience class for the list of {@link Parcelable}s.
+ */
+public final class ParcelableList<T extends Parcelable> implements Parcelable {
+ /**
+ * Create instance from {@link Parcel}.
+ */
+ public static ParcelableList fromParcel(Parcel in) {
+ ParcelableList list = new ParcelableList();
+ int length = in.readInt();
+ if (length > 0) {
+ for (int i = 0; i < length; ++i) {
+ list.mList.add(in.readParcelable(Thread.currentThread().getContextClassLoader()));
+ }
+ }
+ return list;
+ }
+
+ /**
+ * A creator for {@link ParcelableList}.
+ */
+ public static final Creator<ParcelableList> CREATOR = new Creator<ParcelableList>() {
+ @Override
+ public ParcelableList createFromParcel(Parcel in) {
+ return ParcelableList.fromParcel(in);
+ }
+
+ @Override
+ public ParcelableList[] newArray(int size) {
+ return new ParcelableList[size];
+ }
+ };
+
+ private final List<T> mList = new ArrayList<>();
+
+ private ParcelableList() { }
+
+ public ParcelableList(Collection<T> initialList) {
+ mList.addAll(initialList);
+ }
+
+ /**
+ * Returns the list.
+ */
+ public List<T> getList() {
+ return new ArrayList<T>(mList);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int paramInt) {
+ out.writeInt(mList.size());
+ for (T data : mList) {
+ out.writeParcelable(data, 0);
+ }
+ }
+}
diff --git a/src/com/android/tv/data/Program.java b/src/com/android/tv/data/Program.java
index af5f93bb..b9cd3d8d 100644
--- a/src/com/android/tv/data/Program.java
+++ b/src/com/android/tv/data/Program.java
@@ -20,8 +20,12 @@ import android.content.Context;
import android.database.Cursor;
import android.media.tv.TvContentRating;
import android.media.tv.TvContract;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.os.BuildCompat;
import android.text.TextUtils;
import android.util.Log;
@@ -33,13 +37,16 @@ import com.android.tv.common.TvContentRatingCache;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.Utils;
+import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Objects;
/**
* A convenience class to create and insert program information entries into the database.
*/
-public final class Program implements Comparable<Program> {
+public final class Program extends BaseProgram implements Comparable<Program>, Parcelable {
private static final boolean DEBUG = false;
private static final boolean DEBUG_DUMP_DESCRIPTION = false;
private static final String TAG = "Program";
@@ -47,10 +54,12 @@ public final class Program implements Comparable<Program> {
private static final String[] PROJECTION_BASE = {
// Columns must match what is read in Program.fromCursor()
TvContract.Programs._ID,
+ TvContract.Programs.COLUMN_PACKAGE_NAME,
TvContract.Programs.COLUMN_CHANNEL_ID,
TvContract.Programs.COLUMN_TITLE,
TvContract.Programs.COLUMN_EPISODE_TITLE,
TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
+ TvContract.Programs.COLUMN_LONG_DESCRIPTION,
TvContract.Programs.COLUMN_POSTER_ART_URI,
TvContract.Programs.COLUMN_THUMBNAIL_URI,
TvContract.Programs.COLUMN_CANONICAL_GENRE,
@@ -58,10 +67,12 @@ public final class Program implements Comparable<Program> {
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_VIDEO_HEIGHT,
+ TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA
};
// Columns which is deprecated in NYC
+ @SuppressWarnings("deprecation")
private static final String[] PROJECTION_DEPRECATED_IN_NYC = {
TvContract.Programs.COLUMN_SEASON_NUMBER,
TvContract.Programs.COLUMN_EPISODE_NUMBER
@@ -70,7 +81,8 @@ public final class Program implements Comparable<Program> {
private static final String[] PROJECTION_ADDED_IN_NYC = {
TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
TvContract.Programs.COLUMN_SEASON_TITLE,
- TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER
+ TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
+ TvContract.Programs.COLUMN_RECORDING_PROHIBITED
};
public static final String[] PROJECTION = createProjection();
@@ -82,6 +94,18 @@ public final class Program implements Comparable<Program> {
}
/**
+ * Returns the column index for {@code column}, -1 if the column doesn't exist.
+ */
+ public static int getColumnIndex(String column) {
+ for (int i = 0; i < PROJECTION.length; ++i) {
+ if (PROJECTION[i].equals(column)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
* Creates {@code Program} object from cursor.
*
* <p>The query that created the cursor MUST use {@link #PROJECTION}.
@@ -91,10 +115,13 @@ public final class Program implements Comparable<Program> {
Builder builder = new Builder();
int index = 0;
builder.setId(cursor.getLong(index++));
+ String packageName = cursor.getString(index++);
+ builder.setPackageName(packageName);
builder.setChannelId(cursor.getLong(index++));
builder.setTitle(cursor.getString(index++));
builder.setEpisodeTitle(cursor.getString(index++));
builder.setDescription(cursor.getString(index++));
+ builder.setLongDescription(cursor.getString(index++));
builder.setPosterArtUri(cursor.getString(index++));
builder.setThumbnailUri(cursor.getString(index++));
builder.setCanonicalGenres(cursor.getString(index++));
@@ -104,10 +131,15 @@ public final class Program implements Comparable<Program> {
builder.setEndTimeUtcMillis(cursor.getLong(index++));
builder.setVideoWidth((int) cursor.getLong(index++));
builder.setVideoHeight((int) cursor.getLong(index++));
+ if (Utils.isInBundledPackageSet(packageName)) {
+ InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder);
+ }
+ index++;
if (BuildCompat.isAtLeastN()) {
builder.setSeasonNumber(cursor.getString(index++));
builder.setSeasonTitle(cursor.getString(index++));
builder.setEpisodeNumber(cursor.getString(index++));
+ builder.setRecordingProhibited(cursor.getInt(index++) == 1);
} else {
builder.setSeasonNumber(cursor.getString(index++));
builder.setEpisodeNumber(cursor.getString(index++));
@@ -115,9 +147,55 @@ public final class Program implements Comparable<Program> {
return builder.build();
}
+ public static Program fromParcel(Parcel in) {
+ Program program = new Program();
+ program.mId = in.readLong();
+ program.mPackageName = in.readString();
+ program.mChannelId = in.readLong();
+ program.mTitle = in.readString();
+ program.mSeriesId = in.readString();
+ program.mEpisodeTitle = in.readString();
+ program.mSeasonNumber = in.readString();
+ program.mSeasonTitle = in.readString();
+ program.mEpisodeNumber = in.readString();
+ program.mStartTimeUtcMillis = in.readLong();
+ program.mEndTimeUtcMillis = in.readLong();
+ program.mDescription = in.readString();
+ program.mLongDescription = in.readString();
+ program.mVideoWidth = in.readInt();
+ program.mVideoHeight = in.readInt();
+ program.mCriticScores = in.readArrayList(Thread.currentThread().getContextClassLoader());
+ program.mPosterArtUri = in.readString();
+ program.mThumbnailUri = in.readString();
+ program.mCanonicalGenreIds = in.createIntArray();
+ int length = in.readInt();
+ if (length > 0) {
+ program.mContentRatings = new TvContentRating[length];
+ for (int i = 0; i < length; ++i) {
+ program.mContentRatings[i] = TvContentRating.unflattenFromString(in.readString());
+ }
+ }
+ program.mRecordingProhibited = in.readByte() != (byte) 0;
+ return program;
+ }
+
+ public static final Parcelable.Creator<Program> CREATOR = new Parcelable.Creator<Program>() {
+ @Override
+ public Program createFromParcel(Parcel in) {
+ return Program.fromParcel(in);
+ }
+
+ @Override
+ public Program[] newArray(int size) {
+ return new Program[size];
+ }
+ };
+
private long mId;
+ private String mPackageName;
private long mChannelId;
private String mTitle;
+ private String mSeriesId;
private String mEpisodeTitle;
private String mSeasonNumber;
private String mSeasonTitle;
@@ -125,17 +203,19 @@ public final class Program implements Comparable<Program> {
private long mStartTimeUtcMillis;
private long mEndTimeUtcMillis;
private String mDescription;
+ private String mLongDescription;
private int mVideoWidth;
private int mVideoHeight;
+ private List<CriticScore> mCriticScores;
private String mPosterArtUri;
private String mThumbnailUri;
private int[] mCanonicalGenreIds;
private TvContentRating[] mContentRatings;
+ private boolean mRecordingProhibited;
/**
* TODO(DVR): Need to fill the following data.
*/
- private boolean mRecordable;
private boolean mRecordingScheduled;
private Program() {
@@ -146,6 +226,13 @@ public final class Program implements Comparable<Program> {
return mId;
}
+ /**
+ * Returns the package name of this program.
+ */
+ public String getPackageName() {
+ return mPackageName;
+ }
+
public long getChannelId() {
return mChannelId;
}
@@ -153,6 +240,7 @@ public final class Program implements Comparable<Program> {
/**
* Returns {@code true} if this program is valid or {@code false} otherwise.
*/
+ @Override
public boolean isValid() {
return mChannelId >= 0;
}
@@ -164,35 +252,77 @@ public final class Program implements Comparable<Program> {
return program != null && program.isValid();
}
+ @Override
public String getTitle() {
return mTitle;
}
+ /**
+ * Returns the series ID.
+ */
+ @Override
+ public String getSeriesId() {
+ return mSeriesId;
+ }
+
+ /**
+ * Returns the episode title.
+ */
public String getEpisodeTitle() {
return mEpisodeTitle;
}
+ /**
+ * Returns season number, episode number and episode title for display.
+ */
+ @Override
public String getEpisodeDisplayTitle(Context context) {
- if (!TextUtils.isEmpty(mSeasonNumber) && !TextUtils.isEmpty(mEpisodeNumber)
- && !TextUtils.isEmpty(mEpisodeTitle)) {
- return String.format(context.getResources().getString(R.string.episode_format),
- mSeasonNumber, mEpisodeNumber, mEpisodeTitle);
+ if (!TextUtils.isEmpty(mEpisodeNumber)) {
+ String episodeTitle = mEpisodeTitle == null ? "" : mEpisodeTitle;
+ if (TextUtils.equals(mSeasonNumber, "0")) {
+ // Do not show "S0: ".
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format_no_season_number),
+ mEpisodeNumber, episodeTitle);
+ } else {
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format),
+ mSeasonNumber, mEpisodeNumber, episodeTitle);
+ }
}
return mEpisodeTitle;
}
+ @Override
+ public String getTitleWithEpisodeNumber(Context context) {
+ if (TextUtils.isEmpty(mTitle)) {
+ return mTitle;
+ }
+ if (TextUtils.isEmpty(mSeasonNumber) || mSeasonNumber.equals("0")) {
+ return TextUtils.isEmpty(mEpisodeNumber) ? mTitle : context.getString(
+ R.string.program_title_with_episode_number_no_season, mTitle, mEpisodeNumber);
+ } else {
+ return context.getString(R.string.program_title_with_episode_number, mTitle,
+ mSeasonNumber, mEpisodeNumber);
+ }
+ }
+
+ @Override
public String getSeasonNumber() {
return mSeasonNumber;
}
+ @Override
public String getEpisodeNumber() {
return mEpisodeNumber;
}
+ @Override
public long getStartTimeUtcMillis() {
return mStartTimeUtcMillis;
}
+ @Override
public long getEndTimeUtcMillis() {
return mEndTimeUtcMillis;
}
@@ -200,14 +330,21 @@ public final class Program implements Comparable<Program> {
/**
* Returns the program duration.
*/
+ @Override
public long getDurationMillis() {
return mEndTimeUtcMillis - mStartTimeUtcMillis;
}
+ @Override
public String getDescription() {
return mDescription;
}
+ @Override
+ public String getLongDescription() {
+ return mLongDescription;
+ }
+
public int getVideoWidth() {
return mVideoWidth;
}
@@ -216,22 +353,40 @@ public final class Program implements Comparable<Program> {
return mVideoHeight;
}
+ /**
+ * Returns the list of Critic Scores for this program
+ */
+ @Nullable
+ public List<CriticScore> getCriticScores() {
+ return mCriticScores;
+ }
+
public TvContentRating[] getContentRatings() {
return mContentRatings;
}
+ @Override
public String getPosterArtUri() {
return mPosterArtUri;
}
+ @Override
public String getThumbnailUri() {
return mThumbnailUri;
}
/**
+ * Returns {@code true} if the recording of this program is prohibited.
+ */
+ public boolean isRecordingProhibited() {
+ return mRecordingProhibited;
+ }
+
+ /**
* Returns array of canonical genres for this program.
* This is expected to be called rarely.
*/
+ @Nullable
public String[] getCanonicalGenres() {
if (mCanonicalGenreIds == null) {
return null;
@@ -244,6 +399,14 @@ public final class Program implements Comparable<Program> {
}
/**
+ * Returns array of canonical genre ID's for this program.
+ */
+ @Override
+ public int[] getCanonicalGenreIds() {
+ return mCanonicalGenreIds;
+ }
+
+ /**
* Returns if this program has the genre.
*/
public boolean hasGenre(int genreId) {
@@ -262,10 +425,12 @@ public final class Program implements Comparable<Program> {
@Override
public int hashCode() {
+ // Hash with all the properties because program ID can be invalid for the dummy programs.
return Objects.hash(mChannelId, mStartTimeUtcMillis, mEndTimeUtcMillis,
- mTitle, mEpisodeTitle, mDescription, mVideoWidth, mVideoHeight,
- mPosterArtUri, mThumbnailUri, Arrays.hashCode(mContentRatings),
- Arrays.hashCode(mCanonicalGenreIds), mSeasonNumber, mSeasonTitle, mEpisodeNumber);
+ mTitle, mSeriesId, mEpisodeTitle, mDescription, mLongDescription, mVideoWidth,
+ mVideoHeight, mPosterArtUri, mThumbnailUri, Arrays.hashCode(mContentRatings),
+ Arrays.hashCode(mCanonicalGenreIds), mSeasonNumber, mSeasonTitle, mEpisodeNumber,
+ mRecordingProhibited);
}
@Override
@@ -273,13 +438,17 @@ public final class Program implements Comparable<Program> {
if (!(other instanceof Program)) {
return false;
}
+ // Compare all the properties because program ID can be invalid for the dummy programs.
Program program = (Program) other;
- return mChannelId == program.mChannelId
+ return Objects.equals(mPackageName, program.mPackageName)
+ && mChannelId == program.mChannelId
&& mStartTimeUtcMillis == program.mStartTimeUtcMillis
&& mEndTimeUtcMillis == program.mEndTimeUtcMillis
&& Objects.equals(mTitle, program.mTitle)
+ && Objects.equals(mSeriesId, program.mSeriesId)
&& Objects.equals(mEpisodeTitle, program.mEpisodeTitle)
&& Objects.equals(mDescription, program.mDescription)
+ && Objects.equals(mLongDescription, program.mLongDescription)
&& mVideoWidth == program.mVideoWidth
&& mVideoHeight == program.mVideoHeight
&& Objects.equals(mPosterArtUri, program.mPosterArtUri)
@@ -288,7 +457,8 @@ public final class Program implements Comparable<Program> {
&& Arrays.equals(mCanonicalGenreIds, program.mCanonicalGenreIds)
&& Objects.equals(mSeasonNumber, program.mSeasonNumber)
&& Objects.equals(mSeasonTitle, program.mSeasonTitle)
- && Objects.equals(mEpisodeNumber, program.mEpisodeNumber);
+ && Objects.equals(mEpisodeNumber, program.mEpisodeNumber)
+ && mRecordingProhibited == program.mRecordingProhibited;
}
@Override
@@ -299,9 +469,11 @@ public final class Program implements Comparable<Program> {
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
- builder.append("Program[" + mId + "]{")
- .append("channelId=").append(mChannelId)
+ builder.append("Program[").append(mId)
+ .append("]{channelId=").append(mChannelId)
+ .append(", packageName=").append(mPackageName)
.append(", title=").append(mTitle)
+ .append(", seriesId=").append(mSeriesId)
.append(", episodeTitle=").append(mEpisodeTitle)
.append(", seasonNumber=").append(mSeasonNumber)
.append(", seasonTitle=").append(mSeasonTitle)
@@ -314,9 +486,11 @@ public final class Program implements Comparable<Program> {
.append(TvContentRatingCache.contentRatingsToString(mContentRatings))
.append(", posterArtUri=").append(mPosterArtUri)
.append(", thumbnailUri=").append(mThumbnailUri)
- .append(", canonicalGenres=").append(Arrays.toString(mCanonicalGenreIds));
+ .append(", canonicalGenres=").append(Arrays.toString(mCanonicalGenreIds))
+ .append(", recordingProhibited=").append(mRecordingProhibited);
if (DEBUG_DUMP_DESCRIPTION) {
- builder.append(", description=").append(mDescription);
+ builder.append(", description=").append(mDescription)
+ .append(", longDescription=").append(mLongDescription);
}
return builder.append("}").toString();
}
@@ -327,8 +501,10 @@ public final class Program implements Comparable<Program> {
}
mId = other.mId;
+ mPackageName = other.mPackageName;
mChannelId = other.mChannelId;
mTitle = other.mTitle;
+ mSeriesId = other.mSeriesId;
mEpisodeTitle = other.mEpisodeTitle;
mSeasonNumber = other.mSeasonNumber;
mSeasonTitle = other.mSeasonTitle;
@@ -336,21 +512,37 @@ public final class Program implements Comparable<Program> {
mStartTimeUtcMillis = other.mStartTimeUtcMillis;
mEndTimeUtcMillis = other.mEndTimeUtcMillis;
mDescription = other.mDescription;
+ mLongDescription = other.mLongDescription;
mVideoWidth = other.mVideoWidth;
mVideoHeight = other.mVideoHeight;
+ mCriticScores = other.mCriticScores;
mPosterArtUri = other.mPosterArtUri;
mThumbnailUri = other.mThumbnailUri;
mCanonicalGenreIds = other.mCanonicalGenreIds;
mContentRatings = other.mContentRatings;
+ mRecordingProhibited = other.mRecordingProhibited;
+ }
+
+ /**
+ * Checks whether the program is episodic or not.
+ */
+ public boolean isEpisodic() {
+ return mSeriesId != null;
}
+ /**
+ * A Builder for the Program class
+ */
public static final class Builder {
private final Program mProgram;
- private long mId;
+ /**
+ * Creates a Builder for this Program class
+ */
public Builder() {
mProgram = new Program();
// Fill initial data.
+ mProgram.mPackageName = null;
mProgram.mChannelId = Channel.INVALID_ID;
mProgram.mTitle = null;
mProgram.mSeasonNumber = null;
@@ -359,113 +551,258 @@ public final class Program implements Comparable<Program> {
mProgram.mStartTimeUtcMillis = -1;
mProgram.mEndTimeUtcMillis = -1;
mProgram.mDescription = null;
+ mProgram.mLongDescription = null;
+ mProgram.mRecordingProhibited = false;
+ mProgram.mCriticScores = null;
}
+ /**
+ * Creates a builder for this Program class
+ * by setting default values equivalent to another Program
+ * @param other the program to be copied
+ */
+ @VisibleForTesting
public Builder(Program other) {
mProgram = new Program();
mProgram.copyFrom(other);
}
+ /**
+ * Sets the ID of this program
+ * @param id the ID
+ * @return a reference to this object
+ */
public Builder setId(long id) {
mProgram.mId = id;
return this;
}
+ /**
+ * Sets the package name for this program
+ * @param packageName the package name
+ * @return a reference to this object
+ */
+ public Builder setPackageName(String packageName){
+ mProgram.mPackageName = packageName;
+ return this;
+ }
+
+ /**
+ * Sets the channel ID for this program
+ * @param channelId the channel ID
+ * @return a reference to this object
+ */
public Builder setChannelId(long channelId) {
mProgram.mChannelId = channelId;
return this;
}
+ /**
+ * Sets the program title
+ * @param title the title
+ * @return a reference to this object
+ */
public Builder setTitle(String title) {
mProgram.mTitle = title;
return this;
}
+ /**
+ * Sets the series ID.
+ * @param seriesId the series ID
+ * @return a reference to this object
+ */
+ public Builder setSeriesId(String seriesId) {
+ mProgram.mSeriesId = seriesId;
+ return this;
+ }
+
+ /**
+ * Sets the episode title if this is a series program
+ * @param episodeTitle the episode title
+ * @return a reference to this object
+ */
public Builder setEpisodeTitle(String episodeTitle) {
mProgram.mEpisodeTitle = episodeTitle;
return this;
}
+ /**
+ * Sets the season number if this is a series program
+ * @param seasonNumber the season number
+ * @return a reference to this object
+ */
public Builder setSeasonNumber(String seasonNumber) {
mProgram.mSeasonNumber = seasonNumber;
return this;
}
+
+ /**
+ * Sets the season title if this is a series program
+ * @param seasonTitle the season title
+ * @return a reference to this object
+ */
public Builder setSeasonTitle(String seasonTitle) {
mProgram.mSeasonTitle = seasonTitle;
return this;
}
+ /**
+ * Sets the episode number if this is a series program
+ * @param episodeNumber the episode number
+ * @return a reference to this object
+ */
public Builder setEpisodeNumber(String episodeNumber) {
mProgram.mEpisodeNumber = episodeNumber;
return this;
}
+ /**
+ * Sets the start time of this program
+ * @param startTimeUtcMillis the start time in UTC milliseconds
+ * @return a reference to this object
+ */
public Builder setStartTimeUtcMillis(long startTimeUtcMillis) {
mProgram.mStartTimeUtcMillis = startTimeUtcMillis;
return this;
}
+ /**
+ * Sets the end time of this program
+ * @param endTimeUtcMillis the end time in UTC milliseconds
+ * @return a reference to this object
+ */
public Builder setEndTimeUtcMillis(long endTimeUtcMillis) {
mProgram.mEndTimeUtcMillis = endTimeUtcMillis;
return this;
}
+ /**
+ * Sets a description
+ * @param description the description
+ * @return a reference to this object
+ */
public Builder setDescription(String description) {
mProgram.mDescription = description;
return this;
}
+ /**
+ * Sets a long description
+ * @param longDescription the long description
+ * @return a reference to this object
+ */
+ public Builder setLongDescription(String longDescription) {
+ mProgram.mLongDescription = longDescription;
+ return this;
+ }
+
+ /**
+ * Defines the video width of this program
+ * @param width
+ * @return a reference to this object
+ */
public Builder setVideoWidth(int width) {
mProgram.mVideoWidth = width;
return this;
}
+ /**
+ * Defines the video height of this program
+ * @param height
+ * @return a reference to this object
+ */
public Builder setVideoHeight(int height) {
mProgram.mVideoHeight = height;
return this;
}
+ /**
+ * Sets the content ratings for this program
+ * @param contentRatings the content ratings
+ * @return a reference to this object
+ */
public Builder setContentRatings(TvContentRating[] contentRatings) {
mProgram.mContentRatings = contentRatings;
return this;
}
+ /**
+ * Sets the poster art URI
+ * @param posterArtUri the poster art URI
+ * @return a reference to this object
+ */
public Builder setPosterArtUri(String posterArtUri) {
mProgram.mPosterArtUri = posterArtUri;
return this;
}
+ /**
+ * Sets the thumbnail URI
+ * @param thumbnailUri the thumbnail URI
+ * @return a reference to this object
+ */
public Builder setThumbnailUri(String thumbnailUri) {
mProgram.mThumbnailUri = thumbnailUri;
return this;
}
+ /**
+ * Sets the canonical genres by id
+ * @param genres the genres
+ * @return a reference to this object
+ */
public Builder setCanonicalGenres(String genres) {
- if (TextUtils.isEmpty(genres)) {
- return this;
- }
- String[] canonicalGenres = TvContract.Programs.Genres.decode(genres);
- if (canonicalGenres.length > 0) {
- int[] temp = new int[canonicalGenres.length];
- int i = 0;
- for (String canonicalGenre : canonicalGenres) {
- int genreId = GenreItems.getId(canonicalGenre);
- if (genreId == GenreItems.ID_ALL_CHANNELS) {
- // Skip if the genre is unknown.
- continue;
- }
- temp[i++] = genreId;
- }
- if (i < canonicalGenres.length) {
- temp = Arrays.copyOf(temp, i);
+ mProgram.mCanonicalGenreIds = Utils.getCanonicalGenreIds(genres);
+ return this;
+ }
+
+ /**
+ * Sets the recording prohibited flag
+ * @param recordingProhibited recording prohibited flag
+ * @return a reference to this object
+ */
+ public Builder setRecordingProhibited(boolean recordingProhibited) {
+ mProgram.mRecordingProhibited = recordingProhibited;
+ return this;
+ }
+
+ /**
+ * Adds a critic score
+ * @param criticScore the critic score
+ * @return a reference to this object
+ */
+ public Builder addCriticScore(CriticScore criticScore) {
+ if (criticScore.score != null) {
+ if (mProgram.mCriticScores == null) {
+ mProgram.mCriticScores = new ArrayList<>();
}
- mProgram.mCanonicalGenreIds=temp;
+ mProgram.mCriticScores.add(criticScore);
}
return this;
}
+ /**
+ * Sets the critic scores
+ * @param criticScores the critic scores
+ * @return a reference to this objects
+ */
+ public Builder setCriticScores(List<CriticScore> criticScores) {
+ mProgram.mCriticScores = criticScores;
+ return this;
+ }
+
+ /**
+ * Returns a reference to the Program object being constructed
+ * @return the Program object constructed
+ */
public Program build() {
+ // Generate the series ID for the episodic program of other TV input.
+ if (TextUtils.isEmpty(mProgram.mSeriesId)
+ && !TextUtils.isEmpty(mProgram.mEpisodeNumber)) {
+ setSeriesId(BaseProgram.generateSeriesId(mProgram.mPackageName, mProgram.mTitle));
+ }
Program program = new Program();
program.copyFrom(mProgram);
return program;
@@ -509,4 +846,96 @@ public final class Program implements Comparable<Program> {
}
return isDuplicate;
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int paramInt) {
+ out.writeLong(mId);
+ out.writeString(mPackageName);
+ out.writeLong(mChannelId);
+ out.writeString(mTitle);
+ out.writeString(mSeriesId);
+ out.writeString(mEpisodeTitle);
+ out.writeString(mSeasonNumber);
+ out.writeString(mSeasonTitle);
+ out.writeString(mEpisodeNumber);
+ out.writeLong(mStartTimeUtcMillis);
+ out.writeLong(mEndTimeUtcMillis);
+ out.writeString(mDescription);
+ out.writeString(mLongDescription);
+ out.writeInt(mVideoWidth);
+ out.writeInt(mVideoHeight);
+ out.writeList(mCriticScores);
+ out.writeString(mPosterArtUri);
+ out.writeString(mThumbnailUri);
+ out.writeIntArray(mCanonicalGenreIds);
+ out.writeInt(mContentRatings == null ? 0 : mContentRatings.length);
+ if (mContentRatings != null) {
+ for (TvContentRating rating : mContentRatings) {
+ out.writeString(rating.flattenToString());
+ }
+ }
+ out.writeByte((byte) (mRecordingProhibited ? 1 : 0));
+ }
+
+ /**
+ * Holds one type of critic score and its source.
+ */
+ public static final class CriticScore implements Serializable, Parcelable {
+ /**
+ * The source of the rating.
+ */
+ public final String source;
+ /**
+ * The score.
+ */
+ public final String score;
+ /**
+ * The url of the logo image
+ */
+ public final String logoUrl;
+
+ public static final Parcelable.Creator<CriticScore> CREATOR =
+ new Parcelable.Creator<CriticScore>() {
+ @Override
+ public CriticScore createFromParcel(Parcel in) {
+ String source = in.readString();
+ String score = in.readString();
+ String logoUri = in.readString();
+ return new CriticScore(source, score, logoUri);
+ }
+
+ @Override
+ public CriticScore[] newArray(int size) {
+ return new CriticScore[size];
+ }
+ };
+
+ /**
+ * Constructor for this class.
+ * @param source the source of the rating
+ * @param score the score
+ */
+ public CriticScore(String source, String score, String logoUrl) {
+ this.source = source;
+ this.score = score;
+ this.logoUrl = logoUrl;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int i) {
+ out.writeString(source);
+ out.writeString(score);
+ out.writeString(logoUrl);
+ }
+ }
}
diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java
index 88db91b9..d2af33a7 100644
--- a/src/com/android/tv/data/ProgramDataManager.java
+++ b/src/com/android/tv/data/ProgramDataManager.java
@@ -36,6 +36,7 @@ import android.util.LruCache;
import com.android.tv.common.MemoryManageable;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.epg.EpgFetcher;
+import com.android.tv.experiments.Experiments;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.Clock;
import com.android.tv.util.MultiLongSparseArray;
@@ -108,17 +109,17 @@ public class ProgramDataManager implements MemoryManageable {
private boolean mPauseProgramUpdate = false;
private final LruCache<Long, Program> mZeroLengthProgramCache = new LruCache<>(10);
-
- // TODO: Change to final.
- private EpgFetcher mEpgFetcher;
+ private final EpgFetcher mEpgFetcher;
public ProgramDataManager(Context context) {
- this(context.getContentResolver(), Clock.SYSTEM, Looper.myLooper());
- mEpgFetcher = new EpgFetcher(context);
+ this(context.getContentResolver(), Clock.SYSTEM, Looper.myLooper(),
+ EpgFetcher.getInstance(context));
}
@VisibleForTesting
- ProgramDataManager(ContentResolver contentResolver, Clock time, Looper looper) {
+ ProgramDataManager(ContentResolver contentResolver, Clock time, Looper looper,
+ EpgFetcher epgFetcher) {
+ mEpgFetcher = epgFetcher;
mClock = time;
mContentResolver = contentResolver;
mHandler = new MyHandler(looper);
@@ -174,7 +175,7 @@ public class ProgramDataManager implements MemoryManageable {
}
mContentResolver.registerContentObserver(Programs.CONTENT_URI,
true, mProgramObserver);
- if (mEpgFetcher != null) {
+ if (mEpgFetcher != null && Experiments.CLOUD_EPG.get()) {
mEpgFetcher.start();
}
}
@@ -624,22 +625,6 @@ public class ProgramDataManager implements MemoryManageable {
}
}
- /**
- * Gets an single {@link Program} from {@link TvContract.Programs#CONTENT_URI}.
- */
- public static class QueryProgramTask extends AsyncDbTask.AsyncQueryItemTask<Program> {
-
- public QueryProgramTask(ContentResolver contentResolver, long programId) {
- super(contentResolver, TvContract.buildProgramUri(programId), Program.PROJECTION, null,
- null, null);
- }
-
- @Override
- protected Program fromCursor(Cursor c) {
- return Program.fromCursor(c);
- }
- }
-
private class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
diff --git a/src/com/android/tv/data/StreamInfo.java b/src/com/android/tv/data/StreamInfo.java
index df842737..fe461f14 100644
--- a/src/com/android/tv/data/StreamInfo.java
+++ b/src/com/android/tv/data/StreamInfo.java
@@ -16,6 +16,8 @@
package com.android.tv.data;
+import android.media.tv.TvContentRating;
+
public interface StreamInfo {
int VIDEO_DEFINITION_LEVEL_UNKNOWN = 0;
int VIDEO_DEFINITION_LEVEL_SD = 1;
@@ -26,6 +28,7 @@ public interface StreamInfo {
int AUDIO_CHANNEL_COUNT_UNKNOWN = 0;
Channel getCurrentChannel();
+ TvContentRating getBlockedContentRating();
int getVideoWidth();
int getVideoHeight();
diff --git a/src/com/android/tv/data/WatchedHistoryManager.java b/src/com/android/tv/data/WatchedHistoryManager.java
index fc6672d2..59319338 100644
--- a/src/com/android/tv/data/WatchedHistoryManager.java
+++ b/src/com/android/tv/data/WatchedHistoryManager.java
@@ -219,7 +219,7 @@ public class WatchedHistoryManager {
}
Long duration = durationMap.get(channelId);
if (duration == null) {
- duration = 0l;
+ duration = 0L;
}
if (duration >= RECENT_CHANNEL_THRESHOLD_MS) {
continue;
diff --git a/src/com/android/tv/data/epg/EpgFetcher.java b/src/com/android/tv/data/epg/EpgFetcher.java
index 9ff527d8..3b093b6a 100644
--- a/src/com/android/tv/data/epg/EpgFetcher.java
+++ b/src/com/android/tv/data/epg/EpgFetcher.java
@@ -16,37 +16,48 @@
package com.android.tv.data.epg;
+import android.Manifest;
+import android.annotation.SuppressLint;
import android.content.ContentProviderOperation;
-import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
+import android.content.pm.PackageManager;
import android.database.Cursor;
+import android.location.Address;
+import android.media.tv.TvContentRating;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Programs;
+import android.media.tv.TvContract.Programs.Genres;
import android.media.tv.TvInputInfo;
-import android.media.tv.TvInputManager.TvInputCallback;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
import android.preference.PreferenceManager;
+import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
import android.text.TextUtils;
import android.util.Log;
-import com.android.tv.Features;
import com.android.tv.TvApplication;
import com.android.tv.common.WeakHandler;
import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.InternalDataUtils;
+import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.util.LocationUtils;
import com.android.tv.util.RecurringRunner;
-import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
@@ -61,116 +72,275 @@ public class EpgFetcher {
private static final long EPG_PREFETCH_RECURRING_PERIOD_MS = TimeUnit.HOURS.toMillis(4);
private static final long EPG_READER_INIT_WAIT_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long LOCATION_INIT_WAIT_MS = TimeUnit.SECONDS.toMillis(10);
+ private static final long LOCATION_ERROR_WAIT_MS = TimeUnit.HOURS.toMillis(1);
private static final long PROGRAM_QUERY_DURATION = TimeUnit.DAYS.toMillis(30);
private static final int BATCH_OPERATION_COUNT = 100;
+ private static final String SUPPORTED_COUNTRY_CODE = Locale.US.getCountry();
+ private static final String CONTENT_RATING_SEPARATOR = ",";
+
// Value: Long
private static final String KEY_LAST_UPDATED_EPG_TIMESTAMP =
"com.android.tv.data.epg.EpgFetcher.LastUpdatedEpgTimestamp";
+ // Value: String
+ private static final String KEY_LAST_LINEUP_ID =
+ "com.android.tv.data.epg.EpgFetcher.LastLineupId";
+
+ private static EpgFetcher sInstance;
private final Context mContext;
- private final TvInputManagerHelper mInputHelper;
- private final TvInputCallback mInputCallback;
- private HandlerThread mHandlerThread;
+ private final ChannelDataManager mChannelDataManager;
+ private final EpgReader mEpgReader;
private EpgFetcherHandler mHandler;
private RecurringRunner mRecurringRunner;
+ private boolean mStarted;
private long mLastEpgTimestamp = -1;
+ private String mLineupId;
+
+ public static synchronized EpgFetcher getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new EpgFetcher(context.getApplicationContext());
+ }
+ return sInstance;
+ }
+
+ /**
+ * Creates and returns {@link EpgReader}.
+ */
+ public static EpgReader createEpgReader(Context context) {
+ return new StubEpgReader(context);
+ }
- public EpgFetcher(Context context) {
+ private EpgFetcher(Context context) {
mContext = context;
- mInputHelper = TvApplication.getSingletons(mContext).getTvInputManagerHelper();
- mInputCallback = new TvInputCallback() {
+ mEpgReader = new StubEpgReader(mContext);
+ mChannelDataManager = TvApplication.getSingletons(context).getChannelDataManager();
+ mChannelDataManager.addListener(new ChannelDataManager.Listener() {
@Override
- public void onInputAdded(String inputId) {
- if (Utils.isInternalTvInput(mContext, inputId)) {
- mHandler.removeMessages(MSG_FETCH_EPG);
- mHandler.sendEmptyMessage(MSG_FETCH_EPG);
- }
+ public void onLoadFinished() {
+ if (DEBUG) Log.d(TAG, "ChannelDataManager.onLoadFinished()");
+ handleChannelChanged();
+ }
+
+ @Override
+ public void onChannelListUpdated() {
+ if (DEBUG) Log.d(TAG, "ChannelDataManager.onChannelListUpdated()");
+ handleChannelChanged();
+ }
+
+ @Override
+ public void onChannelBrowsableChanged() {
+ if (DEBUG) Log.d(TAG, "ChannelDataManager.onChannelBrowsableChanged()");
+ handleChannelChanged();
+ }
+ });
+ }
+
+ private void handleChannelChanged() {
+ if (mStarted) {
+ if (needToStop()) {
+ stop();
}
- };
+ } else {
+ start();
+ }
+ }
+
+ private boolean needToStop() {
+ return !canStart();
+ }
+
+ private boolean canStart() {
+ if (DEBUG) Log.d(TAG, "canStart()");
+ boolean hasInternalTunerChannel = false;
+ for (TvInputInfo input : TvApplication.getSingletons(mContext).getTvInputManagerHelper()
+ .getTvInputInfos(true, true)) {
+ String inputId = input.getId();
+ if (Utils.isInternalTvInput(mContext, inputId)
+ && mChannelDataManager.getChannelCountForInput(inputId) > 0) {
+ hasInternalTunerChannel = true;
+ break;
+ }
+ }
+ if (!hasInternalTunerChannel) {
+ if (DEBUG) Log.d(TAG, "No internal tuner channels.");
+ return false;
+ }
+
+ if (!TextUtils.isEmpty(getLastLineupId())) {
+ return true;
+ }
+ if (mContext.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ if (DEBUG) Log.d(TAG, "No permission to check the current location.");
+ return false;
+ }
+
+ try {
+ Address address = LocationUtils.getCurrentAddress(mContext);
+ if (address != null
+ && !TextUtils.equals(address.getCountryCode(), SUPPORTED_COUNTRY_CODE)) {
+ if (DEBUG) Log.d(TAG, "Country not supported: " + address.getCountryCode());
+ return false;
+ }
+ } catch (SecurityException e) {
+ Log.w(TAG, "No permission to get the current location", e);
+ return false;
+ } catch (IOException e) {
+ Log.w(TAG, "IO Exception when getting the current location", e);
+ }
+ return true;
}
/**
* Starts fetching EPG.
*/
+ @MainThread
public void start() {
- if (DEBUG) Log.d(TAG, "Request to start fetching EPG.");
- if (!Features.FETCH_EPG.isEnabled(mContext)) {
+ if (DEBUG) Log.d(TAG, "start()");
+ if (mStarted) {
+ if (DEBUG) Log.d(TAG, "EpgFetcher thread already started.");
return;
}
- if (mHandlerThread == null) {
- mHandlerThread = new HandlerThread("EpgFetcher");
- mHandlerThread.start();
- mHandler = new EpgFetcherHandler(mHandlerThread.getLooper(), this);
- mInputHelper.addCallback(mInputCallback);
- mRecurringRunner = new RecurringRunner(mContext, EPG_PREFETCH_RECURRING_PERIOD_MS,
- new Runnable() {
- @Override
- public void run() {
- mHandler.removeMessages(MSG_FETCH_EPG);
- mHandler.sendEmptyMessage(MSG_FETCH_EPG);
- }
- }, null);
- mRecurringRunner.start();
+ if (!canStart()) {
+ return;
+ }
+ mStarted = true;
+ if (DEBUG) Log.d(TAG, "Starting EpgFetcher thread.");
+ HandlerThread handlerThread = new HandlerThread("EpgFetcher");
+ handlerThread.start();
+ mHandler = new EpgFetcherHandler(handlerThread.getLooper(), this);
+ mRecurringRunner = new RecurringRunner(mContext, EPG_PREFETCH_RECURRING_PERIOD_MS,
+ new EpgRunner(), null);
+ mRecurringRunner.start();
+ if (DEBUG) Log.d(TAG, "EpgFetcher thread started successfully.");
+ }
+
+ /**
+ * Starts fetching EPG immediately if possible without waiting for the timer.
+ */
+ @MainThread
+ public void startImmediately() {
+ start();
+ if (mStarted) {
+ if (DEBUG) Log.d(TAG, "Starting fetcher immediately");
+ fetchEpg();
}
}
/**
* Stops fetching EPG.
*/
+ @MainThread
public void stop() {
- if (mHandlerThread == null) {
+ if (DEBUG) Log.d(TAG, "stop()");
+ if (!mStarted) {
return;
}
+ mStarted = false;
mRecurringRunner.stop();
mHandler.removeCallbacksAndMessages(null);
- mHandler = null;
- mHandlerThread.quit();
- mHandlerThread = null;
+ mHandler.getLooper().quit();
+ }
+
+ private void fetchEpg() {
+ fetchEpg(0);
+ }
+
+ private void fetchEpg(long delay) {
+ mHandler.removeMessages(MSG_FETCH_EPG);
+ mHandler.sendEmptyMessageDelayed(MSG_FETCH_EPG, delay);
}
private void onFetchEpg() {
if (DEBUG) Log.d(TAG, "Start fetching EPG.");
- // Check for the internal inputs.
- boolean hasInternalInput = false;
- for (TvInputInfo input : mInputHelper.getTvInputInfos(true, true)) {
- if (Utils.isInternalTvInput(mContext, input.getId())) {
- hasInternalInput = true;
- break;
- }
- }
- if (!hasInternalInput) {
- if (DEBUG) Log.d(TAG, "No internal input found.");
- return;
- }
- // Check if EPG reader is available.
- EpgReader epgReader = new StubEpgReader(mContext);
- if (!epgReader.isAvailable()) {
+ if (!mEpgReader.isAvailable()) {
if (DEBUG) Log.d(TAG, "EPG reader is not temporarily available.");
- mHandler.removeMessages(MSG_FETCH_EPG);
- mHandler.sendEmptyMessageDelayed(MSG_FETCH_EPG, EPG_READER_INIT_WAIT_MS);
+ fetchEpg(EPG_READER_INIT_WAIT_MS);
return;
}
+ String lineupId = getLastLineupId();
+ if (lineupId == null) {
+ Address address;
+ try {
+ address = LocationUtils.getCurrentAddress(mContext);
+ } catch (IOException e) {
+ if (DEBUG) Log.d(TAG, "Couldn't get the current location.", e);
+ fetchEpg(LOCATION_ERROR_WAIT_MS);
+ return;
+ } catch (SecurityException e) {
+ Log.w(TAG, "No permission to get the current location.");
+ return;
+ }
+ if (address == null) {
+ if (DEBUG) Log.d(TAG, "Null address returned.");
+ fetchEpg(LOCATION_INIT_WAIT_MS);
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Current location is " + address);
+
+ lineupId = getLineupForAddress(address);
+ if (lineupId != null) {
+ if (DEBUG) Log.d(TAG, "Saving lineup " + lineupId + "found for " + address);
+ setLastLineupId(lineupId);
+ } else {
+ if (DEBUG) Log.d(TAG, "No lineup found for " + address);
+ return;
+ }
+ }
+
// Check the EPG Timestamp.
- long epgTimestamp = epgReader.getEpgTimestamp();
+ long epgTimestamp = mEpgReader.getEpgTimestamp();
if (epgTimestamp <= getLastUpdatedEpgTimestamp()) {
if (DEBUG) Log.d(TAG, "No new EPG.");
return;
}
- List<Channel> channels = epgReader.getChannels();
+ boolean updated = false;
+ List<Channel> channels = mEpgReader.getChannels(lineupId);
for (Channel channel : channels) {
- List<Program> programs = new ArrayList<>(epgReader.getPrograms(channel.getId()));
+ List<Program> programs = new ArrayList<>(mEpgReader.getPrograms(channel.getId()));
Collections.sort(programs);
if (DEBUG) {
- Log.d(TAG, "Fetching " + programs.size() + " programs for channel " + channel);
+ Log.d(TAG, "Fetched " + programs.size() + " programs for channel " + channel);
+ }
+ if (updateEpg(channel.getId(), programs)) {
+ updated = true;
}
- updateEpg(channel.getId(), programs);
}
+ final boolean epgUpdated = updated;
setLastUpdatedEpgTimestamp(epgTimestamp);
+ mHandler.removeMessages(MSG_FETCH_EPG);
+ if (DEBUG) Log.d(TAG, "Fetching EPG is finished.");
+ }
+
+ @Nullable
+ private String getLineupForAddress(Address address) {
+ String lineup = null;
+ if (TextUtils.equals(address.getCountryCode(), SUPPORTED_COUNTRY_CODE)) {
+ String postalCode = address.getPostalCode();
+ if (!TextUtils.isEmpty(postalCode)) {
+ lineup = getLineupForPostalCode(postalCode);
+ }
+ }
+ return lineup;
+ }
+
+ @Nullable
+ private String getLineupForPostalCode(String postalCode) {
+ List<Lineup> lineups = mEpgReader.getLineups(postalCode);
+ for (Lineup lineup : lineups) {
+ // TODO(EPG): handle more than OTA digital
+ if (lineup.type == Lineup.LINEUP_BROADCAST_DIGITAL) {
+ if (DEBUG) Log.d(TAG, "Setting lineup to " + lineup.name + "(" + lineup.id + ")");
+ return lineup.id;
+ }
+ }
+ return null;
}
private long getLastUpdatedEpgTimestamp() {
@@ -184,18 +354,33 @@ public class EpgFetcher {
private void setLastUpdatedEpgTimestamp(long timestamp) {
mLastEpgTimestamp = timestamp;
PreferenceManager.getDefaultSharedPreferences(mContext).edit().putLong(
- KEY_LAST_UPDATED_EPG_TIMESTAMP, timestamp);
+ KEY_LAST_UPDATED_EPG_TIMESTAMP, timestamp).commit();
+ }
+
+ private String getLastLineupId() {
+ if (mLineupId == null) {
+ mLineupId = PreferenceManager.getDefaultSharedPreferences(mContext)
+ .getString(KEY_LAST_LINEUP_ID, null);
+ }
+ if (DEBUG) Log.d(TAG, "Last lineup_id " + mLineupId);
+ return mLineupId;
}
- private void updateEpg(long channelId, List<Program> newPrograms) {
+ private void setLastLineupId(String lineupId) {
+ mLineupId = lineupId;
+ PreferenceManager.getDefaultSharedPreferences(mContext).edit()
+ .putString(KEY_LAST_LINEUP_ID, lineupId).commit();
+ }
+
+ private boolean updateEpg(long channelId, List<Program> newPrograms) {
final int fetchedProgramsCount = newPrograms.size();
if (fetchedProgramsCount == 0) {
- return;
+ return false;
}
+ boolean updated = false;
long startTimeMs = System.currentTimeMillis();
long endTimeMs = startTimeMs + PROGRAM_QUERY_DURATION;
- List<Program> oldPrograms = queryPrograms(mContext.getContentResolver(), channelId,
- startTimeMs, endTimeMs);
+ List<Program> oldPrograms = queryPrograms(channelId, startTimeMs, endTimeMs);
Program currentOldProgram = oldPrograms.size() > 0 ? oldPrograms.get(0) : null;
int oldProgramsIndex = 0;
int newProgramsIndex = 0;
@@ -224,15 +409,13 @@ public class EpgFetcher {
oldProgramsIndex++;
newProgramsIndex++;
} else if (isSameTitleAndOverlap(oldProgram, newProgram)) {
- if (!oldProgram.equals(oldProgram)) {
- // Partial match. Update the old program with the new one.
- // NOTE: Use 'update' in this case instead of 'insert' and 'delete'. There
- // could be application specific settings which belong to the old program.
- ops.add(ContentProviderOperation.newUpdate(
- TvContract.buildProgramUri(oldProgram.getId()))
- .withValues(toContentValues(newProgram))
- .build());
- }
+ // Partial match. Update the old program with the new one.
+ // NOTE: Use 'update' in this case instead of 'insert' and 'delete'. There
+ // could be application specific settings which belong to the old program.
+ ops.add(ContentProviderOperation.newUpdate(
+ TvContract.buildProgramUri(oldProgram.getId()))
+ .withValues(toContentValues(newProgram))
+ .build());
oldProgramsIndex++;
newProgramsIndex++;
} else if (oldProgram.getEndTimeUtcMillis()
@@ -271,25 +454,26 @@ public class EpgFetcher {
}
}
mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
+ updated = true;
} catch (RemoteException | OperationApplicationException e) {
Log.e(TAG, "Failed to insert programs.", e);
- return;
+ return updated;
}
ops.clear();
}
}
if (DEBUG) {
- Log.d(TAG, "Fetched " + fetchedProgramsCount + " programs for channel " + channelId);
+ Log.d(TAG, "Updated " + fetchedProgramsCount + " programs for channel " + channelId);
}
+ return updated;
}
- private List<Program> queryPrograms(ContentResolver contentResolver, long channelId,
- long startTimeMs, long endTimeMs) {
+ private List<Program> queryPrograms(long channelId, long startTimeMs, long endTimeMs) {
try (Cursor c = mContext.getContentResolver().query(
TvContract.buildProgramsUriForChannel(channelId, startTimeMs, endTimeMs),
Program.PROJECTION, null, null, Programs.COLUMN_START_TIME_UTC_MILLIS)) {
if (c == null) {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
}
ArrayList<Program> programs = new ArrayList<>();
while (c.moveToNext()) {
@@ -313,18 +497,48 @@ public class EpgFetcher {
&& newProgram.getStartTimeUtcMillis() <= oldProgram.getEndTimeUtcMillis();
}
+ @SuppressLint("InlinedApi")
+ @SuppressWarnings("deprecation")
private static ContentValues toContentValues(Program program) {
ContentValues values = new ContentValues();
values.put(TvContract.Programs.COLUMN_CHANNEL_ID, program.getChannelId());
putValue(values, TvContract.Programs.COLUMN_TITLE, program.getTitle());
putValue(values, TvContract.Programs.COLUMN_EPISODE_TITLE, program.getEpisodeTitle());
- putValue(values, TvContract.Programs.COLUMN_SEASON_NUMBER, program.getSeasonNumber());
- putValue(values, TvContract.Programs.COLUMN_EPISODE_NUMBER, program.getEpisodeNumber());
+ if (BuildCompat.isAtLeastN()) {
+ putValue(values, TvContract.Programs.COLUMN_SEASON_DISPLAY_NUMBER,
+ program.getSeasonNumber());
+ putValue(values, TvContract.Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
+ program.getEpisodeNumber());
+ } else {
+ putValue(values, TvContract.Programs.COLUMN_SEASON_NUMBER, program.getSeasonNumber());
+ putValue(values, TvContract.Programs.COLUMN_EPISODE_NUMBER, program.getEpisodeNumber());
+ }
putValue(values, TvContract.Programs.COLUMN_SHORT_DESCRIPTION, program.getDescription());
putValue(values, TvContract.Programs.COLUMN_POSTER_ART_URI, program.getPosterArtUri());
+ putValue(values, TvContract.Programs.COLUMN_THUMBNAIL_URI, program.getThumbnailUri());
+ String[] canonicalGenres = program.getCanonicalGenres();
+ if (canonicalGenres != null && canonicalGenres.length > 0) {
+ putValue(values, TvContract.Programs.COLUMN_CANONICAL_GENRE,
+ Genres.encode(canonicalGenres));
+ } else {
+ putValue(values, TvContract.Programs.COLUMN_CANONICAL_GENRE, "");
+ }
+ TvContentRating[] ratings = program.getContentRatings();
+ if (ratings != null && ratings.length > 0) {
+ StringBuilder sb = new StringBuilder(ratings[0].flattenToString());
+ for (int i = 1; i < ratings.length; ++i) {
+ sb.append(CONTENT_RATING_SEPARATOR);
+ sb.append(ratings[i].flattenToString());
+ }
+ putValue(values, TvContract.Programs.COLUMN_CONTENT_RATING, sb.toString());
+ } else {
+ putValue(values, TvContract.Programs.COLUMN_CONTENT_RATING, "");
+ }
values.put(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
program.getStartTimeUtcMillis());
values.put(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS, program.getEndTimeUtcMillis());
+ putValue(values, TvContract.Programs.COLUMN_INTERNAL_PROVIDER_DATA,
+ InternalDataUtils.serializeInternalProviderData(program));
return values;
}
@@ -336,6 +550,14 @@ public class EpgFetcher {
}
}
+ private static void putValue(ContentValues contentValues, String key, byte[] value) {
+ if (value == null || value.length == 0) {
+ contentValues.putNull(key);
+ } else {
+ contentValues.put(key, value);
+ }
+ }
+
private static class EpgFetcherHandler extends WeakHandler<EpgFetcher> {
public EpgFetcherHandler (@NonNull Looper looper, EpgFetcher ref) {
super(looper, ref);
@@ -353,4 +575,11 @@ public class EpgFetcher {
}
}
}
+
+ private class EpgRunner implements Runnable {
+ @Override
+ public void run() {
+ fetchEpg();
+ }
+ }
}
diff --git a/src/com/android/tv/data/epg/EpgReader.java b/src/com/android/tv/data/epg/EpgReader.java
index 1c7712f4..4f3b6f52 100644
--- a/src/com/android/tv/data/epg/EpgReader.java
+++ b/src/com/android/tv/data/epg/EpgReader.java
@@ -16,10 +16,13 @@
package com.android.tv.data.epg;
+import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
import com.android.tv.data.Channel;
+import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.dvr.SeriesInfo;
import java.util.List;
@@ -42,7 +45,12 @@ public interface EpgReader {
/**
* Returns the channels list.
*/
- List<Channel> getChannels();
+ List<Channel> getChannels(@NonNull String lineupId);
+
+ /**
+ * Returns the lineups list.
+ */
+ List<Lineup> getLineups(@NonNull String postalCode);
/**
* Returns the programs for the given channel. The result is sorted by the start time.
@@ -50,4 +58,9 @@ public interface EpgReader {
* TvProvider.
*/
List<Program> getPrograms(long channelId);
+
+ /**
+ * Returns the series information for the given series ID.
+ */
+ SeriesInfo getSeriesInfo(String seriesId);
}
diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java
index 2896e8e5..64093f89 100644
--- a/src/com/android/tv/data/epg/StubEpgReader.java
+++ b/src/com/android/tv/data/epg/StubEpgReader.java
@@ -19,7 +19,9 @@ package com.android.tv.data.epg;
import android.content.Context;
import com.android.tv.data.Channel;
+import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.dvr.SeriesInfo;
import java.util.Collections;
import java.util.List;
@@ -28,7 +30,7 @@ import java.util.List;
* A stub class to read EPG.
*/
public class StubEpgReader implements EpgReader{
- public StubEpgReader(Context context) {
+ public StubEpgReader(@SuppressWarnings("unused") Context context) {
}
@Override
@@ -42,12 +44,22 @@ public class StubEpgReader implements EpgReader{
}
@Override
- public List<Channel> getChannels() {
- return Collections.EMPTY_LIST;
+ public List<Channel> getChannels(String lineupId) {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List<Lineup> getLineups(String postalCode) {
+ return Collections.emptyList();
}
@Override
public List<Program> getPrograms(long channelId) {
- return Collections.EMPTY_LIST;
+ return Collections.emptyList();
+ }
+
+ @Override
+ public SeriesInfo getSeriesInfo(String seriesId) {
+ return null;
}
}
diff --git a/src/com/android/tv/dialog/PinDialogFragment.java b/src/com/android/tv/dialog/PinDialogFragment.java
index 3952bb0b..d9d6c73f 100644
--- a/src/com/android/tv/dialog/PinDialogFragment.java
+++ b/src/com/android/tv/dialog/PinDialogFragment.java
@@ -75,6 +75,11 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
// 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
+ */
+ public static final int PIN_DIALOG_TYPE_UNLOCK_DVR = 5;
+
private static final int PIN_DIALOG_RESULT_SUCCESS = 0;
private static final int PIN_DIALOG_RESULT_FAIL = 1;
@@ -104,14 +109,20 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
private SharedPreferences mSharedPreferences;
private String mPrevPin;
private String mPin;
+ private String mRatingString;
private int mWrongPinCount;
private long mDisablePinUntil;
private final Handler mHandler = new Handler();
public PinDialogFragment(int type, ResultListener listener) {
+ this(type, listener, null);
+ }
+
+ public PinDialogFragment(int type, ResultListener listener, String rating) {
mType = type;
mListener = listener;
mRetCode = PIN_DIALOG_RESULT_FAIL;
+ mRatingString = rating;
}
@Override
@@ -174,6 +185,9 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
case PIN_DIALOG_TYPE_UNLOCK_PROGRAM:
mTitleView.setText(R.string.pin_enter_unlock_program);
break;
+ case PIN_DIALOG_TYPE_UNLOCK_DVR:
+ mTitleView.setText(getString(R.string.pin_enter_unlock_dvr, mRatingString));
+ break;
case PIN_DIALOG_TYPE_ENTER_PIN:
mTitleView.setText(R.string.pin_enter_pin);
break;
@@ -269,6 +283,7 @@ public class PinDialogFragment extends SafeDismissDialogFragment {
switch (mType) {
case PIN_DIALOG_TYPE_UNLOCK_CHANNEL:
case PIN_DIALOG_TYPE_UNLOCK_PROGRAM:
+ case PIN_DIALOG_TYPE_UNLOCK_DVR:
case PIN_DIALOG_TYPE_ENTER_PIN:
// TODO: Implement limited number of retrials and timeout logic.
if (TextUtils.isEmpty(getPin()) || pin.equals(getPin())) {
diff --git a/src/com/android/tv/dialog/SafeDismissDialogFragment.java b/src/com/android/tv/dialog/SafeDismissDialogFragment.java
index 1569f0a9..f671a87d 100644
--- a/src/com/android/tv/dialog/SafeDismissDialogFragment.java
+++ b/src/com/android/tv/dialog/SafeDismissDialogFragment.java
@@ -47,7 +47,9 @@ public abstract class SafeDismissDialogFragment extends DialogFragment
public void onAttach(Activity activity) {
super.onAttach(activity);
mAttached = true;
- mActivity = (MainActivity) activity;
+ if (activity instanceof MainActivity) {
+ mActivity = (MainActivity) activity;
+ }
mTracker = TvApplication.getSingletons(activity).getTracker();
if (mDismissPending) {
mDismissPending = false;
@@ -100,7 +102,7 @@ public abstract class SafeDismissDialogFragment extends DialogFragment
public boolean onKeyUp(int keyCode, KeyEvent event) {
// When a dialog is showing, key events are handled by the dialog instead of
// MainActivity. Therefore, unless a key is a global key, it should be handled here.
- if (mAttached && keyCode == KeyEvent.KEYCODE_SEARCH) {
+ if (mAttached && keyCode == KeyEvent.KEYCODE_SEARCH && mActivity != null) {
mActivity.showSearchActivity();
return true;
}
diff --git a/src/com/android/tv/dvr/BaseDvrDataManager.java b/src/com/android/tv/dvr/BaseDvrDataManager.java
index 0fb469be..89661df3 100644
--- a/src/com/android/tv/dvr/BaseDvrDataManager.java
+++ b/src/com/android/tv/dvr/BaseDvrDataManager.java
@@ -20,17 +20,24 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
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.recording.RecordedProgram;
+import com.android.tv.dvr.ScheduledRecording.RecordingState;
import com.android.tv.util.Clock;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
/**
* Base implementation of @{link DataManagerInternal}.
@@ -42,8 +49,14 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
private final static boolean DEBUG = false;
protected final Clock mClock;
+ private final Set<OnDvrScheduleLoadFinishedListener> mOnDvrScheduleLoadFinishedListeners =
+ new CopyOnWriteArraySet<>();
+ private final Set<OnRecordedProgramLoadFinishedListener>
+ mOnRecordedProgramLoadFinishedListeners = new CopyOnWriteArraySet<>();
private final Set<ScheduledRecordingListener> mScheduledRecordingListeners = new ArraySet<>();
+ private final Set<SeriesRecordingListener> mSeriesRecordingListeners = new ArraySet<>();
private final Set<RecordedProgramListener> mRecordedProgramListeners = new ArraySet<>();
+ private final HashMap<Long, ScheduledRecording> mDeletedScheduleMap = new HashMap<>();
BaseDvrDataManager(Context context, Clock clock) {
SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
@@ -51,6 +64,28 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
@Override
+ public void addDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener) {
+ mOnDvrScheduleLoadFinishedListeners.add(listener);
+ }
+
+ @Override
+ public void removeDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener) {
+ mOnDvrScheduleLoadFinishedListeners.remove(listener);
+ }
+
+ @Override
+ public void addRecordedProgramLoadFinishedListener(
+ OnRecordedProgramLoadFinishedListener listener) {
+ mOnRecordedProgramLoadFinishedListeners.add(listener);
+ }
+
+ @Override
+ public void removeRecordedProgramLoadFinishedListener(
+ OnRecordedProgramLoadFinishedListener listener) {
+ mOnRecordedProgramLoadFinishedListeners.remove(listener);
+ }
+
+ @Override
public final void addScheduledRecordingListener(ScheduledRecordingListener listener) {
mScheduledRecordingListeners.add(listener);
}
@@ -61,6 +96,16 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
@Override
+ public final void addSeriesRecordingListener(SeriesRecordingListener listener) {
+ mSeriesRecordingListeners.add(listener);
+ }
+
+ @Override
+ public final void removeSeriesRecordingListener(SeriesRecordingListener listener) {
+ mSeriesRecordingListeners.remove(listener);
+ }
+
+ @Override
public final void addRecordedProgramListener(RecordedProgramListener listener) {
mRecordedProgramListeners.add(listener);
}
@@ -71,71 +116,124 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
/**
- * Calls {@link RecordedProgramListener#onRecordedProgramAdded(RecordedProgram)}
+ * Calls {@link OnDvrScheduleLoadFinishedListener#onDvrScheduleLoadFinished} for each listener.
+ */
+ protected final void notifyDvrScheduleLoadFinished() {
+ for (OnDvrScheduleLoadFinishedListener l : mOnDvrScheduleLoadFinishedListeners) {
+ if (DEBUG) Log.d(TAG, "notify DVR schedule load finished");
+ l.onDvrScheduleLoadFinished();
+ }
+ }
+
+ /**
+ * Calls {@link OnRecordedProgramLoadFinishedListener#onRecordedProgramLoadFinished()}
+ * for each listener.
+ */
+ protected final void notifyRecordedProgramLoadFinished() {
+ for (OnRecordedProgramLoadFinishedListener l : mOnRecordedProgramLoadFinishedListeners) {
+ if (DEBUG) Log.d(TAG, "notify recorded programs load finished");
+ l.onRecordedProgramLoadFinished();
+ }
+ }
+
+ /**
+ * Calls {@link RecordedProgramListener#onRecordedProgramsAdded}
* for each listener.
*/
- protected final void notifyRecordedProgramAdded(RecordedProgram recordedProgram) {
+ protected final void notifyRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
for (RecordedProgramListener l : mRecordedProgramListeners) {
- if (DEBUG) Log.d(TAG, "notify " + l + "added " + recordedProgram);
- l.onRecordedProgramAdded(recordedProgram);
+ if (DEBUG) Log.d(TAG, "notify " + l + " added " + Arrays.asList(recordedPrograms));
+ l.onRecordedProgramsAdded(recordedPrograms);
}
}
/**
- * Calls {@link RecordedProgramListener#onRecordedProgramChanged(RecordedProgram)}
+ * Calls {@link RecordedProgramListener#onRecordedProgramsChanged}
* for each listener.
*/
- protected final void notifyRecordedProgramChanged(RecordedProgram recordedProgram) {
+ protected final void notifyRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
for (RecordedProgramListener l : mRecordedProgramListeners) {
- if (DEBUG) Log.d(TAG, "notify " + l + "changed " + recordedProgram);
- l.onRecordedProgramChanged(recordedProgram);
+ if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(recordedPrograms));
+ l.onRecordedProgramsChanged(recordedPrograms);
}
}
/**
- * Calls {@link RecordedProgramListener#onRecordedProgramRemoved(RecordedProgram)}
+ * Calls {@link RecordedProgramListener#onRecordedProgramsRemoved}
* for each listener.
*/
- protected final void notifyRecordedProgramRemoved(RecordedProgram recordedProgram) {
+ protected final void notifyRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
for (RecordedProgramListener l : mRecordedProgramListeners) {
- if (DEBUG) Log.d(TAG, "notify " + l + "removed " + recordedProgram);
- l.onRecordedProgramRemoved(recordedProgram);
+ if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(recordedPrograms));
+ l.onRecordedProgramsRemoved(recordedPrograms);
+ }
+ }
+
+ /**
+ * Calls {@link SeriesRecordingListener#onSeriesRecordingAdded}
+ * for each listener.
+ */
+ protected final void notifySeriesRecordingAdded(SeriesRecording... seriesRecordings) {
+ for (SeriesRecordingListener l : mSeriesRecordingListeners) {
+ if (DEBUG) Log.d(TAG, "notify " + l + " added " + Arrays.asList(seriesRecordings));
+ l.onSeriesRecordingAdded(seriesRecordings);
+ }
+ }
+
+ /**
+ * Calls {@link SeriesRecordingListener#onSeriesRecordingRemoved}
+ * for each listener.
+ */
+ protected final void notifySeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
+ for (SeriesRecordingListener l : mSeriesRecordingListeners) {
+ if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(seriesRecordings));
+ l.onSeriesRecordingRemoved(seriesRecordings);
+ }
+ }
+
+ /**
+ * Calls
+ * {@link SeriesRecordingListener#onSeriesRecordingChanged}
+ * for each listener.
+ */
+ protected final void notifySeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ for (SeriesRecordingListener l : mSeriesRecordingListeners) {
+ if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(seriesRecordings));
+ l.onSeriesRecordingChanged(seriesRecordings);
}
}
/**
- * Calls {@link ScheduledRecordingListener#onScheduledRecordingAdded(ScheduledRecording)}
+ * Calls {@link ScheduledRecordingListener#onScheduledRecordingAdded}
* for each listener.
*/
- protected final void notifyScheduledRecordingAdded(ScheduledRecording scheduledRecording) {
+ protected final void notifyScheduledRecordingAdded(ScheduledRecording... scheduledRecording) {
for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
- if (DEBUG) Log.d(TAG, "notify " + l + "added " + scheduledRecording);
+ if (DEBUG) Log.d(TAG, "notify " + l + " added " + Arrays.asList(scheduledRecording));
l.onScheduledRecordingAdded(scheduledRecording);
}
}
/**
- * Calls {@link ScheduledRecordingListener#onScheduledRecordingRemoved(ScheduledRecording)}
+ * Calls {@link ScheduledRecordingListener#onScheduledRecordingRemoved}
* for each listener.
*/
- protected final void notifyScheduledRecordingRemoved(ScheduledRecording scheduledRecording) {
+ protected final void notifyScheduledRecordingRemoved(ScheduledRecording... scheduledRecording) {
for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
- if (DEBUG) {
- Log.d(TAG, "notify " + l + "removed " + scheduledRecording);
- }
+ if (DEBUG) Log.d(TAG, "notify " + l + " removed " + Arrays.asList(scheduledRecording));
l.onScheduledRecordingRemoved(scheduledRecording);
}
}
/**
* Calls
- * {@link ScheduledRecordingListener#onScheduledRecordingStatusChanged(ScheduledRecording)}
+ * {@link ScheduledRecordingListener#onScheduledRecordingStatusChanged}
* for each listener.
*/
protected final void notifyScheduledRecordingStatusChanged(
- ScheduledRecording scheduledRecording) {
+ ScheduledRecording... scheduledRecording) {
for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
- if (DEBUG) Log.d(TAG, "notify " + l + "changed " + scheduledRecording);
+ if (DEBUG) Log.d(TAG, "notify " + l + " changed " + Arrays.asList(scheduledRecording));
l.onScheduledRecordingStatusChanged(scheduledRecording);
}
}
@@ -155,16 +253,70 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
@Override
+ public List<ScheduledRecording> getAvailableScheduledRecordings() {
+ return filterEndTimeIsPast(getRecordingsWithState(
+ ScheduledRecording.STATE_RECORDING_IN_PROGRESS,
+ ScheduledRecording.STATE_RECORDING_NOT_STARTED));
+ }
+
+ @Override
public List<ScheduledRecording> getStartedRecordings() {
- return filterEndTimeIsPast(
- getRecordingsWithState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS));
+ return filterEndTimeIsPast(getRecordingsWithState(
+ ScheduledRecording.STATE_RECORDING_IN_PROGRESS));
}
@Override
public List<ScheduledRecording> getNonStartedScheduledRecordings() {
- return filterEndTimeIsPast(
- getRecordingsWithState(ScheduledRecording.STATE_RECORDING_NOT_STARTED));
+ return filterEndTimeIsPast(getRecordingsWithState(
+ ScheduledRecording.STATE_RECORDING_NOT_STARTED));
+ }
+
+ @Override
+ public void changeState(ScheduledRecording scheduledRecording, @RecordingState int newState) {
+ if (scheduledRecording.getState() != newState) {
+ updateScheduledRecording(ScheduledRecording.buildFrom(scheduledRecording)
+ .setState(newState).build());
+ }
+ }
+
+ @Override
+ public Collection<ScheduledRecording> getDeletedSchedules() {
+ return mDeletedScheduleMap.values();
+ }
+
+ @NonNull
+ @Override
+ public Collection<Long> getDisallowedProgramIds() {
+ return mDeletedScheduleMap.keySet();
}
- protected abstract List<ScheduledRecording> getRecordingsWithState(int state);
+ /**
+ * Returns the map which contains the deleted schedules which are mapped from the program ID.
+ */
+ protected Map<Long, ScheduledRecording> getDeletedScheduleMap() {
+ return mDeletedScheduleMap;
+ }
+
+ /**
+ * Returns the schedules whose state is contained by states.
+ */
+ protected abstract List<ScheduledRecording> getRecordingsWithState(int... states);
+
+ @Override
+ public List<RecordedProgram> getRecordedPrograms(long seriesRecordingId) {
+ SeriesRecording seriesRecording = getSeriesRecording(seriesRecordingId);
+ if (seriesRecording == null) {
+ return Collections.emptyList();
+ }
+ List<RecordedProgram> result = new ArrayList<>();
+ for (RecordedProgram r : getRecordedPrograms()) {
+ if (seriesRecording.getSeriesId().equals(r.getSeriesId())) {
+ result.add(r);
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void forgetStorage(String inputId) { }
}
diff --git a/src/com/android/tv/dvr/ConflictChecker.java b/src/com/android/tv/dvr/ConflictChecker.java
new file mode 100644
index 00000000..201e379e
--- /dev/null
+++ b/src/com/android/tv/dvr/ConflictChecker.java
@@ -0,0 +1,277 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.ContentUris;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Message;
+import android.support.annotation.MainThread;
+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.TvApplication;
+import com.android.tv.common.WeakHandler;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Checking the runtime conflict of DVR recording.
+ * <p>
+ * This class runs only while the {@link MainActivity} is resumed and holds the upcoming conflicts.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+@MainThread
+public class ConflictChecker {
+ private static final String TAG = "ConflictChecker";
+ private static final boolean DEBUG = false;
+
+ private static final int MSG_CHECK_CONFLICT = 1;
+
+ private static final long CHECK_RETRY_PERIOD_MS = TimeUnit.SECONDS.toMillis(30);
+
+ /**
+ * To show watch conflict dialog, the start time of the earliest conflicting schedule should be
+ * less than or equal to this time.
+ */
+ private static final long MAX_WATCH_CONFLICT_CHECK_TIME_MS = TimeUnit.MINUTES.toMillis(5);
+ /**
+ * To show watch conflict dialog, the start time of the earliest conflicting schedule should be
+ * greater than or equal to this time.
+ */
+ private static final long MIN_WATCH_CONFLICT_CHECK_TIME_MS = TimeUnit.SECONDS.toMillis(30);
+
+ private final MainActivity mMainActivity;
+ private final ChannelDataManager mChannelDataManager;
+ private final DvrScheduleManager mScheduleManager;
+ private final InputSessionManager mSessionManager;
+ private final ConflictCheckerHandler mHandler = new ConflictCheckerHandler(this);
+
+ private final List<ScheduledRecording> mUpcomingConflicts = new ArrayList<>();
+ private final Set<OnUpcomingConflictChangeListener> mOnUpcomingConflictChangeListeners =
+ new ArraySet<>();
+ private final Map<Long, List<ScheduledRecording>> mCheckedConflictsMap = new HashMap<>();
+
+ private final ScheduledRecordingListener mScheduledRecordingListener =
+ new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... 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: " + scheduledRecordings);
+ mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingStatusChanged: " + scheduledRecordings);
+ mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
+ }
+ };
+
+ private final OnTvViewChannelChangeListener mOnTvViewChannelChangeListener =
+ new OnTvViewChannelChangeListener() {
+ @Override
+ public void onTvViewChannelChange(@Nullable Uri channelUri) {
+ mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
+ }
+ };
+
+ private boolean mStarted;
+
+ public ConflictChecker(MainActivity mainActivity) {
+ mMainActivity = mainActivity;
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(mainActivity);
+ mChannelDataManager = appSingletons.getChannelDataManager();
+ mScheduleManager = appSingletons.getDvrScheduleManager();
+ mSessionManager = appSingletons.getInputSessionManager();
+ }
+
+ /**
+ * Starts checking the conflict.
+ */
+ public void start() {
+ if (mStarted) {
+ return;
+ }
+ mStarted = true;
+ mHandler.sendEmptyMessage(MSG_CHECK_CONFLICT);
+ mScheduleManager.addScheduledRecordingListener(mScheduledRecordingListener);
+ mSessionManager.addOnTvViewChannelChangeListener(mOnTvViewChannelChangeListener);
+ }
+
+ /**
+ * Stops checking the conflict.
+ */
+ public void stop() {
+ if (!mStarted) {
+ return;
+ }
+ mStarted = false;
+ mSessionManager.removeOnTvViewChannelChangeListener(mOnTvViewChannelChangeListener);
+ mScheduleManager.removeScheduledRecordingListener(mScheduledRecordingListener);
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
+ /**
+ * Returns the upcoming conflicts.
+ */
+ public List<ScheduledRecording> getUpcomingConflicts() {
+ return new ArrayList<>(mUpcomingConflicts);
+ }
+
+ /**
+ * Adds a {@link OnUpcomingConflictChangeListener}.
+ */
+ public void addOnUpcomingConflictChangeListener(OnUpcomingConflictChangeListener listener) {
+ mOnUpcomingConflictChangeListeners.add(listener);
+ }
+
+ /**
+ * Removes the {@link OnUpcomingConflictChangeListener}.
+ */
+ public void removeOnUpcomingConflictChangeListener(OnUpcomingConflictChangeListener listener) {
+ mOnUpcomingConflictChangeListeners.remove(listener);
+ }
+
+ private void notifyUpcomingConflictChanged() {
+ for (OnUpcomingConflictChangeListener l : mOnUpcomingConflictChangeListeners) {
+ l.onUpcomingConflictChange();
+ }
+ }
+
+ /**
+ * Remembers the user's decision to record while watching the channel.
+ */
+ public void setCheckedConflictsForChannel(long mChannelId, List<ScheduledRecording> conflicts) {
+ mCheckedConflictsMap.put(mChannelId, new ArrayList<>(conflicts));
+ }
+
+ void onCheckConflict() {
+ // Checks the conflicting schedules and setup the next re-check time.
+ // If there are upcoming conflicts soon, it opens the conflict dialog.
+ if (DEBUG) Log.d(TAG, "Handling MSG_CHECK_CONFLICT");
+ mHandler.removeMessages(MSG_CHECK_CONFLICT);
+ mUpcomingConflicts.clear();
+ if (!mScheduleManager.isInitialized()
+ || !mChannelDataManager.isDbLoadFinished()) {
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_CONFLICT, CHECK_RETRY_PERIOD_MS);
+ notifyUpcomingConflictChanged();
+ return;
+ }
+ if (mSessionManager.getCurrentTvViewChannelUri() == null) {
+ // As MainActivity is not using a tuner, no need to check the conflict.
+ notifyUpcomingConflictChanged();
+ return;
+ }
+ Uri channelUri = mSessionManager.getCurrentTvViewChannelUri();
+ if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
+ notifyUpcomingConflictChanged();
+ return;
+ }
+ long channelId = ContentUris.parseId(channelUri);
+ Channel channel = mChannelDataManager.getChannel(channelId);
+ // The conflicts caused by watching the channel.
+ List<ScheduledRecording> conflicts = mScheduleManager
+ .getConflictingSchedulesForWatching(channel.getId());
+ long earliestToCheck = Long.MAX_VALUE;
+ long currentTimeMs = System.currentTimeMillis();
+ for (ScheduledRecording schedule : conflicts) {
+ long startTimeMs = schedule.getStartTimeMs();
+ if (startTimeMs < currentTimeMs + MIN_WATCH_CONFLICT_CHECK_TIME_MS) {
+ // The start time of the upcoming conflict remains less than the minimum
+ // check time.
+ continue;
+ }
+ if (startTimeMs > currentTimeMs + MAX_WATCH_CONFLICT_CHECK_TIME_MS) {
+ // The start time of the upcoming conflict remains greater than the
+ // maximum check time. Setup the next re-check time.
+ long nextCheckTimeMs = startTimeMs - MAX_WATCH_CONFLICT_CHECK_TIME_MS;
+ if (earliestToCheck > nextCheckTimeMs) {
+ earliestToCheck = nextCheckTimeMs;
+ }
+ } else {
+ // Found upcoming conflicts which will start soon.
+ mUpcomingConflicts.add(schedule);
+ // The schedule will be removed from the "upcoming conflict" when the
+ // recording is almost started.
+ long nextCheckTimeMs = startTimeMs - MIN_WATCH_CONFLICT_CHECK_TIME_MS;
+ if (earliestToCheck > nextCheckTimeMs) {
+ earliestToCheck = nextCheckTimeMs;
+ }
+ }
+ }
+ if (earliestToCheck != Long.MAX_VALUE) {
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_CONFLICT,
+ earliestToCheck - currentTimeMs);
+ }
+ if (DEBUG) Log.d(TAG, "upcoming conflicts: " + mUpcomingConflicts);
+ notifyUpcomingConflictChanged();
+ if (!mUpcomingConflicts.isEmpty()
+ && !DvrUiHelper.isChannelWatchConflictDialogShown(mMainActivity)) {
+ // Don't show the conflict dialog if the user already knows.
+ List<ScheduledRecording> checkedConflicts = mCheckedConflictsMap.get(
+ channel.getId());
+ if (checkedConflicts == null
+ || !checkedConflicts.containsAll(mUpcomingConflicts)) {
+ DvrUiHelper.showChannelWatchConflictDialog(mMainActivity, channel);
+ }
+ }
+ }
+
+ private static class ConflictCheckerHandler extends WeakHandler<ConflictChecker> {
+ ConflictCheckerHandler(ConflictChecker conflictChecker) {
+ super(conflictChecker);
+ }
+
+ @Override
+ protected void handleMessage(Message msg, @NonNull ConflictChecker conflictChecker) {
+ switch (msg.what) {
+ case MSG_CHECK_CONFLICT:
+ conflictChecker.onCheckConflict();
+ break;
+ }
+ }
+ }
+
+ /**
+ * A listener for the change of upcoming conflicts.
+ */
+ public interface OnUpcomingConflictChangeListener {
+ void onUpcomingConflictChange();
+ }
+}
diff --git a/src/com/android/tv/dvr/DvrDataManager.java b/src/com/android/tv/dvr/DvrDataManager.java
index c96104e5..06613667 100644
--- a/src/com/android/tv/dvr/DvrDataManager.java
+++ b/src/com/android/tv/dvr/DvrDataManager.java
@@ -17,11 +17,13 @@
package com.android.tv.dvr;
import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Range;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.dvr.ScheduledRecording.RecordingState;
+import java.util.Collection;
import java.util.List;
/**
@@ -34,16 +36,39 @@ public interface DvrDataManager {
boolean isInitialized();
/**
+ * Returns {@code true} if the schedules were loaded, otherwise {@code false}.
+ */
+ boolean isDvrScheduleLoadFinished();
+
+ /**
+ * Returns {@code true} if the recorded programs were loaded, otherwise {@code false}.
+ */
+ boolean isRecordedProgramLoadFinished();
+
+ /**
* Returns past recordings.
*/
List<RecordedProgram> getRecordedPrograms();
/**
+ * Returns past recorded programs in the given series.
+ */
+ List<RecordedProgram> getRecordedPrograms(long seriesRecordingId);
+
+ /**
* Returns all {@link ScheduledRecording} regardless of state.
+ * <p>
+ * The result doesn't contain the deleted schedules.
*/
List<ScheduledRecording> getAllScheduledRecordings();
/**
+ * Returns all available {@link ScheduledRecording}, it contains started and non started
+ * recordings.
+ */
+ List<ScheduledRecording> getAvailableScheduledRecordings();
+
+ /**
* Returns started recordings that expired.
*/
List<ScheduledRecording> getStartedRecordings();
@@ -54,9 +79,14 @@ public interface DvrDataManager {
List<ScheduledRecording> getNonStartedScheduledRecordings();
/**
- * Returns season recordings.
+ * Returns series recordings.
+ */
+ List<SeriesRecording> getSeriesRecordings();
+
+ /**
+ * Returns series recordings from the given input.
*/
- List<SeasonRecording> getSeasonRecordings();
+ List<SeriesRecording> getSeriesRecordings(String inputId);
/**
* Returns the next start time after {@code time} or {@link #NEXT_START_TIME_NOT_FOUND}
@@ -67,15 +97,47 @@ public interface DvrDataManager {
long getNextScheduledStartTimeAfter(long time);
/**
- * Returns a list of all Recordings with a overlap with the given time period inclusive.
+ * Returns a list of the schedules with a overlap with the given time period inclusive and with
+ * the given state.
*
* <p> A recording overlaps with a period when
* {@code recording.getStartTime() <= period.getUpper() &&
* recording.getEndTime() >= period.getLower()}.
*
* @param period a time period in milliseconds.
+ * @param state the state of the schedule.
*/
- List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period);
+ List<ScheduledRecording> getScheduledRecordings(Range<Long> period, @RecordingState int state);
+
+ /**
+ * Returns a list of the schedules in the given series.
+ */
+ List<ScheduledRecording> getScheduledRecordings(long seriesRecordingId);
+
+ /**
+ * Returns a list of the schedules from the given input.
+ */
+ List<ScheduledRecording> getScheduledRecordings(String inputId);
+
+ /**
+ * Add a {@link OnDvrScheduleLoadFinishedListener}.
+ */
+ void addDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener);
+
+ /**
+ * Remove a {@link OnDvrScheduleLoadFinishedListener}.
+ */
+ void removeDvrScheduleLoadFinishedListener(OnDvrScheduleLoadFinishedListener listener);
+
+ /**
+ * Add a {@link OnRecordedProgramLoadFinishedListener}.
+ */
+ void addRecordedProgramLoadFinishedListener(OnRecordedProgramLoadFinishedListener listener);
+
+ /**
+ * Remove a {@link OnRecordedProgramLoadFinishedListener}.
+ */
+ void removeRecordedProgramLoadFinishedListener(OnRecordedProgramLoadFinishedListener listener);
/**
* Add a {@link ScheduledRecordingListener}.
@@ -98,12 +160,21 @@ public interface DvrDataManager {
void removeRecordedProgramListener(RecordedProgramListener listener);
/**
+ * Add a {@link ScheduledRecordingListener}.
+ */
+ void addSeriesRecordingListener(SeriesRecordingListener seriesRecordingListener);
+
+ /**
+ * Remove a {@link ScheduledRecordingListener}.
+ */
+ void removeSeriesRecordingListener(SeriesRecordingListener seriesRecordingListener);
+
+ /**
* Returns the scheduled recording program with the given recordingId or null if is not found.
*/
@Nullable
ScheduledRecording getScheduledRecording(long recordingId);
-
/**
* Returns the scheduled recording program with the given programId or null if is not found.
*/
@@ -116,19 +187,78 @@ public interface DvrDataManager {
@Nullable
RecordedProgram getRecordedProgram(long recordingId);
+ /**
+ * Returns the series recording with the given seriesId or null if is not found.
+ */
+ @Nullable
+ SeriesRecording getSeriesRecording(long seriesRecordingId);
+
+ /**
+ * Returns the series recording with the given series ID or {@code null} if not found.
+ */
+ @Nullable
+ SeriesRecording getSeriesRecording(String seriesId);
+
+ /**
+ * Returns the schedules which are marked deleted.
+ */
+ Collection<ScheduledRecording> getDeletedSchedules();
+
+ /**
+ * Returns the program IDs which is not allowed to make a schedule automatically.
+ */
+ @NonNull
+ Collection<Long> getDisallowedProgramIds();
+
+ /**
+ * Listens for the DVR schedules loading finished.
+ */
+ interface OnDvrScheduleLoadFinishedListener {
+ void onDvrScheduleLoadFinished();
+ }
+
+ /**
+ * Listens for the recorded program loading finished.
+ */
+ interface OnRecordedProgramLoadFinishedListener {
+ void onRecordedProgramLoadFinished();
+ }
+
+ /**
+ * Listens for changes to {@link ScheduledRecording}s.
+ */
interface ScheduledRecordingListener {
- void onScheduledRecordingAdded(ScheduledRecording scheduledRecording);
+ void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings);
- void onScheduledRecordingRemoved(ScheduledRecording scheduledRecording);
+ void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings);
- void onScheduledRecordingStatusChanged(ScheduledRecording scheduledRecording);
+ /**
+ * Called when the schedules are updated.
+ *
+ * <p>Note that the passed arguments are the new objects with the same ID as the old ones.
+ */
+ void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings);
}
+ /**
+ * Listens for changes to {@link SeriesRecording}s.
+ */
+ interface SeriesRecordingListener {
+ void onSeriesRecordingAdded(SeriesRecording... seriesRecordings);
+
+ void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings);
+
+ void onSeriesRecordingChanged(SeriesRecording... seriesRecordings);
+ }
+
+ /**
+ * Listens for changes to {@link RecordedProgram}s.
+ */
interface RecordedProgramListener {
- void onRecordedProgramAdded(RecordedProgram recordedProgram);
+ void onRecordedProgramsAdded(RecordedProgram... recordedPrograms);
- void onRecordedProgramChanged(RecordedProgram recordedProgram);
+ void onRecordedProgramsChanged(RecordedProgram... recordedPrograms);
- void onRecordedProgramRemoved(RecordedProgram recordedProgram);
+ void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms);
}
}
diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java
index 02c47750..46682a48 100644
--- a/src/com/android/tv/dvr/DvrDataManagerImpl.java
+++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java
@@ -16,13 +16,16 @@
package com.android.tv.dvr;
+import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.ContentObserver;
-import android.database.Cursor;
-import android.media.tv.TvContract;
+import android.database.sqlite.SQLiteException;
+import android.media.tv.TvContract.RecordedPrograms;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager.TvInputCallback;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
@@ -31,23 +34,38 @@ import android.os.Looper;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Range;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.dvr.DvrStorageStatusManager.OnStorageMountChangedListener;
import com.android.tv.dvr.ScheduledRecording.RecordingState;
-import com.android.tv.dvr.provider.AsyncDvrDbTask;
-import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQueryTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncAddScheduleTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncAddSeriesRecordingTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDeleteScheduleTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDeleteSeriesRecordingTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQueryScheduleTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncDvrQuerySeriesRecordingTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncUpdateScheduleTask;
+import com.android.tv.dvr.provider.AsyncDvrDbTask.AsyncUpdateSeriesRecordingTask;
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.TvProviderUriMatcher;
+import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map.Entry;
import java.util.Set;
/**
@@ -59,90 +77,221 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
private static final String TAG = "DvrDataManagerImpl";
private static final boolean DEBUG = false;
+ private final TvInputManagerHelper mInputManager;
+
private final HashMap<Long, ScheduledRecording> mScheduledRecordings = new HashMap<>();
+ private final HashMap<Long, RecordedProgram> mRecordedPrograms = new HashMap<>();
+ private final HashMap<Long, SeriesRecording> mSeriesRecordings = new HashMap<>();
private final HashMap<Long, ScheduledRecording> mProgramId2ScheduledRecordings =
new HashMap<>();
- private final HashMap<Long, RecordedProgram> mRecordedPrograms = new HashMap<>();
+ private final HashMap<String, SeriesRecording> mSeriesId2SeriesRecordings = new HashMap<>();
- private final Context mContext;
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
- private final ContentObserver mContentObserver = new ContentObserver(mMainThreadHandler) {
+ private final HashMap<Long, ScheduledRecording> mScheduledRecordingsForRemovedInput =
+ new HashMap<>();
+ private final HashMap<Long, RecordedProgram> mRecordedProgramsForRemovedInput = new HashMap<>();
+ private final HashMap<Long, SeriesRecording> mSeriesRecordingsForRemovedInput = new HashMap<>();
+ private final Context mContext;
+ private final ContentObserver mContentObserver = new ContentObserver(new Handler(
+ Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
@Override
- public void onChange(boolean selfChange, @Nullable final Uri uri) {
- if (uri == null) {
- // TODO reload everything.
- }
- AsyncRecordedProgramQueryTask task = new AsyncRecordedProgramQueryTask(
+ public void onChange(boolean selfChange, final @Nullable Uri uri) {
+ RecordedProgramsQueryTask task = new RecordedProgramsQueryTask(
mContext.getContentResolver(), uri);
task.executeOnDbThread();
mPendingTasks.add(task);
}
};
- private void onObservedChange(Uri uri, RecordedProgram recordedProgram) {
- long id = ContentUris.parseId(uri);
- if (DEBUG) {
- Log.d(TAG, "changed recorded program #" + id + " to " + recordedProgram);
- }
- if (recordedProgram == null) {
- RecordedProgram old = mRecordedPrograms.remove(id);
- if (old != null) {
- notifyRecordedProgramRemoved(old);
- } else {
- Log.w(TAG, "Could not find old version of deleted program #" + id);
+ private boolean mDvrLoadFinished;
+ private boolean mRecordedProgramLoadFinished;
+ private final Set<AsyncTask> mPendingTasks = new ArraySet<>();
+ private DvrDbSync mDbSync;
+ private DvrStorageStatusManager mStorageStatusManager;
+
+ private final TvInputCallback mInputCallback = new TvInputCallback() {
+ @Override
+ public void onInputAdded(String inputId) {
+ if (DEBUG) Log.d(TAG, "onInputAdded " + inputId);
+ if (!isInputAvailable(inputId)) {
+ if (DEBUG) Log.d(TAG, "Not available for recording");
+ return;
}
- } else {
- RecordedProgram old = mRecordedPrograms.put(id, recordedProgram);
- if (old == null) {
- notifyRecordedProgramAdded(recordedProgram);
- } else {
- notifyRecordedProgramChanged(recordedProgram);
+ unhideInput(inputId);
+ }
+
+ @Override
+ public void onInputRemoved(String inputId) {
+ if (DEBUG) Log.d(TAG, "onInputRemoved " + inputId);
+ hideInput(inputId);
+ }
+ };
+
+ private final OnStorageMountChangedListener mStorageMountChangedListener =
+ new OnStorageMountChangedListener() {
+ @Override
+ public void onStorageMountChanged(boolean storageMounted) {
+ for (TvInputInfo input : mInputManager.getTvInputInfos(true, true)) {
+ if (Utils.isBundledInput(input.getId())) {
+ if (storageMounted) {
+ unhideInput(input.getId());
+ } else {
+ hideInput(input.getId());
+ }
+ }
+ }
+ }
+ };
+
+ private static <T> List<T> moveElements(HashMap<Long, T> from, HashMap<Long, T> to,
+ Filter<T> filter) {
+ List<T> moved = new ArrayList<>();
+ Iterator<Entry<Long, T>> iter = from.entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry<Long, T> entry = iter.next();
+ if (filter.filter(entry.getValue())) {
+ to.put(entry.getKey(), entry.getValue());
+ iter.remove();
+ moved.add(entry.getValue());
}
}
+ return moved;
}
- private boolean mDvrLoadFinished;
- private boolean mRecordedProgramLoadFinished;
- private final Set<AsyncTask> mPendingTasks = new ArraySet<>();
-
public DvrDataManagerImpl(Context context, Clock clock) {
super(context, clock);
mContext = context;
+ mInputManager = TvApplication.getSingletons(context).getTvInputManagerHelper();
+ mStorageStatusManager = TvApplication.getSingletons(context).getDvrStorageStatusManager();
}
public void start() {
- AsyncDvrQueryTask mDvrQueryTask = new AsyncDvrQueryTask(mContext) {
+ mInputManager.addCallback(mInputCallback);
+ mStorageStatusManager.addListener(mStorageMountChangedListener);
+ AsyncDvrQuerySeriesRecordingTask dvrQuerySeriesRecordingTask
+ = new AsyncDvrQuerySeriesRecordingTask(mContext) {
+ @Override
+ protected void onCancelled(List<SeriesRecording> seriesRecordings) {
+ mPendingTasks.remove(this);
+ }
@Override
+ protected void onPostExecute(List<SeriesRecording> seriesRecordings) {
+ mPendingTasks.remove(this);
+ long maxId = 0;
+ HashSet<String> seriesIds = new HashSet<>();
+ for (SeriesRecording r : seriesRecordings) {
+ if (SoftPreconditions.checkState(!seriesIds.contains(r.getSeriesId()), TAG,
+ "Skip loading series recording with duplicate series ID: " + r)) {
+ seriesIds.add(r.getSeriesId());
+ if (isInputAvailable(r.getInputId())) {
+ mSeriesRecordings.put(r.getId(), r);
+ mSeriesId2SeriesRecordings.put(r.getSeriesId(), r);
+ } else {
+ mSeriesRecordingsForRemovedInput.put(r.getId(), r);
+ }
+ }
+ if (maxId < r.getId()) {
+ maxId = r.getId();
+ }
+ }
+ IdGenerator.SERIES_RECORDING.setMaxId(maxId);
+ }
+ };
+ dvrQuerySeriesRecordingTask.executeOnDbThread();
+ mPendingTasks.add(dvrQuerySeriesRecordingTask);
+ AsyncDvrQueryScheduleTask dvrQueryScheduleTask
+ = new AsyncDvrQueryScheduleTask(mContext) {
+ @Override
protected void onCancelled(List<ScheduledRecording> scheduledRecordings) {
mPendingTasks.remove(this);
}
+ @SuppressLint("SwitchIntDef")
@Override
protected void onPostExecute(List<ScheduledRecording> result) {
mPendingTasks.remove(this);
- mDvrLoadFinished = true;
+ long maxId = 0;
+ List<SeriesRecording> seriesRecordingsToAdd = new ArrayList<>();
+ List<ScheduledRecording> toUpdate = new ArrayList<>();
+ List<ScheduledRecording> toDelete = new ArrayList<>();
for (ScheduledRecording r : result) {
- mScheduledRecordings.put(r.getId(), r);
+ if (!isInputAvailable(r.getInputId())) {
+ mScheduledRecordingsForRemovedInput.put(r.getId(), r);
+ } else if (r.getState() == ScheduledRecording.STATE_RECORDING_DELETED) {
+ getDeletedScheduleMap().put(r.getProgramId(), r);
+ } else {
+ mScheduledRecordings.put(r.getId(), r);
+ if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) {
+ mProgramId2ScheduledRecordings.put(r.getProgramId(), r);
+ }
+ // Adjust the state of the schedules before DB loading is finished.
+ switch (r.getState()) {
+ case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
+ if (r.getEndTimeMs() <= mClock.currentTimeMillis()) {
+ toUpdate.add(ScheduledRecording.buildFrom(r)
+ .setState(ScheduledRecording.STATE_RECORDING_FAILED)
+ .build());
+ } else {
+ toUpdate.add(ScheduledRecording.buildFrom(r)
+ .setState(
+ ScheduledRecording.STATE_RECORDING_NOT_STARTED)
+ .build());
+ }
+ break;
+ case ScheduledRecording.STATE_RECORDING_NOT_STARTED:
+ if (r.getEndTimeMs() <= mClock.currentTimeMillis()) {
+ toUpdate.add(ScheduledRecording.buildFrom(r)
+ .setState(ScheduledRecording.STATE_RECORDING_FAILED)
+ .build());
+ }
+ break;
+ case ScheduledRecording.STATE_RECORDING_CANCELED:
+ toDelete.add(r);
+ break;
+ }
+ }
+ if (maxId < r.getId()) {
+ maxId = r.getId();
+ }
+ }
+ if (!toUpdate.isEmpty()) {
+ updateScheduledRecording(ScheduledRecording.toArray(toUpdate));
+ }
+ if (!toDelete.isEmpty()) {
+ removeScheduledRecording(ScheduledRecording.toArray(toDelete));
+ }
+ IdGenerator.SCHEDULED_RECORDING.setMaxId(maxId);
+ mDvrLoadFinished = true;
+ notifyDvrScheduleLoadFinished();
+ mDbSync = new DvrDbSync(mContext, DvrDataManagerImpl.this);
+ mDbSync.start();
+ if (isInitialized()) {
+ SeriesRecordingScheduler.getInstance(mContext).start();
}
}
};
- mDvrQueryTask.executeOnDbThread();
- mPendingTasks.add(mDvrQueryTask);
- AsyncRecordedProgramsQueryTask mRecordedProgramQueryTask =
- new AsyncRecordedProgramsQueryTask(mContext.getContentResolver());
+ dvrQueryScheduleTask.executeOnDbThread();
+ mPendingTasks.add(dvrQueryScheduleTask);
+ RecordedProgramsQueryTask mRecordedProgramQueryTask =
+ new RecordedProgramsQueryTask(mContext.getContentResolver(), null);
mRecordedProgramQueryTask.executeOnDbThread();
ContentResolver cr = mContext.getContentResolver();
- cr.registerContentObserver(TvContract.RecordedPrograms.CONTENT_URI, true, mContentObserver);
+ cr.registerContentObserver(RecordedPrograms.CONTENT_URI, true, mContentObserver);
}
public void stop() {
+ mInputManager.removeCallback(mInputCallback);
+ mStorageStatusManager.removeListener(mStorageMountChangedListener);
+ SeriesRecordingScheduler.getInstance(mContext).stop();
+ if (mDbSync != null) {
+ mDbSync.stop();
+ }
ContentResolver cr = mContext.getContentResolver();
cr.unregisterContentObserver(mContentObserver);
Iterator<AsyncTask> i = mPendingTasks.iterator();
@@ -153,11 +302,104 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
}
}
+ private void onRecordedProgramsLoadedFinished(Uri uri, List<RecordedProgram> recordedPrograms) {
+ if (uri == null) {
+ uri = RecordedPrograms.CONTENT_URI;
+ }
+ int match = TvProviderUriMatcher.match(uri);
+ if (match == TvProviderUriMatcher.MATCH_RECORDED_PROGRAM) {
+ if (!mRecordedProgramLoadFinished) {
+ for (RecordedProgram recorded : recordedPrograms) {
+ if (isInputAvailable(recorded.getInputId())) {
+ mRecordedPrograms.put(recorded.getId(), recorded);
+ } else {
+ mRecordedProgramsForRemovedInput.put(recorded.getId(), recorded);
+ }
+ }
+ mRecordedProgramLoadFinished = true;
+ notifyRecordedProgramLoadFinished();
+ } else if (recordedPrograms == null || recordedPrograms.isEmpty()) {
+ List<RecordedProgram> oldRecordedPrograms =
+ new ArrayList<>(mRecordedPrograms.values());
+ mRecordedPrograms.clear();
+ mRecordedProgramsForRemovedInput.clear();
+ notifyRecordedProgramsRemoved(RecordedProgram.toArray(oldRecordedPrograms));
+ } else {
+ HashMap<Long, RecordedProgram> oldRecordedPrograms
+ = new HashMap<>(mRecordedPrograms);
+ mRecordedPrograms.clear();
+ mRecordedProgramsForRemovedInput.clear();
+ List<RecordedProgram> addedRecordedPrograms = new ArrayList<>();
+ List<RecordedProgram> changedRecordedPrograms = new ArrayList<>();
+ for (RecordedProgram recorded : recordedPrograms) {
+ if (isInputAvailable(recorded.getInputId())) {
+ mRecordedPrograms.put(recorded.getId(), recorded);
+ if (oldRecordedPrograms.remove(recorded.getId()) == null) {
+ addedRecordedPrograms.add(recorded);
+ } else {
+ changedRecordedPrograms.add(recorded);
+ }
+ } else {
+ mRecordedProgramsForRemovedInput.put(recorded.getId(), recorded);
+ }
+ }
+ if (!addedRecordedPrograms.isEmpty()) {
+ notifyRecordedProgramsAdded(RecordedProgram.toArray(addedRecordedPrograms));
+ }
+ if (!changedRecordedPrograms.isEmpty()) {
+ notifyRecordedProgramsChanged(RecordedProgram.toArray(changedRecordedPrograms));
+ }
+ if (!oldRecordedPrograms.isEmpty()) {
+ notifyRecordedProgramsRemoved(
+ RecordedProgram.toArray(oldRecordedPrograms.values()));
+ }
+ }
+ if (isInitialized()) {
+ SeriesRecordingScheduler.getInstance(mContext).start();
+ }
+ } else if (match == TvProviderUriMatcher.MATCH_RECORDED_PROGRAM_ID) {
+ if (!mRecordedProgramLoadFinished) {
+ return;
+ }
+ long id = ContentUris.parseId(uri);
+ if (DEBUG) Log.d(TAG, "changed recorded program #" + id + " to " + recordedPrograms);
+ if (recordedPrograms == null || recordedPrograms.isEmpty()) {
+ mRecordedProgramsForRemovedInput.remove(id);
+ RecordedProgram old = mRecordedPrograms.remove(id);
+ if (old != null) {
+ notifyRecordedProgramsRemoved(old);
+ }
+ } else {
+ RecordedProgram recordedProgram = recordedPrograms.get(0);
+ if (isInputAvailable(recordedProgram.getInputId())) {
+ RecordedProgram old = mRecordedPrograms.put(id, recordedProgram);
+ if (old == null) {
+ notifyRecordedProgramsAdded(recordedProgram);
+ } else {
+ notifyRecordedProgramsChanged(recordedProgram);
+ }
+ } else {
+ mRecordedProgramsForRemovedInput.put(id, recordedProgram);
+ }
+ }
+ }
+ }
+
@Override
public boolean isInitialized() {
return mDvrLoadFinished && mRecordedProgramLoadFinished;
}
+ @Override
+ public boolean isDvrScheduleLoadFinished() {
+ return mDvrLoadFinished;
+ }
+
+ @Override
+ public boolean isRecordedProgramLoadFinished() {
+ return mRecordedProgramLoadFinished;
+ }
+
private List<ScheduledRecording> getScheduledRecordingsPrograms() {
if (!mDvrLoadFinished) {
return Collections.emptyList();
@@ -177,24 +419,50 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
}
@Override
+ public List<RecordedProgram> getRecordedPrograms(long seriesRecordingId) {
+ SeriesRecording seriesRecording = getSeriesRecording(seriesRecordingId);
+ if (!mRecordedProgramLoadFinished || seriesRecording == null) {
+ return Collections.emptyList();
+ }
+ return super.getRecordedPrograms(seriesRecordingId);
+ }
+
+ @Override
public List<ScheduledRecording> getAllScheduledRecordings() {
return new ArrayList<>(mScheduledRecordings.values());
}
- protected List<ScheduledRecording> getRecordingsWithState(@RecordingState int state) {
+ @Override
+ protected List<ScheduledRecording> getRecordingsWithState(@RecordingState int... states) {
List<ScheduledRecording> result = new ArrayList<>();
for (ScheduledRecording r : mScheduledRecordings.values()) {
- if (r.getState() == state) {
- result.add(r);
+ for (int state : states) {
+ if (r.getState() == state) {
+ result.add(r);
+ break;
+ }
}
}
return result;
}
@Override
- public List<SeasonRecording> getSeasonRecordings() {
- // If we return dummy data here, we can implement UI part independently.
- return Collections.emptyList();
+ public List<SeriesRecording> getSeriesRecordings() {
+ if (!mDvrLoadFinished) {
+ return Collections.emptyList();
+ }
+ 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
@@ -219,10 +487,33 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
}
@Override
- public List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period) {
+ public List<ScheduledRecording> getScheduledRecordings(Range<Long> period,
+ @RecordingState int state) {
+ List<ScheduledRecording> result = new ArrayList<>();
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ 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.isOverLapping(period)) {
+ 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);
}
}
@@ -232,19 +523,13 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
@Nullable
@Override
public ScheduledRecording getScheduledRecording(long recordingId) {
- if (mDvrLoadFinished) {
- return mScheduledRecordings.get(recordingId);
- }
- return null;
+ return mScheduledRecordings.get(recordingId);
}
@Nullable
@Override
public ScheduledRecording getScheduledRecordingForProgramId(long programId) {
- if (mDvrLoadFinished) {
- return mProgramId2ScheduledRecordings.get(programId);
- }
- return null;
+ return mProgramId2ScheduledRecordings.get(programId);
}
@Nullable
@@ -253,151 +538,386 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
return mRecordedPrograms.get(recordingId);
}
+ @Nullable
@Override
- public void addScheduledRecording(final ScheduledRecording scheduledRecording) {
- new AsyncDvrDbTask.AsyncAddRecordingTask(mContext) {
- @Override
- protected void onPostExecute(List<ScheduledRecording> scheduledRecordings) {
- super.onPostExecute(scheduledRecordings);
- SoftPreconditions.checkArgument(scheduledRecordings.size() == 1);
- for (ScheduledRecording r : scheduledRecordings) {
- if (r.getId() != -1) {
- mScheduledRecordings.put(r.getId(), r);
- if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) {
- mProgramId2ScheduledRecordings.put(r.getProgramId(), r);
- }
- notifyScheduledRecordingAdded(r);
- } else {
- Log.w(TAG, "Error adding " + r);
- }
- }
+ public SeriesRecording getSeriesRecording(long seriesRecordingId) {
+ return mSeriesRecordings.get(seriesRecordingId);
+ }
+ @Nullable
+ @Override
+ public SeriesRecording getSeriesRecording(String seriesId) {
+ return mSeriesId2SeriesRecordings.get(seriesId);
+ }
+
+ @Override
+ public void addScheduledRecording(ScheduledRecording... schedules) {
+ for (ScheduledRecording r : schedules) {
+ if (r.getId() == ScheduledRecording.ID_NOT_SET) {
+ r.setId(IdGenerator.SCHEDULED_RECORDING.newId());
}
- }.executeOnDbThread(scheduledRecording);
+ mScheduledRecordings.put(r.getId(), r);
+ if (r.getProgramId() != ScheduledRecording.ID_NOT_SET) {
+ mProgramId2ScheduledRecordings.put(r.getProgramId(), r);
+ }
+ }
+ if (mDvrLoadFinished) {
+ notifyScheduledRecordingAdded(schedules);
+ }
+ new AsyncAddScheduleTask(mContext).executeOnDbThread(schedules);
+ removeDeletedSchedules(schedules);
}
@Override
- public void addSeasonRecording(SeasonRecording seasonRecording) { }
+ public void addSeriesRecording(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ r.setId(IdGenerator.SERIES_RECORDING.newId());
+ mSeriesRecordings.put(r.getId(), r);
+ SeriesRecording previousSeries = mSeriesId2SeriesRecordings.put(r.getSeriesId(), r);
+ SoftPreconditions.checkArgument(previousSeries == null, TAG, "Attempt to add series"
+ + " recording with the duplicate series ID: " + r.getSeriesId());
+ }
+ if (mDvrLoadFinished) {
+ notifySeriesRecordingAdded(seriesRecordings);
+ }
+ new AsyncAddSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings);
+ }
@Override
- public void removeScheduledRecording(final ScheduledRecording scheduledRecording) {
- new AsyncDvrDbTask.AsyncDeleteRecordingTask(mContext) {
- @Override
- protected void onPostExecute(List<Integer> counts) {
- super.onPostExecute(counts);
- SoftPreconditions.checkArgument(counts.size() == 1);
- for (Integer c : counts) {
- if (c == 1) {
- mScheduledRecordings.remove(scheduledRecording.getId());
- if (scheduledRecording.getProgramId() != ScheduledRecording.ID_NOT_SET) {
- mProgramId2ScheduledRecordings
- .remove(scheduledRecording.getProgramId());
- }
- //TODO change to notifyRecordingUpdated
- notifyScheduledRecordingRemoved(scheduledRecording);
- } else {
- Log.w(TAG, "Error removing " + scheduledRecording);
- }
- }
+ public void removeScheduledRecording(ScheduledRecording... schedules) {
+ removeScheduledRecording(false, schedules);
+ }
+ @Override
+ public void removeScheduledRecording(boolean forceRemove, ScheduledRecording... schedules) {
+ List<ScheduledRecording> schedulesToDelete = new ArrayList<>();
+ List<ScheduledRecording> schedulesNotToDelete = new ArrayList<>();
+ for (ScheduledRecording r : schedules) {
+ mScheduledRecordings.remove(r.getId());
+ getDeletedScheduleMap().remove(r.getId());
+ mProgramId2ScheduledRecordings.remove(r.getProgramId());
+ boolean isScheduleForRemovedInput =
+ mScheduledRecordingsForRemovedInput.remove(r.getProgramId()) != null;
+ // If it belongs to the series recording and it's not started yet, just mark delete
+ // instead of deleting it.
+ if (!isScheduleForRemovedInput && !forceRemove
+ && r.getSeriesRecordingId() != SeriesRecording.ID_NOT_SET
+ && (r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
+ || r.getState() == ScheduledRecording.STATE_RECORDING_CANCELED)) {
+ SoftPreconditions.checkState(r.getProgramId() != ScheduledRecording.ID_NOT_SET);
+ ScheduledRecording deleted = ScheduledRecording.buildFrom(r)
+ .setState(ScheduledRecording.STATE_RECORDING_DELETED).build();
+ getDeletedScheduleMap().put(deleted.getProgramId(), deleted);
+ schedulesNotToDelete.add(deleted);
+ } else {
+ schedulesToDelete.add(r);
}
- }.executeOnDbThread(scheduledRecording);
+ }
+ if (mDvrLoadFinished) {
+ notifyScheduledRecordingRemoved(schedules);
+ }
+ if (!schedulesToDelete.isEmpty()) {
+ new AsyncDeleteScheduleTask(mContext).executeOnDbThread(
+ ScheduledRecording.toArray(schedulesToDelete));
+ }
+ if (!schedulesNotToDelete.isEmpty()) {
+ new AsyncUpdateScheduleTask(mContext).executeOnDbThread(
+ ScheduledRecording.toArray(schedulesNotToDelete));
+ }
}
@Override
- public void removeSeasonSchedule(SeasonRecording seasonSchedule) { }
+ public void removeSeriesRecording(final SeriesRecording... seriesRecordings) {
+ HashSet<Long> ids = new HashSet<>();
+ for (SeriesRecording r : seriesRecordings) {
+ mSeriesRecordings.remove(r.getId());
+ mSeriesId2SeriesRecordings.remove(r.getSeriesId());
+ ids.add(r.getId());
+ }
+ // Reset series recording ID of the scheduled recording.
+ List<ScheduledRecording> toUpdate = new ArrayList<>();
+ List<ScheduledRecording> toDelete = new ArrayList<>();
+ for (ScheduledRecording r : mScheduledRecordings.values()) {
+ if (ids.contains(r.getSeriesRecordingId())) {
+ if (r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ toDelete.add(r);
+ } else {
+ toUpdate.add(ScheduledRecording.buildFrom(r)
+ .setSeriesRecordingId(SeriesRecording.ID_NOT_SET).build());
+ }
+ }
+ }
+ if (!toUpdate.isEmpty()) {
+ // No need to update DB. It's handled in database automatically when the series
+ // recording is deleted.
+ updateScheduledRecording(false, ScheduledRecording.toArray(toUpdate));
+ }
+ if (!toDelete.isEmpty()) {
+ removeScheduledRecording(true, ScheduledRecording.toArray(toDelete));
+ }
+ if (mDvrLoadFinished) {
+ notifySeriesRecordingRemoved(seriesRecordings);
+ }
+ new AsyncDeleteSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings);
+ removeDeletedSchedules(seriesRecordings);
+ }
@Override
- public void updateScheduledRecording(final ScheduledRecording scheduledRecording) {
- new AsyncDvrDbTask.AsyncUpdateRecordingTask(mContext) {
- @Override
- protected void onPostExecute(List<Integer> counts) {
- super.onPostExecute(counts);
- SoftPreconditions.checkArgument(counts.size() == 1);
- for (Integer c : counts) {
- if (c == 1) {
- ScheduledRecording oldScheduledRecording = mScheduledRecordings
- .put(scheduledRecording.getId(), scheduledRecording);
- long programId = scheduledRecording.getProgramId();
- if (oldScheduledRecording != null
- && oldScheduledRecording.getProgramId() != programId
- && oldScheduledRecording.getProgramId()
- != ScheduledRecording.ID_NOT_SET) {
- ScheduledRecording oldValueForProgramId = mProgramId2ScheduledRecordings
- .get(oldScheduledRecording.getProgramId());
- if (oldValueForProgramId.getId() == scheduledRecording.getId()) {
- //Only remove the old ScheduledRecording if it has the same ID as
- // the new one.
- mProgramId2ScheduledRecordings
- .remove(oldScheduledRecording.getProgramId());
- }
- }
- if (programId != ScheduledRecording.ID_NOT_SET) {
- mProgramId2ScheduledRecordings.put(programId, scheduledRecording);
- }
- //TODO change to notifyRecordingUpdated
- notifyScheduledRecordingStatusChanged(scheduledRecording);
- } else {
- Log.w(TAG, "Error updating " + scheduledRecording);
- }
+ public void updateScheduledRecording(final ScheduledRecording... schedules) {
+ updateScheduledRecording(true, schedules);
+ }
+
+ private void updateScheduledRecording(boolean updateDb, final ScheduledRecording... schedules) {
+ List<ScheduledRecording> toUpdate = new ArrayList<>();
+ for (ScheduledRecording r : schedules) {
+ if (!SoftPreconditions.checkState(mScheduledRecordings.containsKey(r.getId()), TAG,
+ "Recording not found for: " + r)) {
+ continue;
+ }
+ toUpdate.add(r);
+ ScheduledRecording oldScheduledRecording = mScheduledRecordings.put(r.getId(), r);
+ // The channel ID should not be changed.
+ SoftPreconditions.checkState(r.getChannelId() == oldScheduledRecording.getChannelId());
+ long programId = r.getProgramId();
+ if (oldScheduledRecording.getProgramId() != programId
+ && oldScheduledRecording.getProgramId() != ScheduledRecording.ID_NOT_SET) {
+ ScheduledRecording oldValueForProgramId = mProgramId2ScheduledRecordings
+ .get(oldScheduledRecording.getProgramId());
+ if (oldValueForProgramId.getId() == r.getId()) {
+ // Only remove the old ScheduledRecording if it has the same ID as the new one.
+ mProgramId2ScheduledRecordings.remove(oldScheduledRecording.getProgramId());
}
}
- }.executeOnDbThread(scheduledRecording);
+ if (programId != ScheduledRecording.ID_NOT_SET) {
+ mProgramId2ScheduledRecordings.put(programId, r);
+ }
+ }
+ if (toUpdate.isEmpty()) {
+ return;
+ }
+ ScheduledRecording[] scheduleArray = ScheduledRecording.toArray(toUpdate);
+ if (mDvrLoadFinished) {
+ notifyScheduledRecordingStatusChanged(scheduleArray);
+ }
+ if (updateDb) {
+ new AsyncUpdateScheduleTask(mContext).executeOnDbThread(scheduleArray);
+ }
+ removeDeletedSchedules(schedules);
}
- private final class AsyncRecordedProgramsQueryTask
- extends AsyncDbTask.AsyncQueryListTask<RecordedProgram> {
- public AsyncRecordedProgramsQueryTask(ContentResolver contentResolver) {
- super(contentResolver, TvContract.RecordedPrograms.CONTENT_URI,
- RecordedProgram.PROJECTION, null, null, null);
+ @Override
+ public void updateSeriesRecording(final SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ 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: " + r);
}
+ if (mDvrLoadFinished) {
+ notifySeriesRecordingChanged(seriesRecordings);
+ }
+ new AsyncUpdateSeriesRecordingTask(mContext).executeOnDbThread(seriesRecordings);
+ }
- @Override
- protected RecordedProgram fromCursor(Cursor c) {
- return RecordedProgram.fromCursor(c);
+ private boolean isInputAvailable(String inputId) {
+ return mInputManager.hasTvInputInfo(inputId)
+ && (!Utils.isBundledInput(inputId) || mStorageStatusManager.isStorageMounted());
+ }
+
+ private void removeDeletedSchedules(ScheduledRecording... addedSchedules) {
+ List<ScheduledRecording> schedulesToDelete = new ArrayList<>();
+ for (ScheduledRecording r : addedSchedules) {
+ ScheduledRecording deleted = getDeletedScheduleMap().remove(r.getProgramId());
+ if (deleted != null) {
+ schedulesToDelete.add(deleted);
+ }
+ }
+ if (!schedulesToDelete.isEmpty()) {
+ new AsyncDeleteScheduleTask(mContext).executeOnDbThread(
+ ScheduledRecording.toArray(schedulesToDelete));
}
+ }
- @Override
- protected void onCancelled(List<RecordedProgram> scheduledRecordings) {
- mPendingTasks.remove(this);
+ private void removeDeletedSchedules(SeriesRecording... removedSeriesRecordings) {
+ Set<Long> seriesRecordingIds = new HashSet<>();
+ for (SeriesRecording r : removedSeriesRecordings) {
+ seriesRecordingIds.add(r.getId());
+ }
+ List<ScheduledRecording> schedulesToDelete = new ArrayList<>();
+ Iterator<Entry<Long, ScheduledRecording>> iter =
+ getDeletedScheduleMap().entrySet().iterator();
+ while (iter.hasNext()) {
+ Entry<Long, ScheduledRecording> entry = iter.next();
+ if (seriesRecordingIds.contains(entry.getValue().getSeriesRecordingId())) {
+ schedulesToDelete.add(entry.getValue());
+ iter.remove();
+ }
+ }
+ if (!schedulesToDelete.isEmpty()) {
+ new AsyncDeleteScheduleTask(mContext).executeOnDbThread(
+ ScheduledRecording.toArray(schedulesToDelete));
}
+ }
- @Override
- protected void onPostExecute(List<RecordedProgram> result) {
- mPendingTasks.remove(this);
- mRecordedProgramLoadFinished = true;
- if (result != null) {
- for (RecordedProgram r : result) {
- mRecordedPrograms.put(r.getId(), r);
- }
+ private void unhideInput(String inputId) {
+ if (DEBUG) Log.d(TAG, "unhideInput " + inputId);
+ List<ScheduledRecording> movedSchedules =
+ moveElements(mScheduledRecordingsForRemovedInput, mScheduledRecordings,
+ new Filter<ScheduledRecording>() {
+ @Override
+ public boolean filter(ScheduledRecording r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ List<SeriesRecording> movedSeriesRecordings =
+ moveElements(mSeriesRecordingsForRemovedInput, mSeriesRecordings,
+ new Filter<SeriesRecording>() {
+ @Override
+ public boolean filter(SeriesRecording r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ List<RecordedProgram> movedRecordedPrograms =
+ moveElements(mRecordedProgramsForRemovedInput, mRecordedPrograms,
+ new Filter<RecordedProgram>() {
+ @Override
+ public boolean filter(RecordedProgram r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ if (!movedSchedules.isEmpty()) {
+ for (ScheduledRecording schedule : movedSchedules) {
+ mProgramId2ScheduledRecordings.put(schedule.getProgramId(), schedule);
+ }
+ }
+ if (!movedSeriesRecordings.isEmpty()) {
+ for (SeriesRecording seriesRecording : movedSeriesRecordings) {
+ mSeriesId2SeriesRecordings.put(seriesRecording.getSeriesId(), seriesRecording);
+ }
+ }
+ // Notify after all the data are moved.
+ if (!movedSchedules.isEmpty()) {
+ notifyScheduledRecordingAdded(ScheduledRecording.toArray(movedSchedules));
+ }
+ if (!movedSeriesRecordings.isEmpty()) {
+ notifySeriesRecordingAdded(SeriesRecording.toArray(movedSeriesRecordings));
+ }
+ if (!movedRecordedPrograms.isEmpty()) {
+ notifyRecordedProgramsAdded(RecordedProgram.toArray(movedRecordedPrograms));
+ }
+ }
+
+ private void hideInput(String inputId) {
+ if (DEBUG) Log.d(TAG, "hideInput " + inputId);
+ List<ScheduledRecording> movedSchedules =
+ moveElements(mScheduledRecordings, mScheduledRecordingsForRemovedInput,
+ new Filter<ScheduledRecording>() {
+ @Override
+ public boolean filter(ScheduledRecording r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ List<SeriesRecording> movedSeriesRecordings =
+ moveElements(mSeriesRecordings, mSeriesRecordingsForRemovedInput,
+ new Filter<SeriesRecording>() {
+ @Override
+ public boolean filter(SeriesRecording r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ List<RecordedProgram> movedRecordedPrograms =
+ moveElements(mRecordedPrograms, mRecordedProgramsForRemovedInput,
+ new Filter<RecordedProgram>() {
+ @Override
+ public boolean filter(RecordedProgram r) {
+ return r.getInputId().equals(inputId);
+ }
+ });
+ if (!movedSchedules.isEmpty()) {
+ for (ScheduledRecording schedule : movedSchedules) {
+ mProgramId2ScheduledRecordings.remove(schedule.getProgramId());
+ }
+ }
+ if (!movedSeriesRecordings.isEmpty()) {
+ for (SeriesRecording seriesRecording : movedSeriesRecordings) {
+ mSeriesId2SeriesRecordings.remove(seriesRecording.getSeriesId());
}
}
+ // Notify after all the data are moved.
+ if (!movedSchedules.isEmpty()) {
+ notifyScheduledRecordingRemoved(ScheduledRecording.toArray(movedSchedules));
+ }
+ if (!movedSeriesRecordings.isEmpty()) {
+ notifySeriesRecordingRemoved(SeriesRecording.toArray(movedSeriesRecordings));
+ }
+ if (!movedRecordedPrograms.isEmpty()) {
+ notifyRecordedProgramsRemoved(RecordedProgram.toArray(movedRecordedPrograms));
+ }
}
- private final class AsyncRecordedProgramQueryTask
- extends AsyncDbTask.AsyncQueryItemTask<RecordedProgram> {
+ @Override
+ public void forgetStorage(String inputId) {
+ List<ScheduledRecording> schedulesToDelete = new ArrayList<>();
+ for (Iterator<ScheduledRecording> i =
+ mScheduledRecordingsForRemovedInput.values().iterator(); i.hasNext(); ) {
+ ScheduledRecording r = i.next();
+ if (inputId.equals(r.getInputId())) {
+ schedulesToDelete.add(r);
+ i.remove();
+ }
+ }
+ List<SeriesRecording> seriesRecordingsToDelete = new ArrayList<>();
+ for (Iterator<SeriesRecording> i =
+ mSeriesRecordingsForRemovedInput.values().iterator(); i.hasNext(); ) {
+ SeriesRecording r = i.next();
+ if (inputId.equals(r.getInputId())) {
+ seriesRecordingsToDelete.add(r);
+ i.remove();
+ }
+ }
+ for (Iterator<RecordedProgram> i =
+ mRecordedProgramsForRemovedInput.values().iterator(); i.hasNext(); ) {
+ if (inputId.equals(i.next().getInputId())) {
+ i.remove();
+ }
+ }
+ new AsyncDeleteScheduleTask(mContext).executeOnDbThread(
+ ScheduledRecording.toArray(schedulesToDelete));
+ new AsyncDeleteSeriesRecordingTask(mContext).executeOnDbThread(
+ SeriesRecording.toArray(seriesRecordingsToDelete));
+ new AsyncDbTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ ContentResolver resolver = mContext.getContentResolver();
+ String args[] = { inputId };
+ try {
+ resolver.delete(RecordedPrograms.CONTENT_URI,
+ RecordedPrograms.COLUMN_INPUT_ID + " = ?", args);
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Failed to delete recorded programs for inputId: " + inputId, e);
+ }
+ return null;
+ }
+ }.executeOnDbThread();
+ }
+ private final class RecordedProgramsQueryTask extends AsyncRecordedProgramQueryTask {
private final Uri mUri;
- public AsyncRecordedProgramQueryTask(ContentResolver contentResolver, Uri uri) {
- super(contentResolver, uri, RecordedProgram.PROJECTION, null, null, null);
+ public RecordedProgramsQueryTask(ContentResolver contentResolver, Uri uri) {
+ super(contentResolver, uri == null ? RecordedPrograms.CONTENT_URI : uri);
mUri = uri;
}
@Override
- protected RecordedProgram fromCursor(Cursor c) {
- return RecordedProgram.fromCursor(c);
- }
-
- @Override
- protected void onCancelled(RecordedProgram recordedProgram) {
+ protected void onCancelled(List<RecordedProgram> scheduledRecordings) {
mPendingTasks.remove(this);
}
@Override
- protected void onPostExecute(RecordedProgram recordedProgram) {
+ protected void onPostExecute(List<RecordedProgram> result) {
mPendingTasks.remove(this);
- onObservedChange(mUri, recordedProgram);
+ onRecordedProgramsLoadedFinished(mUri, result);
}
}
}
diff --git a/src/com/android/tv/dvr/DvrDbSync.java b/src/com/android/tv/dvr/DvrDbSync.java
new file mode 100644
index 00000000..df181455
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrDbSync.java
@@ -0,0 +1,363 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.ContentUris;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.media.tv.TvContract.Programs;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.MainThread;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.android.tv.TvApplication;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.util.AsyncDbTask.AsyncQueryProgramTask;
+import com.android.tv.util.TvProviderUriMatcher;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * A class to synchronizes DVR DB with TvProvider.
+ *
+ * <p>The current implementation of AsyncDbTask allows only one task to run at a time, and all the
+ * other tasks are blocked until the current one finishes. As this class performs the low priority
+ * jobs which take long time, it should not block others if possible. For this reason, only one
+ * program is queried at a time and others are queued and will be executed on the other
+ * AsyncDbTask's after the current one finishes to minimize the execution time of one AsyncDbTask.
+ */
+@MainThread
+@TargetApi(Build.VERSION_CODES.N)
+class DvrDbSync {
+ private static final String TAG = "DvrDbSync";
+ private static final boolean DEBUG = false;
+
+ private final Context mContext;
+ private final DvrDataManagerImpl mDataManager;
+ private final ChannelDataManager mChannelDataManager;
+ private final Queue<Long> mProgramIdQueue = new LinkedList<>();
+ private QueryProgramTask mQueryProgramTask;
+ private final SeriesRecordingScheduler mSeriesRecordingScheduler;
+ private final ContentObserver mContentObserver = new ContentObserver(new Handler(
+ Looper.getMainLooper())) {
+ @SuppressLint("SwitchIntDef")
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ switch (TvProviderUriMatcher.match(uri)) {
+ case TvProviderUriMatcher.MATCH_PROGRAM:
+ if (DEBUG) Log.d(TAG, "onProgramsUpdated");
+ onProgramsUpdated();
+ break;
+ case TvProviderUriMatcher.MATCH_PROGRAM_ID:
+ if (DEBUG) {
+ Log.d(TAG, "onProgramUpdated: programId=" + ContentUris.parseId(uri));
+ }
+ onProgramUpdated(ContentUris.parseId(uri));
+ break;
+ }
+ }
+ };
+
+ private final ChannelDataManager.Listener mChannelDataManagerListener =
+ new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ start();
+ }
+
+ @Override
+ public void onChannelListUpdated() {
+ onChannelsUpdated();
+ }
+
+ @Override
+ public void onChannelBrowsableChanged() { }
+ };
+
+ private final ScheduledRecordingListener mScheduleListener = new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ addProgramIdToCheckIfNeeded(schedule);
+ }
+ startNextUpdateIfNeeded();
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ mProgramIdQueue.remove(schedule.getProgramId());
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ mProgramIdQueue.remove(schedule.getProgramId());
+ addProgramIdToCheckIfNeeded(schedule);
+ }
+ startNextUpdateIfNeeded();
+ }
+ };
+
+ DvrDbSync(Context context, DvrDataManagerImpl dataManager) {
+ this(context, dataManager, TvApplication.getSingletons(context).getChannelDataManager());
+ }
+
+ @VisibleForTesting
+ DvrDbSync(Context context, DvrDataManagerImpl dataManager,
+ ChannelDataManager channelDataManager) {
+ mContext = context;
+ mDataManager = dataManager;
+ mChannelDataManager = channelDataManager;
+ mSeriesRecordingScheduler = SeriesRecordingScheduler.getInstance(context);
+ }
+
+ /**
+ * Starts the DB sync.
+ */
+ public void start() {
+ if (!mChannelDataManager.isDbLoadFinished()) {
+ mChannelDataManager.addListener(mChannelDataManagerListener);
+ return;
+ }
+ mContext.getContentResolver().registerContentObserver(Programs.CONTENT_URI, true,
+ mContentObserver);
+ mDataManager.addScheduledRecordingListener(mScheduleListener);
+ onChannelsUpdated();
+ onProgramsUpdated();
+ }
+
+ /**
+ * Stops the DB sync.
+ */
+ public void stop() {
+ mProgramIdQueue.clear();
+ if (mQueryProgramTask != null) {
+ mQueryProgramTask.cancel(true);
+ }
+ mChannelDataManager.removeListener(mChannelDataManagerListener);
+ mDataManager.removeScheduledRecordingListener(mScheduleListener);
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ }
+
+ private void onChannelsUpdated() {
+ List<SeriesRecording> seriesRecordingsToUpdate = new ArrayList<>();
+ for (SeriesRecording r : mDataManager.getSeriesRecordings()) {
+ if (r.getChannelOption() == SeriesRecording.OPTION_CHANNEL_ONE
+ && !mChannelDataManager.doesChannelExistInDb(r.getChannelId())) {
+ seriesRecordingsToUpdate.add(SeriesRecording.buildFrom(r)
+ .setChannelOption(SeriesRecording.OPTION_CHANNEL_ALL)
+ .setState(SeriesRecording.STATE_SERIES_STOPPED).build());
+ }
+ }
+ if (!seriesRecordingsToUpdate.isEmpty()) {
+ mDataManager.updateSeriesRecording(
+ SeriesRecording.toArray(seriesRecordingsToUpdate));
+ }
+ List<ScheduledRecording> schedulesToRemove = new ArrayList<>();
+ for (ScheduledRecording r : mDataManager.getAvailableScheduledRecordings()) {
+ if (!mChannelDataManager.doesChannelExistInDb(r.getChannelId())) {
+ schedulesToRemove.add(r);
+ mProgramIdQueue.remove(r.getProgramId());
+ }
+ }
+ if (!schedulesToRemove.isEmpty()) {
+ mDataManager.removeScheduledRecording(
+ ScheduledRecording.toArray(schedulesToRemove));
+ }
+ }
+
+ private void onProgramsUpdated() {
+ for (ScheduledRecording schedule : mDataManager.getAvailableScheduledRecordings()) {
+ addProgramIdToCheckIfNeeded(schedule);
+ }
+ startNextUpdateIfNeeded();
+ }
+
+ private void onProgramUpdated(long programId) {
+ addProgramIdToCheckIfNeeded(mDataManager.getScheduledRecordingForProgramId(programId));
+ startNextUpdateIfNeeded();
+ }
+
+ private void addProgramIdToCheckIfNeeded(ScheduledRecording schedule) {
+ if (schedule == null) {
+ return;
+ }
+ long programId = schedule.getProgramId();
+ if (programId != ScheduledRecording.ID_NOT_SET
+ && !mProgramIdQueue.contains(programId)
+ && (schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS)) {
+ if (DEBUG) Log.d(TAG, "Program ID enqueued: " + programId);
+ mProgramIdQueue.offer(programId);
+ // There are schedules to be updated. Pause the SeriesRecordingScheduler until all the
+ // schedule updates finish.
+ // Note that the SeriesRecordingScheduler should be paused even though the program to
+ // check is not episodic because it can be changed to the episodic program after the
+ // update, which affect the SeriesRecordingScheduler.
+ mSeriesRecordingScheduler.pauseUpdate();
+ }
+ }
+
+ private void startNextUpdateIfNeeded() {
+ if (mQueryProgramTask != null && !mQueryProgramTask.isCancelled()) {
+ return;
+ }
+ if (!mProgramIdQueue.isEmpty()) {
+ if (DEBUG) Log.d(TAG, "Program ID dequeued: " + mProgramIdQueue.peek());
+ mQueryProgramTask = new QueryProgramTask(mProgramIdQueue.poll());
+ mQueryProgramTask.executeOnDbThread();
+ } else {
+ mSeriesRecordingScheduler.resumeUpdate();
+ }
+ }
+
+ @VisibleForTesting
+ void handleUpdateProgram(Program program, long programId) {
+ Set<SeriesRecording> seriesRecordingsToUpdate = new HashSet<>();
+ ScheduledRecording schedule = mDataManager.getScheduledRecordingForProgramId(programId);
+ if (schedule != null
+ && (schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS)) {
+ if (program == null) {
+ mDataManager.removeScheduledRecording(schedule);
+ if (schedule.getSeriesRecordingId() != SeriesRecording.ID_NOT_SET) {
+ SeriesRecording seriesRecording =
+ mDataManager.getSeriesRecording(schedule.getSeriesRecordingId());
+ if (seriesRecording != null) {
+ seriesRecordingsToUpdate.add(seriesRecording);
+ }
+ }
+ } else {
+ long currentTimeMs = System.currentTimeMillis();
+ ScheduledRecording.Builder builder = ScheduledRecording.buildFrom(schedule)
+ .setEndTimeMs(program.getEndTimeUtcMillis())
+ .setSeasonNumber(program.getSeasonNumber())
+ .setEpisodeNumber(program.getEpisodeNumber())
+ .setEpisodeTitle(program.getEpisodeTitle())
+ .setProgramDescription(program.getDescription())
+ .setProgramLongDescription(program.getLongDescription())
+ .setProgramPosterArtUri(program.getPosterArtUri())
+ .setProgramThumbnailUri(program.getThumbnailUri());
+ boolean needUpdate = false;
+ // Check the series recording.
+ SeriesRecording seriesRecordingForOldSchedule =
+ mDataManager.getSeriesRecording(schedule.getSeriesRecordingId());
+ if (program.getSeriesId() != null) {
+ // New program belongs to a series.
+ SeriesRecording seriesRecording =
+ mDataManager.getSeriesRecording(program.getSeriesId());
+ if (seriesRecording == null) {
+ // The new program is episodic while the previous one isn't.
+ SeriesRecording newSeriesRecording = TvApplication.getSingletons(mContext)
+ .getDvrManager().addSeriesRecording(program,
+ Collections.singletonList(program),
+ SeriesRecording.STATE_SERIES_STOPPED);
+ builder.setSeriesRecordingId(newSeriesRecording.getId());
+ needUpdate = true;
+ } else if (seriesRecording.getId() != schedule.getSeriesRecordingId()) {
+ // The new program belongs to the other series.
+ builder.setSeriesRecordingId(seriesRecording.getId());
+ needUpdate = true;
+ seriesRecordingsToUpdate.add(seriesRecording);
+ if (seriesRecordingForOldSchedule != null) {
+ seriesRecordingsToUpdate.add(seriesRecordingForOldSchedule);
+ }
+ } else if (!Objects.equals(schedule.getSeasonNumber(),
+ program.getSeasonNumber())
+ || !Objects.equals(schedule.getEpisodeNumber(),
+ program.getEpisodeNumber())) {
+ // The episode number has been changed.
+ if (seriesRecordingForOldSchedule != null) {
+ seriesRecordingsToUpdate.add(seriesRecordingForOldSchedule);
+ }
+ }
+ } else if (seriesRecordingForOldSchedule != null) {
+ // Old program belongs to a series but the new one doesn't.
+ seriesRecordingsToUpdate.add(seriesRecordingForOldSchedule);
+ }
+ // Change start time only when the recording start time has not passed.
+ boolean needToChangeStartTime = schedule.getStartTimeMs() > currentTimeMs
+ && program.getStartTimeUtcMillis() != schedule.getStartTimeMs();
+ if (needToChangeStartTime) {
+ builder.setStartTimeMs(program.getStartTimeUtcMillis());
+ needUpdate = true;
+ }
+ if (needUpdate || schedule.getEndTimeMs() != program.getEndTimeUtcMillis()
+ || !Objects.equals(schedule.getSeasonNumber(), program.getSeasonNumber())
+ || !Objects.equals(schedule.getEpisodeNumber(), program.getEpisodeNumber())
+ || !Objects.equals(schedule.getEpisodeTitle(), program.getEpisodeTitle())
+ || !Objects.equals(schedule.getProgramDescription(),
+ program.getDescription())
+ || !Objects.equals(schedule.getProgramLongDescription(),
+ program.getLongDescription())
+ || !Objects.equals(schedule.getProgramPosterArtUri(),
+ program.getPosterArtUri())
+ || !Objects.equals(schedule.getProgramThumbnailUri(),
+ program.getThumbnailUri())) {
+ mDataManager.updateScheduledRecording(builder.build());
+ }
+ if (!seriesRecordingsToUpdate.isEmpty()) {
+ // The series recordings will be updated after it's resumed.
+ mSeriesRecordingScheduler.updateSchedules(seriesRecordingsToUpdate);
+ }
+ }
+ }
+ }
+
+ private class QueryProgramTask extends AsyncQueryProgramTask {
+ private final long mProgramId;
+
+ QueryProgramTask(long programId) {
+ super(mContext.getContentResolver(), programId);
+ mProgramId = programId;
+ }
+
+ @Override
+ protected void onCancelled(Program program) {
+ if (mQueryProgramTask == this) {
+ mQueryProgramTask = null;
+ }
+ startNextUpdateIfNeeded();
+ }
+
+ @Override
+ protected void onPostExecute(Program program) {
+ if (mQueryProgramTask == this) {
+ mQueryProgramTask = null;
+ }
+ handleUpdateProgram(program, mProgramId);
+ startNextUpdateIfNeeded();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/DvrManager.java b/src/com/android/tv/dvr/DvrManager.java
index e3dc622e..5fa6f90f 100644
--- a/src/com/android/tv/dvr/DvrManager.java
+++ b/src/com/android/tv/dvr/DvrManager.java
@@ -16,28 +16,43 @@
package com.android.tv.dvr;
+import android.annotation.TargetApi;
+import android.content.ContentProviderOperation;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.Context;
+import android.content.OperationApplicationException;
+import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Build;
import android.os.Handler;
+import android.os.RemoteException;
import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.util.Log;
import android.util.Range;
-import android.widget.Toast;
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.recording.RecordedProgram;
import com.android.tv.data.Channel;
-import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
+import com.android.tv.dvr.DvrScheduleManager.OnInitializeListener;
+import com.android.tv.dvr.SeriesRecording.SeriesState;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.Utils;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@@ -49,68 +64,375 @@ import java.util.Map.Entry;
* instead of modifying them directly through {@link DvrDataManager}.
*/
@MainThread
+@TargetApi(Build.VERSION_CODES.N)
public class DvrManager {
- private final static String TAG = "DvrManager";
+ private static final String TAG = "DvrManager";
+ private static final boolean DEBUG = false;
+
private final WritableDvrDataManager mDataManager;
- private final ChannelDataManager mChannelDataManager;
- private final DvrSessionManager mDvrSessionManager;
+ private final DvrScheduleManager mScheduleManager;
// @GuardedBy("mListener")
private final Map<Listener, Handler> mListener = new HashMap<>();
private final Context mAppContext;
public DvrManager(Context context) {
SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
+ mAppContext = context.getApplicationContext();
ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
mDataManager = (WritableDvrDataManager) appSingletons.getDvrDataManager();
- mAppContext = context.getApplicationContext();
- mChannelDataManager = appSingletons.getChannelDataManager();
- mDvrSessionManager = appSingletons.getDvrSessionManger();
+ mScheduleManager = appSingletons.getDvrScheduleManager();
+ if (mDataManager.isInitialized() && mScheduleManager.isInitialized()) {
+ createSeriesRecordingsForRecordedProgramsIfNeeded(mDataManager.getRecordedPrograms());
+ } else {
+ // No need to handle DVR schedule load finished because schedule manager is initialized
+ // after the all the schedules are loaded.
+ if (!mDataManager.isRecordedProgramLoadFinished()) {
+ mDataManager.addRecordedProgramLoadFinishedListener(
+ new OnRecordedProgramLoadFinishedListener() {
+ @Override
+ public void onRecordedProgramLoadFinished() {
+ mDataManager.removeRecordedProgramLoadFinishedListener(this);
+ if (mDataManager.isInitialized()
+ && mScheduleManager.isInitialized()) {
+ createSeriesRecordingsForRecordedProgramsIfNeeded(
+ mDataManager.getRecordedPrograms());
+ }
+ }
+ });
+ }
+ if (!mScheduleManager.isInitialized()) {
+ mScheduleManager.addOnInitializeListener(new OnInitializeListener() {
+ @Override
+ public void onInitialize() {
+ mScheduleManager.removeOnInitializeListener(this);
+ if (mDataManager.isInitialized() && mScheduleManager.isInitialized()) {
+ createSeriesRecordingsForRecordedProgramsIfNeeded(
+ mDataManager.getRecordedPrograms());
+ }
+ }
+ });
+ }
+ }
+ mDataManager.addRecordedProgramListener(new RecordedProgramListener() {
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ if (!mDataManager.isInitialized() || !mScheduleManager.isInitialized()) {
+ return;
+ }
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ createSeriesRecordingForRecordedProgramIfNeeded(recordedProgram);
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) { }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ // Removing series recording is handled in the SeriesRecordingDetailsFragment.
+ }
+ });
+ }
+
+ private void createSeriesRecordingsForRecordedProgramsIfNeeded(
+ List<RecordedProgram> recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ createSeriesRecordingForRecordedProgramIfNeeded(recordedProgram);
+ }
+ }
+
+ private void createSeriesRecordingForRecordedProgramIfNeeded(RecordedProgram recordedProgram) {
+ if (recordedProgram.getSeriesId() != null) {
+ SeriesRecording seriesRecording =
+ mDataManager.getSeriesRecording(recordedProgram.getSeriesId());
+ if (seriesRecording == null) {
+ addSeriesRecording(recordedProgram);
+ }
+ }
}
/**
- * Schedules a recording for {@code program} instead of the list of recording that conflict.
- * @param program the program to record
- * @param recordingsToOverride the possible empty list of recordings that will not be recorded
+ * Schedules a recording for {@code program}.
*/
- public void addSchedule(Program program, List<ScheduledRecording> recordingsToOverride) {
- Log.i(TAG,
- "Adding scheduled recording of " + program + " instead of " + recordingsToOverride);
- Collections.sort(recordingsToOverride, ScheduledRecording.PRIORITY_COMPARATOR);
- Channel c = mChannelDataManager.getChannel(program.getChannelId());
- long priority = recordingsToOverride.isEmpty() ? Long.MAX_VALUE
- : recordingsToOverride.get(0).getPriority() - 1;
- ScheduledRecording r = ScheduledRecording.builder(program)
+ public ScheduledRecording addSchedule(Program program) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return null;
+ }
+ SeriesRecording seriesRecording = getSeriesRecording(program);
+ return addSchedule(program, seriesRecording == null
+ ? mScheduleManager.suggestNewPriority()
+ : seriesRecording.getPriority());
+ }
+
+ /**
+ * Schedules a recording for {@code program} with the highest priority so that the schedule
+ * can be recorded.
+ */
+ public ScheduledRecording addScheduleWithHighestPriority(Program program) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return null;
+ }
+ SeriesRecording seriesRecording = getSeriesRecording(program);
+ return addSchedule(program, seriesRecording == null
+ ? mScheduleManager.suggestNewPriority()
+ : mScheduleManager.suggestHighestPriority(seriesRecording.getInputId(),
+ new Range(program.getStartTimeUtcMillis(), program.getEndTimeUtcMillis()),
+ seriesRecording.getPriority()));
+ }
+
+ private ScheduledRecording addSchedule(Program program, long priority) {
+ TvInputInfo input = Utils.getTvInputInfoForProgram(mAppContext, program);
+ if (input == null) {
+ Log.e(TAG, "Can't find input for program: " + program);
+ return null;
+ }
+ ScheduledRecording schedule;
+ SeriesRecording seriesRecording = getSeriesRecording(program);
+ schedule = createScheduledRecordingBuilder(input.getId(), program)
.setPriority(priority)
- .setChannelId(c.getId())
+ .setSeriesRecordingId(seriesRecording == null ? SeriesRecording.ID_NOT_SET
+ : seriesRecording.getId())
.build();
- mDataManager.addScheduledRecording(r);
+ mDataManager.addScheduledRecording(schedule);
+ return schedule;
}
/**
* Adds a recording schedule with a time range.
*/
public void addSchedule(Channel channel, long startTime, long endTime) {
- Log.i(TAG, "Adding scheduled recording of channel" + channel + " starting at " +
+ Log.i(TAG, "Adding scheduled recording of channel " + channel + " starting at " +
Utils.toTimeString(startTime) + " and ending at " + Utils.toTimeString(endTime));
- //TODO: handle error cases
- ScheduledRecording r = ScheduledRecording.builder(startTime, endTime)
- .setChannelId(channel.getId())
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
+ TvInputInfo input = Utils.getTvInputInfoForChannelId(mAppContext, channel.getId());
+ if (input == null) {
+ Log.e(TAG, "Can't find input for channel: " + channel);
+ return;
+ }
+ addScheduleInternal(input.getId(), channel.getId(), startTime, endTime);
+ }
+
+ /**
+ * Adds the schedule.
+ */
+ public void addSchedule(ScheduledRecording schedule) {
+ if (mDataManager.isDvrScheduleLoadFinished()) {
+ mDataManager.addScheduledRecording(schedule);
+ }
+ }
+
+ private void addScheduleInternal(String inputId, long channelId, long startTime, long endTime) {
+ mDataManager.addScheduledRecording(ScheduledRecording
+ .builder(inputId, channelId, startTime, endTime)
+ .setPriority(mScheduleManager.suggestNewPriority())
+ .build());
+ }
+
+ /**
+ * Adds a new series recording and schedules for the programs with the initial state.
+ */
+ public SeriesRecording addSeriesRecording(Program selectedProgram,
+ List<Program> programsToSchedule, @SeriesState int initialState) {
+ Log.i(TAG, "Adding series recording for program " + selectedProgram + ", and schedules: "
+ + programsToSchedule);
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
+ return null;
+ }
+ TvInputInfo input = Utils.getTvInputInfoForProgram(mAppContext, selectedProgram);
+ if (input == null) {
+ Log.e(TAG, "Can't find input for program: " + selectedProgram);
+ return null;
+ }
+ SeriesRecording seriesRecording = SeriesRecording.builder(input.getId(), selectedProgram)
+ .setPriority(mScheduleManager.suggestNewSeriesPriority())
+ .setState(initialState)
.build();
- mDataManager.addScheduledRecording(r);
+ mDataManager.addSeriesRecording(seriesRecording);
+ // The schedules for the recorded programs should be added not to create the schedule the
+ // duplicate episodes.
+ addRecordedProgramToSeriesRecording(seriesRecording);
+ addScheduleToSeriesRecording(seriesRecording, programsToSchedule);
+ return seriesRecording;
+ }
+
+ private void addSeriesRecording(RecordedProgram recordedProgram) {
+ SeriesRecording seriesRecording =
+ SeriesRecording.builder(recordedProgram.getInputId(), recordedProgram)
+ .setPriority(mScheduleManager.suggestNewSeriesPriority())
+ .setState(SeriesRecording.STATE_SERIES_STOPPED)
+ .build();
+ mDataManager.addSeriesRecording(seriesRecording);
+ // The schedules for the recorded programs should be added not to create the schedule the
+ // duplicate episodes.
+ addRecordedProgramToSeriesRecording(seriesRecording);
+ }
+
+ private void addRecordedProgramToSeriesRecording(SeriesRecording series) {
+ List<ScheduledRecording> toAdd = new ArrayList<>();
+ for (RecordedProgram recordedProgram : mDataManager.getRecordedPrograms()) {
+ if (series.getSeriesId().equals(recordedProgram.getSeriesId())
+ && !recordedProgram.isClipped()) {
+ // Duplicate schedules can exist, but they will be deleted in a few days. And it's
+ // also guaranteed that the schedules don't belong to any series recordings because
+ // there are no more than one series recordings which have the same program title.
+ toAdd.add(ScheduledRecording.builder(recordedProgram)
+ .setPriority(series.getPriority())
+ .setSeriesRecordingId(series.getId()).build());
+ }
+ }
+ if (!toAdd.isEmpty()) {
+ mDataManager.addScheduledRecording(ScheduledRecording.toArray(toAdd));
+ }
}
/**
- * Adds a season recording schedule based on {@code program}.
+ * Adds {@link ScheduledRecording}s for the series recording.
+ * <p>
+ * This method doesn't add the series recording.
*/
- public void addSeasonSchedule(Program program) {
- Log.i(TAG, "Adding season recording of " + program);
- // TODO: implement
+ public void addScheduleToSeriesRecording(SeriesRecording series,
+ List<Program> programsToSchedule) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mAppContext, series.getInputId());
+ if (input == null) {
+ Log.e(TAG, "Can't find input with ID: " + series.getInputId());
+ return;
+ }
+ List<ScheduledRecording> toAdd = new ArrayList<>();
+ List<ScheduledRecording> toUpdate = new ArrayList<>();
+ for (Program program : programsToSchedule) {
+ ScheduledRecording scheduleWithSameProgram =
+ mDataManager.getScheduledRecordingForProgramId(program.getId());
+ if (scheduleWithSameProgram != null) {
+ if (scheduleWithSameProgram.getState()
+ == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ ScheduledRecording r = ScheduledRecording.buildFrom(scheduleWithSameProgram)
+ .setSeriesRecordingId(series.getId())
+ .build();
+ if (!r.equals(scheduleWithSameProgram)) {
+ toUpdate.add(r);
+ }
+ }
+ } else {
+ toAdd.add(createScheduledRecordingBuilder(input.getId(), program)
+ .setPriority(series.getPriority())
+ .setSeriesRecordingId(series.getId())
+ .build());
+ }
+ }
+ if (!toAdd.isEmpty()) {
+ mDataManager.addScheduledRecording(ScheduledRecording.toArray(toAdd));
+ }
+ if (!toUpdate.isEmpty()) {
+ mDataManager.updateScheduledRecording(ScheduledRecording.toArray(toUpdate));
+ }
+ }
+
+ /**
+ * Updates the series recording.
+ */
+ public void updateSeriesRecording(SeriesRecording series) {
+ if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ SeriesRecordingScheduler scheduler = SeriesRecordingScheduler.getInstance(mAppContext);
+ scheduler.pauseUpdate();
+ SeriesRecording previousSeries = mDataManager.getSeriesRecording(series.getId());
+ if (previousSeries != null) {
+ if (previousSeries.getChannelOption() != series.getChannelOption()
+ || (previousSeries.getChannelOption() == SeriesRecording.OPTION_CHANNEL_ONE
+ && previousSeries.getChannelId() != series.getChannelId())) {
+ List<ScheduledRecording> schedules =
+ mDataManager.getScheduledRecordings(series.getId());
+ List<ScheduledRecording> schedulesToRemove = new ArrayList<>();
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.isNotStarted()) {
+ schedulesToRemove.add(schedule);
+ }
+ }
+ mDataManager.removeScheduledRecording(true,
+ ScheduledRecording.toArray(schedulesToRemove));
+ }
+ }
+ mDataManager.updateSeriesRecording(series);
+ if (previousSeries == null
+ || previousSeries.getPriority() != series.getPriority()) {
+ long priority = series.getPriority();
+ List<ScheduledRecording> schedulesToUpdate = new ArrayList<>();
+ for (ScheduledRecording schedule
+ : mDataManager.getScheduledRecordings(series.getId())) {
+ if (schedule.isNotStarted()) {
+ schedulesToUpdate.add(ScheduledRecording.buildFrom(schedule)
+ .setPriority(priority).build());
+ }
+ }
+ if (!schedulesToUpdate.isEmpty()) {
+ mDataManager.updateScheduledRecording(
+ ScheduledRecording.toArray(schedulesToUpdate));
+ }
+ }
+ scheduler.resumeUpdate();
+ }
+ }
+
+ /**
+ * Removes the series recording and all the corresponding schedules which are not started yet.
+ */
+ public void removeSeriesRecording(long seriesRecordingId) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
+ SeriesRecording series = mDataManager.getSeriesRecording(seriesRecordingId);
+ if (series == null) {
+ return;
+ }
+ for (ScheduledRecording schedule : mDataManager.getAllScheduledRecordings()) {
+ if (schedule.getSeriesRecordingId() == seriesRecordingId) {
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ stopRecording(schedule);
+ break;
+ }
+ }
+ }
+ mDataManager.removeSeriesRecording(series);
+ }
+
+ /**
+ * Returns true, if the series recording can be removed. If a series recording is NORMAL state
+ * or has recordings or schedules, it cannot be removed.
+ */
+ public boolean canRemoveSeriesRecording(long seriesRecordingId) {
+ SeriesRecording seriesRecording = mDataManager.getSeriesRecording(seriesRecordingId);
+ if (seriesRecording == null) {
+ return false;
+ }
+ if (!seriesRecording.isStopped()) {
+ return false;
+ }
+ for (ScheduledRecording r : mDataManager.getAvailableScheduledRecordings()) {
+ if (r.getSeriesRecordingId() == seriesRecordingId) {
+ return false;
+ }
+ }
+ String seriesId = seriesRecording.getSeriesId();
+ SoftPreconditions.checkNotNull(seriesId);
+ for (RecordedProgram r : mDataManager.getRecordedPrograms()) {
+ if (seriesId.equals(r.getSeriesId())) {
+ return false;
+ }
+ }
+ return true;
}
/**
* Stops the currently recorded program
*/
public void stopRecording(final ScheduledRecording recording) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
synchronized (mListener) {
for (final Entry<Listener, Handler> entry : mListener.entrySet()) {
entry.getValue().post(new Runnable() {
@@ -124,86 +446,297 @@ public class DvrManager {
}
/**
- * Removes a scheduled recording or an existing recording.
+ * Removes scheduled recordings or an existing recordings.
+ */
+ public void removeScheduledRecording(ScheduledRecording... schedules) {
+ Log.i(TAG, "Removing " + Arrays.asList(schedules));
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
+ for (ScheduledRecording r : schedules) {
+ if (r.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ stopRecording(r);
+ } else {
+ mDataManager.removeScheduledRecording(r);
+ }
+ }
+ }
+
+ /**
+ * Removes scheduled recordings without changing to the DELETED state.
+ */
+ public void forceRemoveScheduledRecording(ScheduledRecording... schedules) {
+ Log.i(TAG, "Force removing " + Arrays.asList(schedules));
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return;
+ }
+ for (ScheduledRecording r : schedules) {
+ if (r.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ stopRecording(r);
+ } else {
+ mDataManager.removeScheduledRecording(true, r);
+ }
+ }
+ }
+
+ /**
+ * Removes the recorded program. It deletes the file if possible.
*/
- public void removeScheduledRecording(ScheduledRecording scheduledRecording) {
- Log.i(TAG, "Removing " + scheduledRecording);
- mDataManager.removeScheduledRecording(scheduledRecording);
+ public void removeRecordedProgram(Uri recordedProgramUri) {
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
+ return;
+ }
+ removeRecordedProgram(ContentUris.parseId(recordedProgramUri));
}
+ /**
+ * Removes the recorded program. It deletes the file if possible.
+ */
+ public void removeRecordedProgram(long recordedProgramId) {
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
+ return;
+ }
+ RecordedProgram recordedProgram = mDataManager.getRecordedProgram(recordedProgramId);
+ if (recordedProgram != null) {
+ removeRecordedProgram(recordedProgram);
+ }
+ }
+
+ /**
+ * Removes the recorded program. It deletes the file if possible.
+ */
public void removeRecordedProgram(final RecordedProgram recordedProgram) {
- // TODO(dvr): implement
- Log.i(TAG, "To delete " + recordedProgram
- + "\nyou should manually delete video data at"
- + "\nadb shell rm -rf " + recordedProgram.getDataUri()
- );
- Toast.makeText(mAppContext, "Deleting recorded programs is not fully implemented yet",
- Toast.LENGTH_SHORT).show();
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized())) {
+ return;
+ }
+ new AsyncDbTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ ContentResolver resolver = mAppContext.getContentResolver();
+ int deletedCounts = resolver.delete(recordedProgram.getUri(), null, null);
+ if (deletedCounts > 0) {
+ // TODO: executeOnExecutor should be called on the main thread.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ removeRecordedData(recordedProgram.getDataUri());
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ return null;
+ }
+ }.executeOnDbThread();
+ }
+
+ public void removeRecordedPrograms(List<Long> recordedProgramIds) {
+ final ArrayList<ContentProviderOperation> dbOperations = new ArrayList<>();
+ final List<Uri> dataUris = new ArrayList<>();
+ for (Long rId : recordedProgramIds) {
+ RecordedProgram r = mDataManager.getRecordedProgram(rId);
+ if (r != null) {
+ dataUris.add(r.getDataUri());
+ dbOperations.add(ContentProviderOperation.newDelete(r.getUri()).build());
+ }
+ }
new AsyncDbTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
ContentResolver resolver = mAppContext.getContentResolver();
- resolver.delete(recordedProgram.getUri(), null, null);
+ try {
+ resolver.applyBatch(TvContract.AUTHORITY, dbOperations);
+ // TODO: executeOnExecutor should be called on the main thread.
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ for (Uri dataUri : dataUris) {
+ removeRecordedData(dataUri);
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ } catch (RemoteException | OperationApplicationException e) {
+ Log.w(TAG, "Remove reocrded programs from DB failed.", e);
+ }
return null;
}
- }.execute();
+ }.executeOnDbThread();
}
/**
- * Returns priority ordered list of all scheduled recording that will not be recorded if
+ * Updates the scheduled recording.
+ */
+ public void updateScheduledRecording(ScheduledRecording recording) {
+ if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ mDataManager.updateScheduledRecording(recording);
+ }
+ }
+
+ /**
+ * Returns priority ordered list of all scheduled recordings that will not be recorded if
* this program is.
*
- * <p>Any empty list means there is no conflicts. If there is conflict the program must be
- * scheduled to record with a Priority lower than the first Recording in the list returned.
- */
- public List<ScheduledRecording> getScheduledRecordingsThatConflict(Program program) {
- //TODO(DVR): move to scheduler.
- //TODO(DVR): deal with more than one DvrInputService
- List<ScheduledRecording> overLap = mDataManager.getRecordingsThatOverlapWith(getPeriod(program));
- if (!overLap.isEmpty()) {
- // TODO(DVR): ignore shows that already won't record.
- Channel channel = mChannelDataManager.getChannel(program.getChannelId());
- if (channel != null) {
- TvInputInfo info = mDvrSessionManager.getTvInputInfo(channel.getInputId());
- if (info == null) {
- Log.w(TAG,
- "Could not find a recording TvInputInfo for " + channel.getInputId());
- return overLap;
- }
- int remove = Math.max(0, info.getTunerCount() - 1);
- if (remove >= overLap.size()) {
- return Collections.EMPTY_LIST;
- }
- overLap = overLap.subList(remove, overLap.size() - 1);
+ * @see DvrScheduleManager#getConflictingSchedules(Program)
+ */
+ public List<ScheduledRecording> getConflictingSchedules(Program program) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return Collections.emptyList();
+ }
+ return mScheduleManager.getConflictingSchedules(program);
+ }
+
+ /**
+ * Returns priority ordered list of all scheduled recordings that will not be recorded if
+ * this channel is.
+ *
+ * @see DvrScheduleManager#getConflictingSchedules(long, long, long)
+ */
+ public List<ScheduledRecording> getConflictingSchedules(long channelId, long startTimeMs,
+ long endTimeMs) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return Collections.emptyList();
+ }
+ return mScheduleManager.getConflictingSchedules(channelId, startTimeMs, endTimeMs);
+ }
+
+ /**
+ * Checks if the schedule is conflicting.
+ *
+ * <p>Note that the {@code schedule} should be the existing one. If not, this returns
+ * {@code false}.
+ */
+ public boolean isConflicting(ScheduledRecording schedule) {
+ return schedule != null
+ && SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())
+ && mScheduleManager.isConflicting(schedule);
+ }
+
+ /**
+ * Returns priority ordered list of all scheduled recording that will not be recorded if
+ * this channel is tuned to.
+ *
+ * @see DvrScheduleManager#getConflictingSchedulesForTune
+ */
+ public List<ScheduledRecording> getConflictingSchedulesForTune(long channelId) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return Collections.emptyList();
+ }
+ return mScheduleManager.getConflictingSchedulesForTune(channelId);
+ }
+
+ /**
+ * Sets the highest priority to the schedule.
+ */
+ public void setHighestPriority(ScheduledRecording schedule) {
+ if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ long newPriority = mScheduleManager.suggestHighestPriority(schedule);
+ if (newPriority != schedule.getPriority()) {
+ mDataManager.updateScheduledRecording(ScheduledRecording.buildFrom(schedule)
+ .setPriority(newPriority).build());
}
}
- return overLap;
}
- @NonNull
- private static Range getPeriod(Program program) {
- return new Range(program.getStartTimeUtcMillis(), program.getEndTimeUtcMillis());
+ /**
+ * Suggests the higher priority than the schedules which overlap with {@code schedule}.
+ */
+ public long suggestHighestPriority(ScheduledRecording schedule) {
+ if (SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return mScheduleManager.suggestHighestPriority(schedule);
+ }
+ return DvrScheduleManager.DEFAULT_PRIORITY;
}
/**
- * Checks whether {@code channel} can be tuned without any conflict with existing recordings
- * in progress. If there is any conflict, {@code outConflictRecordings} will be filled.
+ * Returns {@code true} if the channel can be recorded.
+ * <p>
+ * Note that this method doesn't check the conflict of the schedule or available tuners.
+ * This can be called from the UI before the schedules are loaded.
*/
- public boolean canTuneTo(Channel channel, List<ScheduledRecording> outConflictScheduledRecordings) {
- // TODO: implement
- return true;
+ public boolean isChannelRecordable(Channel channel) {
+ if (!mDataManager.isDvrScheduleLoadFinished() || channel == null) {
+ return false;
+ }
+ TvInputInfo info = Utils.getTvInputInfoForChannelId(mAppContext, channel.getId());
+ if (info == null) {
+ Log.w(TAG, "Could not find TvInputInfo for " + channel);
+ return false;
+ }
+ if (!info.canRecord()) {
+ return false;
+ }
+ Program program = TvApplication.getSingletons(mAppContext).getProgramDataManager()
+ .getCurrentProgram(channel.getId());
+ return program == null || !program.isRecordingProhibited();
+ }
+
+ /**
+ * Returns {@code true} if the program can be recorded.
+ * <p>
+ * Note that this method doesn't check the conflict of the schedule or available tuners.
+ * This can be called from the UI before the schedules are loaded.
+ */
+ public boolean isProgramRecordable(Program program) {
+ if (!mDataManager.isInitialized()) {
+ return false;
+ }
+ TvInputInfo info = Utils.getTvInputInfoForProgram(mAppContext, program);
+ if (info == null) {
+ Log.w(TAG, "Could not find TvInputInfo for " + program);
+ return false;
+ }
+ return info.canRecord() && !program.isRecordingProhibited();
+ }
+
+ /**
+ * Returns the current recording for the channel.
+ * <p>
+ * This can be called from the UI before the schedules are loaded.
+ */
+ public ScheduledRecording getCurrentRecording(long channelId) {
+ if (!mDataManager.isDvrScheduleLoadFinished()) {
+ return null;
+ }
+ for (ScheduledRecording recording : mDataManager.getStartedRecordings()) {
+ if (recording.getChannelId() == channelId) {
+ return recording;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns schedules which is available (i.e., isNotStarted or isInProgress) and belongs to
+ * the series recording {@code seriesRecordingId}.
+ */
+ public List<ScheduledRecording> getAvailableScheduledRecording(long seriesRecordingId) {
+ if (!mDataManager.isDvrScheduleLoadFinished()) {
+ return Collections.emptyList();
+ }
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ for (ScheduledRecording schedule : mDataManager.getScheduledRecordings(seriesRecordingId)) {
+ if (schedule.isInProgress() || schedule.isNotStarted()) {
+ schedules.add(schedule);
+ }
+ }
+ return schedules;
}
/**
- * Returns true is the inputId supports recording.
+ * Returns the series recording related to the program.
*/
- public boolean canRecord(String inputId) {
- TvInputInfo info = mDvrSessionManager.getTvInputInfo(inputId);
- return info != null && info.getTunerCount() > 0;
+ @Nullable
+ public SeriesRecording getSeriesRecording(Program program) {
+ if (!SoftPreconditions.checkState(mDataManager.isDvrScheduleLoadFinished())) {
+ return null;
+ }
+ return mDataManager.getSeriesRecording(program.getSeriesId());
}
@WorkerThread
- void addListener(Listener listener, @NonNull Handler handler) {
+ @VisibleForTesting
+ // Should be public to use mock DvrManager object.
+ public void addListener(Listener listener, @NonNull Handler handler) {
SoftPreconditions.checkNotNull(handler);
synchronized (mListener) {
mListener.put(listener, handler);
@@ -211,13 +744,102 @@ public class DvrManager {
}
@WorkerThread
- void removeListener(Listener listener) {
+ @VisibleForTesting
+ // Should be public to use mock DvrManager object.
+ public void removeListener(Listener listener) {
synchronized (mListener) {
mListener.remove(listener);
}
}
/**
+ * Returns ScheduledRecording.builder based on {@code program}. If program is already started,
+ * recording started time is clipped to the current time.
+ */
+ private ScheduledRecording.Builder createScheduledRecordingBuilder(String inputId,
+ Program program) {
+ ScheduledRecording.Builder builder = ScheduledRecording.builder(inputId, program);
+ long time = System.currentTimeMillis();
+ if (program.getStartTimeUtcMillis() < time && time < program.getEndTimeUtcMillis()) {
+ builder.setStartTimeMs(time);
+ }
+ return builder;
+ }
+
+ /**
+ * Returns a schedule which matches to the given episode.
+ */
+ public ScheduledRecording getScheduledRecording(String title, String seasonNumber,
+ String episodeNumber) {
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized()) || title == null
+ || seasonNumber == null || episodeNumber == null) {
+ return null;
+ }
+ for (ScheduledRecording r : mDataManager.getAllScheduledRecordings()) {
+ if (title.equals(r.getProgramTitle())
+ && seasonNumber.equals(r.getSeasonNumber())
+ && episodeNumber.equals(r.getEpisodeNumber())) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns a recorded program which is the same episode as the given {@code program}.
+ */
+ public RecordedProgram getRecordedProgram(String title, String seasonNumber,
+ String episodeNumber) {
+ if (!SoftPreconditions.checkState(mDataManager.isInitialized()) || title == null
+ || seasonNumber == null || episodeNumber == null) {
+ return null;
+ }
+ for (RecordedProgram r : mDataManager.getRecordedPrograms()) {
+ if (title.equals(r.getTitle())
+ && seasonNumber.equals(r.getSeasonNumber())
+ && episodeNumber.equals(r.getEpisodeNumber())
+ && !r.isClipped()) {
+ return r;
+ }
+ }
+ return null;
+ }
+
+ @WorkerThread
+ private void removeRecordedData(Uri dataUri) {
+ try {
+ if (dataUri != null && ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())
+ && dataUri.getPath() != null) {
+ File recordedProgramPath = new File(dataUri.getPath());
+ if (!recordedProgramPath.exists()) {
+ if (DEBUG) Log.d(TAG, "File to delete not exist: " + recordedProgramPath);
+ } else {
+ Utils.deleteDirOrFile(recordedProgramPath);
+ if (DEBUG) {
+ Log.d(TAG, "Sucessfully deleted files of the recorded program: " + dataUri);
+ }
+ }
+ }
+ } catch (SecurityException e) {
+ if (DEBUG) {
+ Log.d(TAG, "To delete this recorded program, please manually delete video data at"
+ + "\nadb shell rm -rf " + dataUri);
+ }
+ }
+ }
+
+ /**
+ * Remove all the records related to the input.
+ * <p>
+ * Note that this should be called after the input was removed.
+ */
+ public void forgetStorage(String inputId) {
+ if (mDataManager.isInitialized()) {
+ mDataManager.forgetStorage(inputId);
+ }
+ }
+
+ /**
* Listener internally used inside dvr package.
*/
interface Listener {
diff --git a/src/com/android/tv/dvr/DvrPlayActivity.java b/src/com/android/tv/dvr/DvrPlayActivity.java
deleted file mode 100644
index b117a7cf..00000000
--- a/src/com/android/tv/dvr/DvrPlayActivity.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.tv.dvr;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.widget.TextView;
-
-import com.android.tv.R;
-import com.android.tv.TvApplication;
-
-/**
- * Simple Activity to play a {@link ScheduledRecording}.
- */
-public class DvrPlayActivity extends Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.dvr_play);
-
- DvrDataManager dvrDataManager = TvApplication.getSingletons(this).getDvrDataManager();
- // TODO(DVR) handle errors.
- long recordingId = getIntent().getLongExtra(ScheduledRecording.RECORDING_ID_EXTRA, 0);
- ScheduledRecording scheduledRecording = dvrDataManager.getScheduledRecording(recordingId);
- TextView textView = (TextView) findViewById(R.id.placeHolderText);
- if (scheduledRecording != null) {
- textView.setText(scheduledRecording.toString());
- } else {
- textView.setText(R.string.ut_result_not_found_title); // TODO(DVR) update error text
- }
- }
-} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/DvrPlaybackActivity.java b/src/com/android/tv/dvr/DvrPlaybackActivity.java
new file mode 100644
index 00000000..5deda44a
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrPlaybackActivity.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.ui.DvrPlaybackOverlayFragment;
+
+/**
+ * Activity to play a {@link RecordedProgram}.
+ */
+public class DvrPlaybackActivity extends Activity {
+ private static final String TAG = "DvrPlaybackActivity";
+ private static final boolean DEBUG = false;
+
+ private DvrPlaybackOverlayFragment mOverlayFragment;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, true);
+ if (DEBUG) Log.d(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dvr_playback);
+ mOverlayFragment = (DvrPlaybackOverlayFragment) getFragmentManager()
+ .findFragmentById(R.id.dvr_playback_controls_fragment);
+ }
+
+ @Override
+ public void onVisibleBehindCanceled() {
+ if (DEBUG) Log.d(TAG, "onVisibleBehindCanceled");
+ super.onVisibleBehindCanceled();
+ finish();
+ }
+
+ @Override
+ protected void onNewIntent(Intent intent) {
+ mOverlayFragment.onNewIntent(intent);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ float density = getResources().getDisplayMetrics().density;
+ mOverlayFragment.onWindowSizeChanged((int) (newConfig.screenWidthDp * density),
+ (int) (newConfig.screenHeightDp * density));
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/DvrPlaybackMediaSessionHelper.java b/src/com/android/tv/dvr/DvrPlaybackMediaSessionHelper.java
new file mode 100644
index 00000000..9759a856
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrPlaybackMediaSessionHelper.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaSession;
+import android.media.session.PlaybackState;
+import android.media.tv.TvContract;
+import android.os.AsyncTask;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.ui.DvrPlaybackOverlayFragment;
+import com.android.tv.util.ImageLoader;
+import com.android.tv.util.TimeShiftUtils;
+import com.android.tv.util.Utils;
+
+public class DvrPlaybackMediaSessionHelper {
+ private static final String TAG = "DvrPlaybackMediaSessionHelper";
+ private static final boolean DEBUG = false;
+
+ private int mNowPlayingCardWidth;
+ private int mNowPlayingCardHeight;
+ private int mSpeedLevel;
+ private long mProgramDurationMs;
+
+ private Activity mActivity;
+ private DvrPlayer mDvrPlayer;
+ private MediaSession mMediaSession;
+ private final DvrWatchedPositionManager mDvrWatchedPositionManager;
+ private final ChannelDataManager mChannelDataManager;
+
+ public DvrPlaybackMediaSessionHelper(Activity activity, String mediaSessionTag,
+ DvrPlayer dvrPlayer, DvrPlaybackOverlayFragment overlayFragment) {
+ mActivity = activity;
+ mDvrPlayer = dvrPlayer;
+ mDvrWatchedPositionManager =
+ TvApplication.getSingletons(activity).getDvrWatchedPositionManager();
+ mChannelDataManager = TvApplication.getSingletons(activity).getChannelDataManager();
+ mDvrPlayer.setCallback(new DvrPlayer.DvrPlayerCallback() {
+ @Override
+ public void onPlaybackStateChanged(int playbackState, int playbackSpeed) {
+ updateMediaSessionPlaybackState();
+ }
+
+ @Override
+ public void onPlaybackPositionChanged(long positionMs) {
+ updateMediaSessionPlaybackState();
+ if (mDvrPlayer.isPlaybackPrepared()) {
+ mDvrWatchedPositionManager
+ .setWatchedPosition(mDvrPlayer.getProgram().getId(), positionMs);
+ }
+ }
+
+ @Override
+ public void onPlaybackEnded() {
+ // TODO: Deal with watched over recordings in DVR library
+ RecordedProgram nextEpisode =
+ overlayFragment.getNextEpisode(mDvrPlayer.getProgram());
+ if (nextEpisode == null) {
+ mDvrPlayer.reset();
+ mActivity.finish();
+ } else {
+ Intent intent = new Intent(activity, DvrPlaybackActivity.class);
+ intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, nextEpisode.getId());
+ mActivity.startActivity(intent);
+ }
+ }
+ });
+ initializeMediaSession(mediaSessionTag);
+ }
+
+ /**
+ * Stops DVR player and release media session.
+ */
+ public void release() {
+ if (mDvrPlayer != null) {
+ mDvrPlayer.reset();
+ }
+ if (mMediaSession != null) {
+ mMediaSession.release();
+ }
+ }
+
+ /**
+ * Updates media session's playback state and speed.
+ */
+ public void updateMediaSessionPlaybackState() {
+ mMediaSession.setPlaybackState(new PlaybackState.Builder()
+ .setState(mDvrPlayer.getPlaybackState(), mDvrPlayer.getPlaybackPosition(),
+ mSpeedLevel).build());
+ }
+
+ /**
+ * Sets the recorded program for playback.
+ *
+ * @param program The recorded program to play. {@code null} to reset the DVR player.
+ */
+ public void setupPlayback(RecordedProgram program, long seekPositionMs) {
+ if (program != null) {
+ mDvrPlayer.setProgram(program, seekPositionMs);
+ setupMediaSession(program);
+ } else {
+ mDvrPlayer.reset();
+ mMediaSession.setActive(false);
+ }
+ }
+
+ /**
+ * Returns the recorded program now playing.
+ */
+ public RecordedProgram getProgram() {
+ return mDvrPlayer.getProgram();
+ }
+
+ /**
+ * Checks if the recorded program is the same as now playing one.
+ */
+ public boolean isCurrentProgram(RecordedProgram program) {
+ return program != null && program.equals(getProgram());
+ }
+
+ /**
+ * Returns playback state.
+ */
+ public int getPlaybackState() {
+ return mDvrPlayer.getPlaybackState();
+ }
+
+ /**
+ * Returns the underlying DVR player.
+ */
+ public DvrPlayer getDvrPlayer() {
+ return mDvrPlayer;
+ }
+
+ private void initializeMediaSession(String mediaSessionTag) {
+ mMediaSession = new MediaSession(mActivity, mediaSessionTag);
+ mMediaSession.setFlags(MediaSession.FLAG_HANDLES_MEDIA_BUTTONS
+ | MediaSession.FLAG_HANDLES_TRANSPORT_CONTROLS);
+ mNowPlayingCardWidth = mActivity.getResources()
+ .getDimensionPixelSize(R.dimen.notif_card_img_max_width);
+ mNowPlayingCardHeight = mActivity.getResources()
+ .getDimensionPixelSize(R.dimen.notif_card_img_height);
+ mMediaSession.setCallback(new MediaSessionCallback());
+ mActivity.setMediaController(
+ new MediaController(mActivity, mMediaSession.getSessionToken()));
+ updateMediaSessionPlaybackState();
+ }
+
+ private void setupMediaSession(RecordedProgram program) {
+ mProgramDurationMs = program.getDurationMillis();
+ String cardTitleText = program.getTitle();
+ if (TextUtils.isEmpty(cardTitleText)) {
+ Channel channel = mChannelDataManager.getChannel(program.getChannelId());
+ cardTitleText = (channel != null) ? channel.getDisplayName()
+ : mActivity.getString(R.string.no_program_information);
+ }
+ updateMediaMetadata(program.getId(), cardTitleText, program.getDescription(),
+ mProgramDurationMs, null, 0);
+ String posterArtUri = program.getPosterArtUri();
+ if (posterArtUri == null) {
+ posterArtUri = TvContract.buildChannelLogoUri(program.getChannelId()).toString();
+ }
+ updatePosterArt(program, cardTitleText, program.getDescription(),
+ mProgramDurationMs, null, posterArtUri);
+ mMediaSession.setActive(true);
+ }
+
+ private void updatePosterArt(RecordedProgram program, String cardTitleText,
+ String cardSubtitleText, long duration,
+ @Nullable Bitmap posterArt, @Nullable String posterArtUri) {
+ if (posterArt != null) {
+ updateMediaMetadata(program.getId(), cardTitleText,
+ cardSubtitleText, duration, posterArt, 0);
+ } else if (posterArtUri != null) {
+ ImageLoader.loadBitmap(mActivity, posterArtUri, mNowPlayingCardWidth,
+ mNowPlayingCardHeight, new ProgramPosterArtCallback(
+ mActivity, program, cardTitleText, cardSubtitleText, duration));
+ } else {
+ updateMediaMetadata(program.getId(), cardTitleText,
+ cardSubtitleText, duration, null, R.drawable.default_now_card);
+ }
+ }
+
+ private class ProgramPosterArtCallback extends
+ ImageLoader.ImageLoaderCallback<Activity> {
+ private RecordedProgram mRecordedProgram;
+ private String mCardTitleText;
+ private String mCardSubtitleText;
+ private long mDuration;
+
+ public ProgramPosterArtCallback(Activity activity, RecordedProgram program,
+ String cardTitleText, String cardSubtitleText, long duration) {
+ super(activity);
+ mRecordedProgram = program;
+ mCardTitleText = cardTitleText;
+ mCardSubtitleText = cardSubtitleText;
+ mDuration = duration;
+ }
+
+ @Override
+ public void onBitmapLoaded(Activity activity, @Nullable Bitmap posterArt) {
+ if (isCurrentProgram(mRecordedProgram)) {
+ updatePosterArt(mRecordedProgram, mCardTitleText,
+ mCardSubtitleText, mDuration, posterArt, null);
+ }
+ }
+ }
+
+ private void updateMediaMetadata(final long programId, final String title,
+ final String subtitle, final long duration,
+ final Bitmap posterArt, final int imageResId) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ builder.putLong(MediaMetadata.METADATA_KEY_MEDIA_ID, programId)
+ .putString(MediaMetadata.METADATA_KEY_TITLE, title)
+ .putLong(MediaMetadata.METADATA_KEY_DURATION, duration);
+ if (subtitle != null) {
+ builder.putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, subtitle);
+ }
+ Bitmap programPosterArt = posterArt;
+ if (programPosterArt == null && imageResId != 0) {
+ programPosterArt =
+ BitmapFactory.decodeResource(mActivity.getResources(), imageResId);
+ }
+ if (programPosterArt != null) {
+ builder.putBitmap(MediaMetadata.METADATA_KEY_ART, programPosterArt);
+ }
+ mMediaSession.setMetadata(builder.build());
+ return null;
+ }
+ }.execute();
+ }
+
+ // An event was triggered by MediaController.TransportControls and must be handled here.
+ // Here we update the media itself to act on the event that was triggered.
+ private class MediaSessionCallback extends MediaSession.Callback {
+ @Override
+ public void onPrepare() {
+ if (!mDvrPlayer.isPlaybackPrepared()) {
+ mDvrPlayer.prepare(true);
+ }
+ }
+
+ @Override
+ public void onPlay() {
+ if (mDvrPlayer.isPlaybackPrepared()) {
+ mDvrPlayer.play();
+ }
+ }
+
+ @Override
+ public void onPause() {
+ if (mDvrPlayer.isPlaybackPrepared()) {
+ mDvrPlayer.pause();
+ }
+ }
+
+ @Override
+ public void onFastForward() {
+ if (!mDvrPlayer.isPlaybackPrepared()) {
+ return;
+ }
+ if (mDvrPlayer.getPlaybackState() == PlaybackState.STATE_FAST_FORWARDING) {
+ if (mSpeedLevel < TimeShiftUtils.MAX_SPEED_LEVEL) {
+ mSpeedLevel++;
+ } else {
+ return;
+ }
+ } else {
+ mSpeedLevel = 0;
+ }
+ mDvrPlayer.fastForward(
+ TimeShiftUtils.getPlaybackSpeed(mSpeedLevel, mProgramDurationMs));
+ }
+
+ @Override
+ public void onRewind() {
+ if (!mDvrPlayer.isPlaybackPrepared()) {
+ return;
+ }
+ if (mDvrPlayer.getPlaybackState() == PlaybackState.STATE_REWINDING) {
+ if (mSpeedLevel < TimeShiftUtils.MAX_SPEED_LEVEL) {
+ mSpeedLevel++;
+ } else {
+ return;
+ }
+ } else {
+ mSpeedLevel = 0;
+ }
+ mDvrPlayer.rewind(TimeShiftUtils.getPlaybackSpeed(mSpeedLevel, mProgramDurationMs));
+ }
+
+ @Override
+ public void onSeekTo(long positionMs) {
+ if (mDvrPlayer.isPlaybackPrepared()) {
+ mDvrPlayer.seekTo(positionMs);
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/DvrPlayer.java b/src/com/android/tv/dvr/DvrPlayer.java
new file mode 100644
index 00000000..5656655c
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrPlayer.java
@@ -0,0 +1,425 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.media.PlaybackParams;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvInputManager;
+import android.media.tv.TvTrackInfo;
+import android.media.tv.TvView;
+import android.media.session.PlaybackState;
+import android.util.Log;
+
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class DvrPlayer {
+ private static final String TAG = "DvrPlayer";
+ private static final boolean DEBUG = false;
+
+ /**
+ * The max rewinding speed supported by DVR player.
+ */
+ public static final int MAX_REWIND_SPEED = 256;
+ /**
+ * The max fast-forwarding speed supported by DVR player.
+ */
+ public static final int MAX_FAST_FORWARD_SPEED = 256;
+
+ private static final long SEEK_POSITION_MARGIN_MS = TimeUnit.SECONDS.toMillis(2);
+ private static final long REWIND_POSITION_MARGIN_MS = 32; // Workaround value. b/29994826
+
+ private RecordedProgram mProgram;
+ private long mInitialSeekPositionMs;
+ private final TvView mTvView;
+ private DvrPlayerCallback mCallback;
+ private AspectRatioChangedListener mAspectRatioChangedListener;
+ private ContentBlockedListener mContentBlockedListener;
+ private float mAspectRatio = Float.NaN;
+ private int mPlaybackState = PlaybackState.STATE_NONE;
+ private long mTimeShiftCurrentPositionMs;
+ private boolean mPauseOnPrepared;
+ private final PlaybackParams mPlaybackParams = new PlaybackParams();
+ private final DvrPlayerCallback mEmptyCallback = new DvrPlayerCallback();
+ private long mStartPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+ private boolean mTimeShiftPlayAvailable;
+
+ public static class DvrPlayerCallback {
+ /**
+ * Called when the playback position is changed. The normal updating frequency is
+ * around 1 sec., which is restricted to the implementation of
+ * {@link android.media.tv.TvInputService}.
+ */
+ public void onPlaybackPositionChanged(long positionMs) { }
+ /**
+ * Called when the playback state or the playback speed is changed.
+ */
+ public void onPlaybackStateChanged(int playbackState, int playbackSpeed) { }
+ /**
+ * Called when the playback toward the end.
+ */
+ public void onPlaybackEnded() { }
+ }
+
+ public interface AspectRatioChangedListener {
+ /**
+ * Called when the Video's aspect ratio is changed.
+ */
+ void onAspectRatioChanged(float videoAspectRatio);
+ }
+
+ public interface ContentBlockedListener {
+ /**
+ * Called when the Video's aspect ratio is changed.
+ */
+ void onContentBlocked(TvContentRating rating);
+ }
+
+ public DvrPlayer(TvView tvView) {
+ mTvView = tvView;
+ mPlaybackParams.setSpeed(1.0f);
+ setTvViewCallbacks();
+ setCallback(null);
+ }
+
+ /**
+ * Prepares playback.
+ *
+ * @param doPlay indicates DVR player do or do not start playback after media is prepared.
+ */
+ public void prepare(boolean doPlay) throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "prepare()");
+ if (mProgram == null) {
+ throw new IllegalStateException("Recorded program not set");
+ } else if (mPlaybackState != PlaybackState.STATE_NONE) {
+ throw new IllegalStateException("Playback is already prepared");
+ }
+ mTvView.timeShiftPlay(mProgram.getInputId(), mProgram.getUri());
+ mPlaybackState = PlaybackState.STATE_CONNECTING;
+ mPauseOnPrepared = !doPlay;
+ mCallback.onPlaybackStateChanged(mPlaybackState, 1);
+ }
+
+ /**
+ * Resumes playback.
+ */
+ public void play() throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "play()");
+ if (!isPlaybackPrepared()) {
+ throw new IllegalStateException("Recorded program not set or video not ready yet");
+ }
+ switch (mPlaybackState) {
+ case PlaybackState.STATE_FAST_FORWARDING:
+ case PlaybackState.STATE_REWINDING:
+ setPlaybackSpeed(1);
+ break;
+ default:
+ mTvView.timeShiftResume();
+ }
+ mPlaybackState = PlaybackState.STATE_PLAYING;
+ mCallback.onPlaybackStateChanged(mPlaybackState, 1);
+ }
+
+ /**
+ * Pauses playback.
+ */
+ public void pause() throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "pause()");
+ if (!isPlaybackPrepared()) {
+ throw new IllegalStateException("Recorded program not set or playback not started yet");
+ }
+ switch (mPlaybackState) {
+ case PlaybackState.STATE_FAST_FORWARDING:
+ case PlaybackState.STATE_REWINDING:
+ setPlaybackSpeed(1);
+ // falls through
+ case PlaybackState.STATE_PLAYING:
+ mTvView.timeShiftPause();
+ mPlaybackState = PlaybackState.STATE_PAUSED;
+ break;
+ default:
+ break;
+ }
+ mCallback.onPlaybackStateChanged(mPlaybackState, 1);
+ }
+
+ /**
+ * Fast-forwards playback with the given speed. If the given speed is larger than
+ * {@value #MAX_FAST_FORWARD_SPEED}, uses {@value #MAX_FAST_FORWARD_SPEED}.
+ */
+ public void fastForward(int speed) throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "fastForward()");
+ if (!isPlaybackPrepared()) {
+ throw new IllegalStateException("Recorded program not set or playback not started yet");
+ }
+ if (speed <= 0) {
+ throw new IllegalArgumentException("Speed cannot be negative or 0");
+ }
+ if (mTimeShiftCurrentPositionMs >= mProgram.getDurationMillis() - SEEK_POSITION_MARGIN_MS) {
+ return;
+ }
+ speed = Math.min(speed, MAX_FAST_FORWARD_SPEED);
+ if (DEBUG) Log.d(TAG, "Let's play with speed: " + speed);
+ setPlaybackSpeed(speed);
+ mPlaybackState = PlaybackState.STATE_FAST_FORWARDING;
+ mCallback.onPlaybackStateChanged(mPlaybackState, speed);
+ }
+
+ /**
+ * Rewinds playback with the given speed. If the given speed is larger than
+ * {@value #MAX_REWIND_SPEED}, uses {@value #MAX_REWIND_SPEED}.
+ */
+ public void rewind(int speed) throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "rewind()");
+ if (!isPlaybackPrepared()) {
+ throw new IllegalStateException("Recorded program not set or playback not started yet");
+ }
+ if (speed <= 0) {
+ throw new IllegalArgumentException("Speed cannot be negative or 0");
+ }
+ if (mTimeShiftCurrentPositionMs <= REWIND_POSITION_MARGIN_MS) {
+ return;
+ }
+ speed = Math.min(speed, MAX_REWIND_SPEED);
+ if (DEBUG) Log.d(TAG, "Let's play with speed: " + speed);
+ setPlaybackSpeed(-speed);
+ mPlaybackState = PlaybackState.STATE_REWINDING;
+ mCallback.onPlaybackStateChanged(mPlaybackState, speed);
+ }
+
+ /**
+ * Seeks playback to the specified position.
+ */
+ public void seekTo(long positionMs) throws IllegalStateException {
+ if (DEBUG) Log.d(TAG, "seekTo()");
+ if (!isPlaybackPrepared()) {
+ throw new IllegalStateException("Recorded program not set or playback not started yet");
+ }
+ if (mProgram == null || mPlaybackState == PlaybackState.STATE_NONE) {
+ return;
+ }
+ positionMs = getRealSeekPosition(positionMs, SEEK_POSITION_MARGIN_MS);
+ if (DEBUG) Log.d(TAG, "Now: " + getPlaybackPosition() + ", shift to: " + positionMs);
+ mTvView.timeShiftSeekTo(positionMs + mStartPositionMs);
+ if (mPlaybackState == PlaybackState.STATE_FAST_FORWARDING ||
+ mPlaybackState == PlaybackState.STATE_REWINDING) {
+ mPlaybackState = PlaybackState.STATE_PLAYING;
+ mTvView.timeShiftResume();
+ mCallback.onPlaybackStateChanged(mPlaybackState, 1);
+ }
+ }
+
+ /**
+ * Resets playback.
+ */
+ public void reset() {
+ if (DEBUG) Log.d(TAG, "reset()");
+ mCallback.onPlaybackStateChanged(PlaybackState.STATE_NONE, 1);
+ mPlaybackState = PlaybackState.STATE_NONE;
+ mTvView.reset();
+ mTimeShiftPlayAvailable = false;
+ mStartPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+ mTimeShiftCurrentPositionMs = 0;
+ mPlaybackParams.setSpeed(1.0f);
+ mProgram = null;
+ }
+
+ /**
+ * Sets callbacks for playback.
+ */
+ public void setCallback(DvrPlayerCallback callback) {
+ if (callback != null) {
+ mCallback = callback;
+ } else {
+ mCallback = mEmptyCallback;
+ }
+ }
+
+ /**
+ * Sets listener to aspect ratio changing.
+ */
+ public void setAspectRatioChangedListener(AspectRatioChangedListener listener) {
+ mAspectRatioChangedListener = listener;
+ }
+
+ /**
+ * Sets listener to content blocking.
+ */
+ public void setContentBlockedListener(ContentBlockedListener listener) {
+ mContentBlockedListener = listener;
+ }
+
+ /**
+ * Sets recorded programs for playback. If the player is playing another program, stops it.
+ */
+ public void setProgram(RecordedProgram program, long initialSeekPositionMs) {
+ if (mProgram != null && mProgram.equals(program)) {
+ return;
+ }
+ if (mPlaybackState != PlaybackState.STATE_NONE) {
+ reset();
+ }
+ mInitialSeekPositionMs = initialSeekPositionMs;
+ mProgram = program;
+ }
+
+ /**
+ * Returns the recorded program now playing.
+ */
+ public RecordedProgram getProgram() {
+ return mProgram;
+ }
+
+ /**
+ * Returns the currrent playback posistion in msecs.
+ */
+ public long getPlaybackPosition() {
+ return mTimeShiftCurrentPositionMs;
+ }
+
+ /**
+ * Returns the playback speed currently used.
+ */
+ public int getPlaybackSpeed() {
+ return (int) mPlaybackParams.getSpeed();
+ }
+
+ /**
+ * Returns the playback state defined in {@link android.media.session.PlaybackState}.
+ */
+ public int getPlaybackState() {
+ return mPlaybackState;
+ }
+
+ /**
+ * Returns if playback of the recorded program is started.
+ */
+ public boolean isPlaybackPrepared() {
+ return mPlaybackState != PlaybackState.STATE_NONE
+ && mPlaybackState != PlaybackState.STATE_CONNECTING;
+ }
+
+ private void setPlaybackSpeed(int speed) {
+ mPlaybackParams.setSpeed(speed);
+ mTvView.timeShiftSetPlaybackParams(mPlaybackParams);
+ }
+
+ private long getRealSeekPosition(long seekPositionMs, long endMarginMs) {
+ return Math.max(0, Math.min(seekPositionMs, mProgram.getDurationMillis() - endMarginMs));
+ }
+
+ private void setTvViewCallbacks() {
+ mTvView.setTimeShiftPositionCallback(new TvView.TimeShiftPositionCallback() {
+ @Override
+ public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
+ if (DEBUG) Log.d(TAG, "onTimeShiftStartPositionChanged:" + timeMs);
+ mStartPositionMs = timeMs;
+ if (mTimeShiftPlayAvailable) {
+ resumeToWatchedPositionIfNeeded();
+ }
+ }
+
+ @Override
+ public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
+ if (DEBUG) Log.d(TAG, "onTimeShiftCurrentPositionChanged: " + timeMs);
+ if (!mTimeShiftPlayAvailable) {
+ // Workaround of b/31436263
+ return;
+ }
+ // Workaround of b/32211561, TIF won't report start position when TIS report
+ // its start position as 0. In that case, we have to do the prework of playback
+ // on the first time we get current position, and the start position should be 0
+ // at that time.
+ if (mStartPositionMs == TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ mStartPositionMs = 0;
+ resumeToWatchedPositionIfNeeded();
+ }
+ timeMs -= mStartPositionMs;
+ if (mPlaybackState == PlaybackState.STATE_REWINDING
+ && timeMs <= REWIND_POSITION_MARGIN_MS) {
+ play();
+ } else {
+ mTimeShiftCurrentPositionMs = getRealSeekPosition(timeMs, 0);
+ mCallback.onPlaybackPositionChanged(mTimeShiftCurrentPositionMs);
+ if (timeMs >= mProgram.getDurationMillis()) {
+ pause();
+ mCallback.onPlaybackEnded();
+ }
+ }
+ }
+ });
+ mTvView.setCallback(new TvView.TvInputCallback() {
+ @Override
+ public void onTimeShiftStatusChanged(String inputId, int status) {
+ if (DEBUG) Log.d(TAG, "onTimeShiftStatusChanged:" + status);
+ if (status == TvInputManager.TIME_SHIFT_STATUS_AVAILABLE
+ && mPlaybackState == PlaybackState.STATE_CONNECTING) {
+ mTimeShiftPlayAvailable = true;
+ }
+ }
+
+ @Override
+ public void onTrackSelected(String inputId, int type, String trackId) {
+ if (trackId == null || type != TvTrackInfo.TYPE_VIDEO
+ || mAspectRatioChangedListener == null) {
+ return;
+ }
+ List<TvTrackInfo> trackInfos = mTvView.getTracks(TvTrackInfo.TYPE_VIDEO);
+ if (trackInfos != null) {
+ for (TvTrackInfo trackInfo : trackInfos) {
+ if (trackInfo.getId().equals(trackId)) {
+ float videoAspectRatio = trackInfo.getVideoPixelAspectRatio()
+ * trackInfo.getVideoWidth() / trackInfo.getVideoHeight();
+ if (DEBUG) Log.d(TAG, "Aspect Ratio: " + videoAspectRatio);
+ if (!Float.isNaN(videoAspectRatio)
+ && mAspectRatio != videoAspectRatio) {
+ mAspectRatioChangedListener
+ .onAspectRatioChanged(videoAspectRatio);
+ mAspectRatio = videoAspectRatio;
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onContentBlocked(String inputId, TvContentRating rating) {
+ if (mContentBlockedListener != null) {
+ mContentBlockedListener.onContentBlocked(rating);
+ }
+ }
+ });
+ }
+
+ private void resumeToWatchedPositionIfNeeded() {
+ if (mInitialSeekPositionMs != TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ mTvView.timeShiftSeekTo(getRealSeekPosition(mInitialSeekPositionMs,
+ SEEK_POSITION_MARGIN_MS) + mStartPositionMs);
+ mInitialSeekPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+ }
+ if (mPauseOnPrepared) {
+ mTvView.timeShiftPause();
+ mPlaybackState = PlaybackState.STATE_PAUSED;
+ mPauseOnPrepared = false;
+ } else {
+ mTvView.timeShiftResume();
+ mPlaybackState = PlaybackState.STATE_PLAYING;
+ }
+ mCallback.onPlaybackStateChanged(mPlaybackState, 1);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/DvrRecordingService.java b/src/com/android/tv/dvr/DvrRecordingService.java
index 2f3abccf..8c40aaa8 100644
--- a/src/com/android/tv/dvr/DvrRecordingService.java
+++ b/src/com/android/tv/dvr/DvrRecordingService.java
@@ -20,7 +20,6 @@ import android.app.AlarmManager;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.os.Binder;
import android.os.HandlerThread;
import android.os.IBinder;
import android.support.annotation.Nullable;
@@ -29,10 +28,10 @@ import android.util.Log;
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.util.Clock;
import com.android.tv.util.RecurringRunner;
-import com.android.tv.common.SoftPreconditions;
/**
* DVR Scheduler service.
@@ -60,31 +59,18 @@ public class DvrRecordingService extends Service {
private final Clock mClock = Clock.SYSTEM;
private RecurringRunner mReaperRunner;
- private WritableDvrDataManager mDataManager;
-
- /**
- * Class for clients to access. Because we know this service always
- * runs in the same process as its clients, we don't need to deal with
- * IPC.
- */
- public class SchedulerBinder extends Binder {
- Scheduler getScheduler() {
- return mScheduler;
- }
- }
-
- private final IBinder mBinder = new SchedulerBinder();
private Scheduler mScheduler;
private HandlerThread mHandlerThread;
@Override
public void onCreate() {
+ TvApplication.setCurrentRunningProcess(this, true);
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate();
SoftPreconditions.checkFeatureEnabled(this, CommonFeatures.DVR, TAG);
ApplicationSingletons singletons = TvApplication.getSingletons(this);
- mDataManager = (WritableDvrDataManager) singletons.getDvrDataManager();
+ WritableDvrDataManager dataManager = (WritableDvrDataManager) singletons.getDvrDataManager();
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// mScheduler may have been set for testing.
@@ -92,12 +78,13 @@ public class DvrRecordingService extends Service {
mHandlerThread = new HandlerThread(HANDLER_THREAD_NAME);
mHandlerThread.start();
mScheduler = new Scheduler(mHandlerThread.getLooper(), singletons.getDvrManager(),
- singletons.getDvrSessionManger(), mDataManager,
- singletons.getChannelDataManager(), this, mClock, alarmManager);
+ singletons.getInputSessionManager(), dataManager,
+ singletons.getChannelDataManager(), singletons.getTvInputManagerHelper(), this,
+ mClock, alarmManager);
+ mScheduler.start();
}
- mDataManager.addScheduledRecordingListener(mScheduler);
mReaperRunner = new RecurringRunner(this, java.util.concurrent.TimeUnit.DAYS.toMillis(1),
- new ScheduledProgramReaper(mDataManager, mClock), null);
+ new ScheduledProgramReaper(dataManager, mClock), null);
mReaperRunner.start();
}
@@ -112,10 +99,10 @@ public class DvrRecordingService extends Service {
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
mReaperRunner.stop();
- mDataManager.removeScheduledRecordingListener(mScheduler);
+ mScheduler.stop();
mScheduler = null;
if (mHandlerThread != null) {
- mHandlerThread.quit();
+ mHandlerThread.quitSafely();
mHandlerThread = null;
}
super.onDestroy();
@@ -124,7 +111,7 @@ public class DvrRecordingService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
- return mBinder;
+ return null;
}
@VisibleForTesting
diff --git a/src/com/android/tv/dvr/DvrScheduleManager.java b/src/com/android/tv/dvr/DvrScheduleManager.java
new file mode 100644
index 00000000..a5851a75
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrScheduleManager.java
@@ -0,0 +1,980 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.Context;
+import android.media.tv.TvInputInfo;
+import android.os.Build;
+import android.support.annotation.MainThread;
+import android.support.annotation.NonNull;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.LongSparseArray;
+import android.util.Range;
+
+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.data.Program;
+import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.util.CompositeComparator;
+import com.android.tv.util.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * A class to manage the schedules.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+@MainThread
+public class DvrScheduleManager {
+ private static final String TAG = "DvrScheduleManager";
+
+ /**
+ * The default priority of scheduled recording.
+ */
+ public static final long DEFAULT_PRIORITY = Long.MAX_VALUE >> 1;
+ /**
+ * The default priority of series recording.
+ */
+ public static final long DEFAULT_SERIES_PRIORITY = DEFAULT_PRIORITY >> 1;
+ // The new priority will have the offset from the existing one.
+ private static final long PRIORITY_OFFSET = 1024;
+
+ private static final Comparator<ScheduledRecording> RESULT_COMPARATOR =
+ new CompositeComparator<>(
+ ScheduledRecording.PRIORITY_COMPARATOR.reversed(),
+ ScheduledRecording.START_TIME_COMPARATOR,
+ ScheduledRecording.ID_COMPARATOR.reversed());
+
+ // The candidate comparator should be the consistent with
+ // InputTaskScheduler#CANDIDATE_COMPARATOR.
+ private static final Comparator<ScheduledRecording> CANDIDATE_COMPARATOR =
+ new CompositeComparator<>(
+ ScheduledRecording.PRIORITY_COMPARATOR,
+ ScheduledRecording.END_TIME_COMPARATOR,
+ ScheduledRecording.ID_COMPARATOR);
+
+ private final Context mContext;
+ private final DvrDataManagerImpl mDataManager;
+ private final ChannelDataManager mChannelDataManager;
+
+ private final Map<String, List<ScheduledRecording>> mInputScheduleMap = new HashMap<>();
+ // The inner map is a hash map from scheduled recording to its conflicting status, i.e.,
+ // the boolean value true denotes the schedule is just partially conflicting, which means
+ // although there's conflictit, it might still be recorded partially.
+ private final Map<String, Map<ScheduledRecording, Boolean>> mInputConflictInfoMap =
+ new HashMap<>();
+
+ private boolean mInitialized;
+
+ private final Set<OnInitializeListener> mOnInitializeListeners = new CopyOnWriteArraySet<>();
+ private final Set<ScheduledRecordingListener> mScheduledRecordingListeners = new ArraySet<>();
+ private final Set<OnConflictStateChangeListener> mOnConflictStateChangeListeners =
+ new ArraySet<>();
+
+ public DvrScheduleManager(Context context) {
+ mContext = context;
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mDataManager = (DvrDataManagerImpl) appSingletons.getDvrDataManager();
+ mChannelDataManager = appSingletons.getChannelDataManager();
+ if (mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished()) {
+ buildData();
+ } else {
+ mDataManager.addDvrScheduleLoadFinishedListener(
+ new OnDvrScheduleLoadFinishedListener() {
+ @Override
+ public void onDvrScheduleLoadFinished() {
+ mDataManager.removeDvrScheduleLoadFinishedListener(this);
+ if (mChannelDataManager.isDbLoadFinished() && !mInitialized) {
+ buildData();
+ }
+ }
+ });
+ }
+ ScheduledRecordingListener scheduledRecordingListener = new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ if (!mInitialized) {
+ return;
+ }
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ if (!schedule.isNotStarted() && !schedule.isInProgress()) {
+ continue;
+ }
+ TvInputInfo input = Utils
+ .getTvInputInfoForInputId(mContext, schedule.getInputId());
+ if (!SoftPreconditions.checkArgument(input != null, TAG,
+ "Input was removed for : " + schedule)) {
+ // Input removed.
+ mInputScheduleMap.remove(schedule.getInputId());
+ mInputConflictInfoMap.remove(schedule.getInputId());
+ continue;
+ }
+ String inputId = input.getId();
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules == null) {
+ schedules = new ArrayList<>();
+ mInputScheduleMap.put(inputId, schedules);
+ }
+ schedules.add(schedule);
+ }
+ onSchedulesChanged();
+ notifyScheduledRecordingAdded(scheduledRecordings);
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ if (!mInitialized) {
+ return;
+ }
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TvInputInfo input = Utils
+ .getTvInputInfoForInputId(mContext, schedule.getInputId());
+ if (input == null) {
+ // Input removed.
+ mInputScheduleMap.remove(schedule.getInputId());
+ mInputConflictInfoMap.remove(schedule.getInputId());
+ continue;
+ }
+ String inputId = input.getId();
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules != null) {
+ schedules.remove(schedule);
+ if (schedules.isEmpty()) {
+ mInputScheduleMap.remove(inputId);
+ }
+ }
+ Map<ScheduledRecording, Boolean> conflictInfo =
+ mInputConflictInfoMap.get(inputId);
+ if (conflictInfo != null) {
+ conflictInfo.remove(schedule);
+ if (conflictInfo.isEmpty()) {
+ mInputConflictInfoMap.remove(inputId);
+ }
+ }
+ }
+ onSchedulesChanged();
+ notifyScheduledRecordingRemoved(scheduledRecordings);
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(
+ ScheduledRecording... scheduledRecordings) {
+ if (!mInitialized) {
+ return;
+ }
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TvInputInfo input = Utils
+ .getTvInputInfoForInputId(mContext, schedule.getInputId());
+ if (!SoftPreconditions.checkArgument(input != null, TAG,
+ "Input was removed for : " + schedule)) {
+ // Input removed.
+ mInputScheduleMap.remove(schedule.getInputId());
+ mInputConflictInfoMap.remove(schedule.getInputId());
+ continue;
+ }
+ String inputId = input.getId();
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules == null) {
+ schedules = new ArrayList<>();
+ mInputScheduleMap.put(inputId, schedules);
+ }
+ // Compare ID because ScheduledRecording.equals() doesn't work if the state
+ // is changed.
+ for (Iterator<ScheduledRecording> i = schedules.iterator(); i.hasNext(); ) {
+ if (i.next().getId() == schedule.getId()) {
+ i.remove();
+ break;
+ }
+ }
+ if (schedule.isNotStarted() || schedule.isInProgress()) {
+ schedules.add(schedule);
+ }
+ if (schedules.isEmpty()) {
+ mInputScheduleMap.remove(inputId);
+ }
+ // Update conflict list as well
+ Map<ScheduledRecording, Boolean> conflictInfo =
+ mInputConflictInfoMap.get(inputId);
+ if (conflictInfo != null) {
+ // Compare ID because ScheduledRecording.equals() doesn't work if the state
+ // is changed.
+ ScheduledRecording oldSchedule = null;
+ for (ScheduledRecording s : conflictInfo.keySet()) {
+ if (s.getId() == schedule.getId()) {
+ oldSchedule = s;
+ break;
+ }
+ }
+ if (oldSchedule != null) {
+ conflictInfo.put(schedule, conflictInfo.get(oldSchedule));
+ conflictInfo.remove(oldSchedule);
+ }
+ }
+ }
+ onSchedulesChanged();
+ notifyScheduledRecordingStatusChanged(scheduledRecordings);
+ }
+ };
+ mDataManager.addScheduledRecordingListener(scheduledRecordingListener);
+ ChannelDataManager.Listener channelDataManagerListener = new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() {
+ if (mDataManager.isDvrScheduleLoadFinished() && !mInitialized) {
+ buildData();
+ }
+ }
+
+ @Override
+ public void onChannelListUpdated() {
+ if (mDataManager.isDvrScheduleLoadFinished()) {
+ buildData();
+ }
+ }
+
+ @Override
+ public void onChannelBrowsableChanged() {
+ }
+ };
+ mChannelDataManager.addListener(channelDataManagerListener);
+ }
+
+ /**
+ * Returns the started recordings for the given input.
+ */
+ private List<ScheduledRecording> getStartedRecordings(String inputId) {
+ if (!SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet")) {
+ return Collections.emptyList();
+ }
+ List<ScheduledRecording> result = new ArrayList<>();
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules != null) {
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ result.add(schedule);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void buildData() {
+ mInputScheduleMap.clear();
+ for (ScheduledRecording schedule : mDataManager.getAllScheduledRecordings()) {
+ if (!schedule.isNotStarted() && !schedule.isInProgress()) {
+ continue;
+ }
+ Channel channel = mChannelDataManager.getChannel(schedule.getChannelId());
+ if (channel != null) {
+ String inputId = channel.getInputId();
+ // Do not check whether the input is valid or not. The input might be temporarily
+ // invalid.
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules == null) {
+ schedules = new ArrayList<>();
+ mInputScheduleMap.put(inputId, schedules);
+ }
+ schedules.add(schedule);
+ }
+ }
+ if (!mInitialized) {
+ mInitialized = true;
+ notifyInitialize();
+ }
+ onSchedulesChanged();
+ }
+
+ private void onSchedulesChanged() {
+ // TODO: notify conflict state change when some conflicting recording becomes partially
+ // conflicting, vice versa.
+ List<ScheduledRecording> addedConflicts = new ArrayList<>();
+ List<ScheduledRecording> removedConflicts = new ArrayList<>();
+ for (String inputId : mInputScheduleMap.keySet()) {
+ Map<ScheduledRecording, Boolean> oldConflictsInfo = mInputConflictInfoMap.get(inputId);
+ Map<Long, ScheduledRecording> oldConflictMap = new HashMap<>();
+ if (oldConflictsInfo != null) {
+ for (ScheduledRecording r : oldConflictsInfo.keySet()) {
+ oldConflictMap.put(r.getId(), r);
+ }
+ }
+ Map<ScheduledRecording, Boolean> conflictInfo = getConflictingSchedulesInfo(inputId);
+ if (conflictInfo.isEmpty()) {
+ mInputConflictInfoMap.remove(inputId);
+ } else {
+ mInputConflictInfoMap.put(inputId, conflictInfo);
+ List<ScheduledRecording> conflicts = new ArrayList<>(conflictInfo.keySet());
+ for (ScheduledRecording r : conflicts) {
+ if (oldConflictMap.remove(r.getId()) == null) {
+ addedConflicts.add(r);
+ }
+ }
+ }
+ removedConflicts.addAll(oldConflictMap.values());
+ }
+ if (!removedConflicts.isEmpty()) {
+ notifyConflictStateChange(false, ScheduledRecording.toArray(removedConflicts));
+ }
+ if (!addedConflicts.isEmpty()) {
+ notifyConflictStateChange(true, ScheduledRecording.toArray(addedConflicts));
+ }
+ }
+
+ /**
+ * Returns {@code true} if this class has been initialized.
+ */
+ public boolean isInitialized() {
+ return mInitialized;
+ }
+
+ /**
+ * Adds a {@link ScheduledRecordingListener}.
+ */
+ public final void addScheduledRecordingListener(ScheduledRecordingListener listener) {
+ mScheduledRecordingListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link ScheduledRecordingListener}.
+ */
+ public final void removeScheduledRecordingListener(ScheduledRecordingListener listener) {
+ mScheduledRecordingListeners.remove(listener);
+ }
+
+ /**
+ * Calls {@link ScheduledRecordingListener#onScheduledRecordingAdded} for each listener.
+ */
+ private void notifyScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
+ l.onScheduledRecordingAdded(scheduledRecordings);
+ }
+ }
+
+ /**
+ * Calls {@link ScheduledRecordingListener#onScheduledRecordingRemoved} for each listener.
+ */
+ private void notifyScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
+ l.onScheduledRecordingRemoved(scheduledRecordings);
+ }
+ }
+
+ /**
+ * Calls {@link ScheduledRecordingListener#onScheduledRecordingStatusChanged} for each listener.
+ */
+ private void notifyScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecordingListener l : mScheduledRecordingListeners) {
+ l.onScheduledRecordingStatusChanged(scheduledRecordings);
+ }
+ }
+
+ /**
+ * Adds a {@link OnInitializeListener}.
+ */
+ public final void addOnInitializeListener(OnInitializeListener listener) {
+ mOnInitializeListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link OnInitializeListener}.
+ */
+ public final void removeOnInitializeListener(OnInitializeListener listener) {
+ mOnInitializeListeners.remove(listener);
+ }
+
+ /**
+ * Calls {@link OnInitializeListener#onInitialize} for each listener.
+ */
+ private void notifyInitialize() {
+ for (OnInitializeListener l : mOnInitializeListeners) {
+ l.onInitialize();
+ }
+ }
+
+ /**
+ * Adds a {@link OnConflictStateChangeListener}.
+ */
+ public final void addOnConflictStateChangeListener(OnConflictStateChangeListener listener) {
+ mOnConflictStateChangeListeners.add(listener);
+ }
+
+ /**
+ * Removes a {@link OnConflictStateChangeListener}.
+ */
+ public final void removeOnConflictStateChangeListener(OnConflictStateChangeListener listener) {
+ mOnConflictStateChangeListeners.remove(listener);
+ }
+
+ /**
+ * Calls {@link OnConflictStateChangeListener#onConflictStateChange} for each listener.
+ */
+ private void notifyConflictStateChange(boolean conflict,
+ ScheduledRecording... scheduledRecordings) {
+ for (OnConflictStateChangeListener l : mOnConflictStateChangeListeners) {
+ l.onConflictStateChange(conflict, scheduledRecordings);
+ }
+ }
+
+ /**
+ * Returns the priority for the program if it is recorded.
+ * <p>
+ * The recording will have the higher priority than the existing ones.
+ */
+ public long suggestNewPriority() {
+ if (!SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet")) {
+ return DEFAULT_PRIORITY;
+ }
+ return suggestHighestPriority();
+ }
+
+ private long suggestHighestPriority() {
+ long highestPriority = DEFAULT_PRIORITY - PRIORITY_OFFSET;
+ for (ScheduledRecording schedule : mDataManager.getAllScheduledRecordings()) {
+ if (schedule.getPriority() > highestPriority) {
+ highestPriority = schedule.getPriority();
+ }
+ }
+ return highestPriority + PRIORITY_OFFSET;
+ }
+
+ /**
+ * Suggests the higher priority than the schedules which overlap with {@code schedule}.
+ */
+ public long suggestHighestPriority(ScheduledRecording schedule) {
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(schedule.getInputId());
+ if (schedules == null) {
+ return DEFAULT_PRIORITY;
+ }
+ long highestPriority = Long.MIN_VALUE;
+ for (ScheduledRecording r : schedules) {
+ if (!r.equals(schedule) && r.isOverLapping(schedule)
+ && r.getPriority() > highestPriority) {
+ highestPriority = r.getPriority();
+ }
+ }
+ if (highestPriority == Long.MIN_VALUE || highestPriority < schedule.getPriority()) {
+ return schedule.getPriority();
+ }
+ return highestPriority + PRIORITY_OFFSET;
+ }
+
+ /**
+ * Suggests the higher priority than the schedules which overlap with {@code schedule}.
+ */
+ public long suggestHighestPriority(String inputId, Range<Long> peroid, long basePriority) {
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(inputId);
+ if (schedules == null) {
+ return DEFAULT_PRIORITY;
+ }
+ long highestPriority = Long.MIN_VALUE;
+ for (ScheduledRecording r : schedules) {
+ if (r.isOverLapping(peroid) && r.getPriority() > highestPriority) {
+ highestPriority = r.getPriority();
+ }
+ }
+ if (highestPriority == Long.MIN_VALUE || highestPriority < basePriority) {
+ return basePriority;
+ }
+ return highestPriority + PRIORITY_OFFSET;
+ }
+
+ /**
+ * Returns the priority for a series recording.
+ * <p>
+ * The recording will have the higher priority than the existing series.
+ */
+ public long suggestNewSeriesPriority() {
+ if (!SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet")) {
+ return DEFAULT_SERIES_PRIORITY;
+ }
+ return suggestHighestSeriesPriority();
+ }
+
+ /**
+ * Returns the priority for a series recording by order of series recording priority.
+ *
+ * Higher order will have higher priority.
+ */
+ public static long suggestSeriesPriority(int order) {
+ return DEFAULT_SERIES_PRIORITY + order * PRIORITY_OFFSET;
+ }
+
+ private long suggestHighestSeriesPriority() {
+ long highestPriority = DEFAULT_SERIES_PRIORITY - PRIORITY_OFFSET;
+ for (SeriesRecording schedule : mDataManager.getSeriesRecordings()) {
+ if (schedule.getPriority() > highestPriority) {
+ highestPriority = schedule.getPriority();
+ }
+ }
+ return highestPriority + PRIORITY_OFFSET;
+ }
+
+ /**
+ * Returns a sorted list of all scheduled recordings that will not be recorded if
+ * this program is going to be recorded, with their priorities in decending order.
+ * <p>
+ * An empty list means there is no conflicts. If there is conflict, a priority higher than
+ * the first recording in the returned list should be assigned to the new schedule of this
+ * program to guarantee the program would be completely recorded.
+ */
+ public List<ScheduledRecording> getConflictingSchedules(Program program) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ SoftPreconditions.checkState(Program.isValid(program), TAG,
+ "Program is invalid: " + program);
+ SoftPreconditions.checkState(
+ program.getStartTimeUtcMillis() < program.getEndTimeUtcMillis(), TAG,
+ "Program duration is empty: " + program);
+ if (!mInitialized || !Program.isValid(program)
+ || program.getStartTimeUtcMillis() >= program.getEndTimeUtcMillis()) {
+ return Collections.emptyList();
+ }
+ TvInputInfo input = Utils.getTvInputInfoForProgram(mContext, program);
+ if (input == null || !input.canRecord() || input.getTunerCount() <= 0) {
+ return Collections.emptyList();
+ }
+ return getConflictingSchedules(input, Collections.singletonList(
+ ScheduledRecording.builder(input.getId(), program)
+ .setPriority(suggestHighestPriority())
+ .build()));
+ }
+
+ /**
+ * Returns list of all conflicting scheduled recordings with schedules belonging to {@code
+ * seriesRecording}
+ * recording.
+ * <p>
+ * Any empty list means there is no conflicts.
+ */
+ public List<ScheduledRecording> getConflictingSchedules(SeriesRecording seriesRecording) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ SoftPreconditions.checkState(seriesRecording != null, TAG, "series recording is null");
+ if (!mInitialized || seriesRecording == null) {
+ return Collections.emptyList();
+ }
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, seriesRecording.getInputId());
+ if (input == null || !input.canRecord() || input.getTunerCount() <= 0) {
+ return Collections.emptyList();
+ }
+ List<ScheduledRecording> schedulesForSeries = mDataManager.getScheduledRecordings(
+ seriesRecording.getId());
+ return getConflictingSchedules(input, schedulesForSeries);
+ }
+
+ /**
+ * Returns a sorted list of all scheduled recordings that will not be recorded if
+ * this channel is going to be recorded, with their priority in decending order.
+ * <p>
+ * An empty list means there is no conflicts. If there is conflict, a priority higher than
+ * the first recording in the returned list should be assigned to the new schedule of this
+ * channel to guarantee the channel would be completely recorded in the designated time range.
+ */
+ public List<ScheduledRecording> getConflictingSchedules(long channelId, long startTimeMs,
+ long endTimeMs) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ SoftPreconditions.checkState(channelId != Channel.INVALID_ID, TAG, "Invalid channel ID");
+ SoftPreconditions.checkState(startTimeMs < endTimeMs, TAG, "Recording duration is empty.");
+ if (!mInitialized || channelId == Channel.INVALID_ID || startTimeMs >= endTimeMs) {
+ return Collections.emptyList();
+ }
+ TvInputInfo input = Utils.getTvInputInfoForChannelId(mContext, channelId);
+ if (input == null || !input.canRecord() || input.getTunerCount() <= 0) {
+ return Collections.emptyList();
+ }
+ return getConflictingSchedules(input, Collections.singletonList(
+ ScheduledRecording.builder(input.getId(), channelId, startTimeMs, endTimeMs)
+ .setPriority(suggestHighestPriority())
+ .build()));
+ }
+
+ /**
+ * Returns all the scheduled recordings that conflicts and will not be recorded or clipped for
+ * the given input.
+ */
+ @NonNull
+ private Map<ScheduledRecording, Boolean> getConflictingSchedulesInfo(String inputId) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, inputId);
+ SoftPreconditions.checkState(input != null, TAG, "Can't find input for : " + inputId);
+ if (!mInitialized || input == null) {
+ return Collections.emptyMap();
+ }
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(input.getId());
+ if (schedules == null || schedules.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ return getConflictingSchedulesInfo(schedules, input.getTunerCount());
+ }
+
+ /**
+ * Checks if the schedule is conflicting.
+ *
+ * <p>Note that the {@code schedule} should be the existing one. If not, this returns
+ * {@code false}.
+ */
+ public boolean isConflicting(ScheduledRecording schedule) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
+ SoftPreconditions.checkState(input != null, TAG, "Can't find input for channel ID : "
+ + schedule.getChannelId());
+ if (!mInitialized || input == null) {
+ return false;
+ }
+ Map<ScheduledRecording, Boolean> conflicts = mInputConflictInfoMap.get(input.getId());
+ return conflicts != null && conflicts.containsKey(schedule);
+ }
+
+ /**
+ * Checks if the schedule is partially conflicting, i.e., part of the scheduled program might be
+ * recorded even if the priority of the schedule is not raised.
+ * <p>
+ * If the given schedule is not conflicting or is totally conflicting, i.e., cannot be recorded
+ * at all, this method returns {@code false} in both cases.
+ */
+ public boolean isPartiallyConflicting(@NonNull ScheduledRecording schedule) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
+ SoftPreconditions.checkState(input != null, TAG, "Can't find input for channel ID : "
+ + schedule.getChannelId());
+ if (!mInitialized || input == null) {
+ return false;
+ }
+ Map<ScheduledRecording, Boolean> conflicts = mInputConflictInfoMap.get(input.getId());
+ return conflicts != null && conflicts.getOrDefault(schedule, false);
+ }
+
+ /**
+ * Returns priority ordered list of all scheduled recordings that will not be recorded if
+ * this channel is tuned to.
+ */
+ public List<ScheduledRecording> getConflictingSchedulesForTune(long channelId) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ SoftPreconditions.checkState(channelId != Channel.INVALID_ID, TAG, "Invalid channel ID");
+ TvInputInfo input = Utils.getTvInputInfoForChannelId(mContext, channelId);
+ SoftPreconditions.checkState(input != null, TAG, "Can't find input for channel ID: "
+ + channelId);
+ if (!mInitialized || channelId == Channel.INVALID_ID || input == null) {
+ return Collections.emptyList();
+ }
+ return getConflictingSchedulesForTune(input.getId(), channelId, System.currentTimeMillis(),
+ suggestHighestPriority(), getStartedRecordings(input.getId()),
+ input.getTunerCount());
+ }
+
+ @VisibleForTesting
+ public static List<ScheduledRecording> getConflictingSchedulesForTune(String inputId,
+ long channelId, long currentTimeMs, long newPriority,
+ List<ScheduledRecording> startedRecordings, int tunerCount) {
+ boolean channelFound = false;
+ for (ScheduledRecording schedule : startedRecordings) {
+ if (schedule.getChannelId() == channelId) {
+ channelFound = true;
+ break;
+ }
+ }
+ List<ScheduledRecording> schedules;
+ if (!channelFound) {
+ // The current channel is not being recorded.
+ schedules = new ArrayList<>(startedRecordings);
+ schedules.add(ScheduledRecording
+ .builder(inputId, channelId, currentTimeMs, currentTimeMs + 1)
+ .setPriority(newPriority)
+ .build());
+ } else {
+ schedules = startedRecordings;
+ }
+ return getConflictingSchedules(schedules, tunerCount);
+ }
+
+ /**
+ * Returns priority ordered list of all scheduled recordings that will not be recorded if
+ * the user keeps watching this channel.
+ * <p>
+ * Note that if the user keeps watching the channel, the channel can be recorded.
+ */
+ public List<ScheduledRecording> getConflictingSchedulesForWatching(long channelId) {
+ SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
+ SoftPreconditions.checkState(channelId != Channel.INVALID_ID, TAG, "Invalid channel ID");
+ TvInputInfo input = Utils.getTvInputInfoForChannelId(mContext, channelId);
+ SoftPreconditions.checkState(input != null, TAG, "Can't find input for channel ID: "
+ + channelId);
+ if (!mInitialized || channelId == Channel.INVALID_ID || input == null) {
+ return Collections.emptyList();
+ }
+ List<ScheduledRecording> schedules = mInputScheduleMap.get(input.getId());
+ if (schedules == null || schedules.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return getConflictingSchedulesForWatching(input.getId(), channelId,
+ System.currentTimeMillis(), suggestNewPriority(), schedules, input.getTunerCount());
+ }
+
+ private List<ScheduledRecording> getConflictingSchedules(TvInputInfo input,
+ List<ScheduledRecording> schedulesToAdd) {
+ SoftPreconditions.checkNotNull(input);
+ if (input == null || !input.canRecord() || input.getTunerCount() <= 0) {
+ return Collections.emptyList();
+ }
+ List<ScheduledRecording> currentSchedules = mInputScheduleMap.get(input.getId());
+ if (currentSchedules == null || currentSchedules.isEmpty()) {
+ return Collections.emptyList();
+ }
+ return getConflictingSchedules(schedulesToAdd, currentSchedules, input.getTunerCount());
+ }
+
+ @VisibleForTesting
+ static List<ScheduledRecording> getConflictingSchedulesForWatching(String inputId,
+ long channelId, long currentTimeMs, long newPriority,
+ @NonNull List<ScheduledRecording> schedules, int tunerCount) {
+ List<ScheduledRecording> schedulesToCheck = new ArrayList<>(schedules);
+ List<ScheduledRecording> schedulesSameChannel = new ArrayList<>();
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.getChannelId() == channelId) {
+ schedulesSameChannel.add(schedule);
+ schedulesToCheck.remove(schedule);
+ }
+ }
+ // Assume that the user will watch the current channel forever.
+ schedulesToCheck.add(ScheduledRecording
+ .builder(inputId, channelId, currentTimeMs, Long.MAX_VALUE)
+ .setPriority(newPriority)
+ .build());
+ List<ScheduledRecording> result = new ArrayList<>();
+ result.addAll(getConflictingSchedules(schedulesSameChannel, 1));
+ result.addAll(getConflictingSchedules(schedulesToCheck, tunerCount));
+ Collections.sort(result, RESULT_COMPARATOR);
+ return result;
+ }
+
+ @VisibleForTesting
+ static List<ScheduledRecording> getConflictingSchedules(List<ScheduledRecording> schedulesToAdd,
+ List<ScheduledRecording> currentSchedules, int tunerCount) {
+ List<ScheduledRecording> schedulesToCheck = new ArrayList<>(currentSchedules);
+ // When the duplicate schedule is to be added, remove the current duplicate recording.
+ for (Iterator<ScheduledRecording> iter = schedulesToCheck.iterator(); iter.hasNext(); ) {
+ ScheduledRecording schedule = iter.next();
+ for (ScheduledRecording toAdd : schedulesToAdd) {
+ if (schedule.getType() == ScheduledRecording.TYPE_PROGRAM) {
+ if (toAdd.getProgramId() == schedule.getProgramId()) {
+ iter.remove();
+ break;
+ }
+ } else {
+ if (toAdd.getChannelId() == schedule.getChannelId()
+ && toAdd.getStartTimeMs() == schedule.getStartTimeMs()
+ && toAdd.getEndTimeMs() == schedule.getEndTimeMs()) {
+ iter.remove();
+ break;
+ }
+ }
+ }
+ }
+ schedulesToCheck.addAll(schedulesToAdd);
+ List<Range<Long>> ranges = new ArrayList<>();
+ for (ScheduledRecording schedule : schedulesToAdd) {
+ ranges.add(new Range<>(schedule.getStartTimeMs(), schedule.getEndTimeMs()));
+ }
+ return getConflictingSchedules(schedulesToCheck, tunerCount, ranges);
+ }
+
+ /**
+ * Returns all conflicting scheduled recordings for the given schedules and count of tuner.
+ */
+ public static List<ScheduledRecording> getConflictingSchedules(
+ List<ScheduledRecording> schedules, int tunerCount) {
+ return getConflictingSchedules(schedules, tunerCount, null);
+ }
+
+ @VisibleForTesting
+ static List<ScheduledRecording> getConflictingSchedules(
+ List<ScheduledRecording> schedules, int tunerCount, List<Range<Long>> periods) {
+ List<ScheduledRecording> result = new ArrayList<>(
+ getConflictingSchedulesInfo(schedules, tunerCount, periods).keySet());
+ Collections.sort(result, RESULT_COMPARATOR);
+ return result;
+ }
+
+ @VisibleForTesting
+ static Map<ScheduledRecording, Boolean> getConflictingSchedulesInfo(
+ List<ScheduledRecording> schedules, int tunerCount) {
+ return getConflictingSchedulesInfo(schedules, tunerCount, null);
+ }
+
+ /**
+ * This is the core method to calculate all the conflicting schedules (in given periods).
+ * <p>
+ * Note that this method will ignore duplicated schedules with a same hash code. (Please refer
+ * to {@link ScheduledRecording#hashCode}.)
+ *
+ * @return A {@link HashMap} from {@link ScheduledRecording} to {@link Boolean}. The boolean
+ * value denotes if the scheduled recording is partially conflicting, i.e., is possible
+ * to be partially recorded under the given schedules and tuner count {@code true},
+ * or not {@code false}.
+ */
+ private static Map<ScheduledRecording, Boolean> getConflictingSchedulesInfo(
+ List<ScheduledRecording> schedules, int tunerCount, List<Range<Long>> periods) {
+ List<ScheduledRecording> schedulesToCheck = new ArrayList<>(schedules);
+ // Sort by the same order as that in InputTaskScheduler.
+ Collections.sort(schedulesToCheck, InputTaskScheduler.getRecordingOrderComparator());
+ List<ScheduledRecording> recordings = new ArrayList<>();
+ Map<ScheduledRecording, Boolean> conflicts = new HashMap<>();
+ Map<ScheduledRecording, ScheduledRecording> modified2OriginalSchedules = new HashMap<>();
+ // Simulate InputTaskScheduler.
+ while (!schedulesToCheck.isEmpty()) {
+ ScheduledRecording schedule = schedulesToCheck.remove(0);
+ removeFinishedRecordings(recordings, schedule.getStartTimeMs());
+ if (recordings.size() < tunerCount) {
+ recordings.add(schedule);
+ if (modified2OriginalSchedules.containsKey(schedule)) {
+ // Schedule has been modified, which means it's already conflicted.
+ // Modify its state to partially conflicted.
+ conflicts.put(modified2OriginalSchedules.get(schedule), true);
+ }
+ } else {
+ ScheduledRecording candidate = findReplaceableRecording(recordings, schedule);
+ if (candidate != null) {
+ if (!modified2OriginalSchedules.containsKey(candidate)) {
+ conflicts.put(candidate, true);
+ }
+ recordings.remove(candidate);
+ recordings.add(schedule);
+ if (modified2OriginalSchedules.containsKey(schedule)) {
+ // Schedule has been modified, which means it's already conflicted.
+ // Modify its state to partially conflicted.
+ conflicts.put(modified2OriginalSchedules.get(schedule), true);
+ }
+ } else {
+ if (!modified2OriginalSchedules.containsKey(schedule)) {
+ // if schedule has been modified, it's already conflicted.
+ // No need to add it again.
+ conflicts.put(schedule, false);
+ }
+ long earliestEndTime = getEarliestEndTime(recordings);
+ if (earliestEndTime < schedule.getEndTimeMs()) {
+ // The schedule can starts when other recording ends even though it's
+ // clipped.
+ ScheduledRecording modifiedSchedule = ScheduledRecording.buildFrom(schedule)
+ .setStartTimeMs(earliestEndTime).build();
+ ScheduledRecording originalSchedule =
+ modified2OriginalSchedules.getOrDefault(schedule, schedule);
+ modified2OriginalSchedules.put(modifiedSchedule, originalSchedule);
+ int insertPosition = Collections.binarySearch(schedulesToCheck,
+ modifiedSchedule,
+ ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR);
+ if (insertPosition >= 0) {
+ schedulesToCheck.add(insertPosition, modifiedSchedule);
+ } else {
+ schedulesToCheck.add(-insertPosition - 1, modifiedSchedule);
+ }
+ }
+ }
+ }
+ }
+ // Returns only the schedules with the given range.
+ if (periods != null && !periods.isEmpty()) {
+ for (Iterator<ScheduledRecording> iter = conflicts.keySet().iterator();
+ iter.hasNext(); ) {
+ boolean overlapping = false;
+ ScheduledRecording schedule = iter.next();
+ for (Range<Long> period : periods) {
+ if (schedule.isOverLapping(period)) {
+ overlapping = true;
+ break;
+ }
+ }
+ if (!overlapping) {
+ iter.remove();
+ }
+ }
+ }
+ return conflicts;
+ }
+
+ private static void removeFinishedRecordings(List<ScheduledRecording> recordings,
+ long currentTimeMs) {
+ for (Iterator<ScheduledRecording> iter = recordings.iterator(); iter.hasNext(); ) {
+ if (iter.next().getEndTimeMs() <= currentTimeMs) {
+ iter.remove();
+ }
+ }
+ }
+
+ /**
+ * @see InputTaskScheduler#getReplacableTask
+ */
+ private static ScheduledRecording findReplaceableRecording(List<ScheduledRecording> recordings,
+ ScheduledRecording schedule) {
+ // Returns the recording with the following priority.
+ // 1. The recording with the lowest priority is returned.
+ // 2. If the priorities are the same, the recording which finishes early is returned.
+ // 3. If 1) and 2) are the same, the early created schedule is returned.
+ ScheduledRecording candidate = null;
+ for (ScheduledRecording recording : recordings) {
+ if (schedule.getPriority() > recording.getPriority()) {
+ if (candidate == null || CANDIDATE_COMPARATOR.compare(candidate, recording) > 0) {
+ candidate = recording;
+ }
+ }
+ }
+ return candidate;
+ }
+
+ private static long getEarliestEndTime(List<ScheduledRecording> recordings) {
+ long earliest = Long.MAX_VALUE;
+ for (ScheduledRecording recording : recordings) {
+ if (earliest > recording.getEndTimeMs()) {
+ earliest = recording.getEndTimeMs();
+ }
+ }
+ return earliest;
+ }
+
+ /**
+ * A listener which is notified the initialization of schedule manager.
+ */
+ public interface OnInitializeListener {
+ /**
+ * Called when the schedule manager has been initialized.
+ */
+ void onInitialize();
+ }
+
+ /**
+ * A listener which is notified the conflict state change of the schedules.
+ */
+ public interface OnConflictStateChangeListener {
+ /**
+ * Called when the conflicting schedules change.
+ *
+ * @param conflict {@code true} if the {@code schedules} are the new conflicts, otherwise
+ * {@code false}.
+ * @param schedules the schedules
+ */
+ void onConflictStateChange(boolean conflict, ScheduledRecording... schedules);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/DvrSessionManager.java b/src/com/android/tv/dvr/DvrSessionManager.java
deleted file mode 100644
index fba05cb6..00000000
--- a/src/com/android/tv/dvr/DvrSessionManager.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.tv.dvr;
-
-import android.annotation.TargetApi;
-import android.content.Context;
-import android.media.tv.TvInputInfo;
-import android.media.tv.TvInputManager;
-import android.media.tv.TvRecordingClient;
-import android.os.Build;
-import android.os.Handler;
-import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
-import android.support.v4.util.ArrayMap;
-import android.util.Log;
-
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.data.Channel;
-
-/**
- * Manages Dvr Sessions.
- * Responsible for:
- * <ul>
- * <li>Manage DvrSession</li>
- * <li>Manage capabilities (conflict)</li>
- * </ul>
- */
-@TargetApi(Build.VERSION_CODES.N)
-public class DvrSessionManager extends TvInputManager.TvInputCallback {
- //consider moving all of this to TvInputManagerHelper
- private final static String TAG = "DvrSessionManager";
- private static final boolean DEBUG = false;
-
- private final Context mContext;
- private final TvInputManager mTvInputManager;
- private final ArrayMap<String, TvInputInfo> mRecordingTvInputs = new ArrayMap<>();
-
- public DvrSessionManager(Context context) {
- this(context, (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE),
- new Handler());
- }
-
- @VisibleForTesting
- DvrSessionManager(Context context, TvInputManager tvInputManager, Handler handler) {
- SoftPreconditions.checkFeatureEnabled(context, CommonFeatures.DVR, TAG);
- mTvInputManager = tvInputManager;
- mContext = context.getApplicationContext();
- for (TvInputInfo info : tvInputManager.getTvInputList()) {
- if (DEBUG) {
- Log.d(TAG, info + " canRecord=" + info.canRecord() + " tunerCount=" + info
- .getTunerCount());
- }
- if (info.canRecord()) {
- mRecordingTvInputs.put(info.getId(), info);
- }
- }
- tvInputManager.registerCallback(this, handler);
-
- }
-
- public TvRecordingClient createTvRecordingClient(String tag,
- TvRecordingClient.RecordingCallback callback, Handler handler) {
- return new TvRecordingClient(mContext, tag, callback, handler);
- }
-
- public boolean canAcquireDvrSession(String inputId, Channel channel) {
- // TODO(DVR): implement checking tuner count etc.
- TvInputInfo info = mRecordingTvInputs.get(inputId);
- return info != null;
- }
-
- public void releaseTvRecordingClient(TvRecordingClient recordingClient) {
- recordingClient.release();
- }
-
- @Override
- public void onInputAdded(String inputId) {
- super.onInputAdded(inputId);
- TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
- if (DEBUG) {
- Log.d(TAG, "onInputAdded " + info.toString() + " canRecord=" + info.canRecord()
- + " tunerCount=" + info.getTunerCount());
- }
- if (info.canRecord()) {
- mRecordingTvInputs.put(inputId, info);
- }
- }
-
- @Override
- public void onInputRemoved(String inputId) {
- super.onInputRemoved(inputId);
- if (DEBUG) Log.d(TAG, "onInputRemoved " + inputId);
- mRecordingTvInputs.remove(inputId);
- }
-
- @Override
- public void onInputUpdated(String inputId) {
- super.onInputUpdated(inputId);
- TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
- if (DEBUG) {
- Log.d(TAG, "onInputUpdated " + info.toString() + " canRecord=" + info.canRecord()
- + " tunerCount=" + info.getTunerCount());
- }
- if (info.canRecord()) {
- mRecordingTvInputs.put(inputId, info);
- } else {
- mRecordingTvInputs.remove(inputId);
- }
- }
-
- @Nullable
- public TvInputInfo getTvInputInfo(String inputId) {
- return mRecordingTvInputs.get(inputId);
- }
-}
diff --git a/src/com/android/tv/dvr/DvrStartRecordingReceiver.java b/src/com/android/tv/dvr/DvrStartRecordingReceiver.java
index 3649ad1e..6d2f0d43 100644
--- a/src/com/android/tv/dvr/DvrStartRecordingReceiver.java
+++ b/src/com/android/tv/dvr/DvrStartRecordingReceiver.java
@@ -16,6 +16,8 @@
package com.android.tv.dvr;
+import com.android.tv.TvApplication;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -26,6 +28,7 @@ import android.content.Intent;
public class DvrStartRecordingReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ TvApplication.setCurrentRunningProcess(context, true);
DvrRecordingService.startService(context);
}
}
diff --git a/src/com/android/tv/dvr/DvrStorageStatusManager.java b/src/com/android/tv/dvr/DvrStorageStatusManager.java
new file mode 100644
index 00000000..a653b5f4
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrStorageStatusManager.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.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.net.Uri;
+import android.os.AsyncTask;
+import android.os.Environment;
+import android.os.Looper;
+import android.os.RemoteException;
+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 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;
+
+/**
+ * Signals DVR storage status change such as plugging/unplugging.
+ */
+public class DvrStorageStatusManager {
+ private static final String TAG = "DvrStorageStatusManager";
+ 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";
+
+ private static final String[] PROJECTION = {
+ TvContract.RecordedPrograms._ID,
+ TvContract.RecordedPrograms.COLUMN_PACKAGE_NAME,
+ TvContract.RecordedPrograms.COLUMN_RECORDING_DATA_URI
+ };
+ private final static int BATCH_OPERATION_COUNT = 100;
+
+ @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;
+ }
+
+ /**
+ * 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;
+ }
+ }
+ return new MountedStorageStatus(
+ storageMounted, storageMountedDir, storageMountedCapacity);
+ }
+
+ private class CleanUpDbTask extends AsyncTask<Void, Void, Void> {
+ private final ContentResolver mContentResolver;
+
+ private CleanUpDbTask() {
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ @Override
+ protected Void doInBackground(Void... params) {
+ @DvrStorageStatusManager.StorageStatus int storageStatus = getDvrStorageStatus();
+ if (storageStatus == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
+ return null;
+ }
+ List<ContentProviderOperation> ops = getDeleteOps(storageStatus
+ == DvrStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL);
+ if (ops == null || ops.isEmpty()) {
+ return null;
+ }
+ Log.i(TAG, "New device storage mounted. # of recordings to be forgotten : "
+ + ops.size());
+ for (int i = 0 ; i < ops.size() && !isCancelled() ; i += BATCH_OPERATION_COUNT) {
+ int toIndex = (i + BATCH_OPERATION_COUNT) > ops.size()
+ ? ops.size() : (i + BATCH_OPERATION_COUNT);
+ ArrayList<ContentProviderOperation> batchOps =
+ new ArrayList<>(ops.subList(i, toIndex));
+ try {
+ mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, batchOps);
+ } catch (RemoteException | OperationApplicationException e) {
+ Log.e(TAG, "Failed to clean up RecordedPrograms.", e);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ if (mCleanUpDbTask == this) {
+ mCleanUpDbTask = null;
+ }
+ }
+
+ private List<ContentProviderOperation> getDeleteOps(boolean deleteAll) {
+ List<ContentProviderOperation> ops = new ArrayList<>();
+
+ try (Cursor c = mContentResolver.query(
+ TvContract.RecordedPrograms.CONTENT_URI, PROJECTION, null, null, null)) {
+ if (c == null) {
+ return null;
+ }
+ while (c.moveToNext()) {
+ @DvrStorageStatusManager.StorageStatus int storageStatus =
+ getDvrStorageStatus();
+ if (isCancelled()
+ || storageStatus == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
+ ops.clear();
+ break;
+ }
+ String id = c.getString(0);
+ String packageName = c.getString(1);
+ String dataUriString = c.getString(2);
+ if (dataUriString == null) {
+ continue;
+ }
+ Uri dataUri = Uri.parse(dataUriString);
+ if (!Utils.isInBundledPackageSet(packageName)
+ || dataUri == null || dataUri.getPath() == null
+ || !ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())) {
+ continue;
+ }
+ File recordedProgramDir = new File(dataUri.getPath());
+ if (deleteAll || !recordedProgramDir.exists()) {
+ ops.add(ContentProviderOperation.newDelete(
+ TvContract.buildRecordedProgramUri(Long.parseLong(id))).build());
+ }
+ }
+ return ops;
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/DvrUiHelper.java b/src/com/android/tv/dvr/DvrUiHelper.java
new file mode 100644
index 00000000..c0d3b0c5
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrUiHelper.java
@@ -0,0 +1,450 @@
+/*
+ * 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.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.media.tv.TvInputManager;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+import android.support.v4.app.ActivityOptionsCompat;
+import android.text.TextUtils;
+import android.widget.ImageView;
+import android.widget.Toast;
+
+import com.android.tv.MainActivity;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Channel;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.ui.DvrDetailsActivity;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrAlreadyRecordedDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrAlreadyScheduledDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrChannelRecordDurationOptionDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrChannelWatchConflictDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrInsufficientSpaceErrorDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrMissingStorageErrorDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrProgramConflictDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrScheduleDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrSmallSizedStorageErrorDialogFragment;
+import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrStopRecordingDialogFragment;
+import com.android.tv.dvr.ui.DvrSchedulesActivity;
+import com.android.tv.dvr.ui.DvrSeriesDeletionActivity;
+import com.android.tv.dvr.ui.DvrSeriesScheduledDialogActivity;
+import com.android.tv.dvr.ui.DvrSeriesSettingsActivity;
+import com.android.tv.dvr.ui.DvrStopRecordingFragment;
+import com.android.tv.dvr.ui.DvrStopSeriesRecordingDialogFragment;
+import com.android.tv.dvr.ui.DvrStopSeriesRecordingFragment;
+import com.android.tv.dvr.ui.HalfSizedDialogFragment;
+import com.android.tv.dvr.ui.list.DvrSchedulesFragment;
+import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment;
+import com.android.tv.util.Utils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A helper class for DVR UI.
+ */
+@MainThread
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrUiHelper {
+ /**
+ * Handles the action to create the new schedule. It returns {@code true} if the schedule is
+ * added and there's no additional UI, otherwise {@code false}.
+ */
+ public static boolean handleCreateSchedule(MainActivity activity, Program program) {
+ if (program == null) {
+ return false;
+ }
+ DvrManager dvrManager = TvApplication.getSingletons(activity).getDvrManager();
+ if (!program.isEpisodic()) {
+ // One time recording.
+ dvrManager.addSchedule(program);
+ if (!dvrManager.getConflictingSchedules(program).isEmpty()) {
+ DvrUiHelper.showScheduleConflictDialog(activity, program);
+ return false;
+ }
+ } else {
+ SeriesRecording seriesRecording = dvrManager.getSeriesRecording(program);
+ if (seriesRecording == null || seriesRecording.isStopped()) {
+ DvrUiHelper.showScheduleDialog(activity, program);
+ return false;
+ } else {
+ // Show recorded program rather than the schedule.
+ RecordedProgram recordedProgram = dvrManager.getRecordedProgram(program.getTitle(),
+ program.getSeasonNumber(), program.getEpisodeNumber());
+ if (recordedProgram != null) {
+ DvrUiHelper.showAlreadyRecordedDialog(activity, program);
+ return false;
+ }
+ ScheduledRecording duplicate = dvrManager.getScheduledRecording(program.getTitle(),
+ program.getSeasonNumber(), program.getEpisodeNumber());
+ if (duplicate != null
+ && (duplicate.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
+ || duplicate.getState()
+ == ScheduledRecording.STATE_RECORDING_IN_PROGRESS)) {
+ DvrUiHelper.showAlreadyScheduleDialog(activity, program);
+ return false;
+ }
+ // Just add the schedule.
+ dvrManager.addSchedule(program);
+ }
+ }
+ return true;
+
+ }
+
+ /**
+ * Checks if the storage status is good for recording and shows error messages if needed.
+ *
+ * @return true if the storage status is fine to be recorded for {@code inputId}.
+ */
+ public static boolean checkStorageStatusAndShowErrorMessage(Activity activity, String inputId) {
+ if (!Utils.isBundledInput(inputId)) {
+ return true;
+ }
+ DvrStorageStatusManager dvrStorageStatusManager =
+ TvApplication.getSingletons(activity).getDvrStorageStatusManager();
+ int status = dvrStorageStatusManager.getDvrStorageStatus();
+ if (status == DvrStorageStatusManager.STORAGE_STATUS_TOTAL_CAPACITY_TOO_SMALL) {
+ showDvrSmallSizedStorageErrorDialog(activity);
+ return false;
+ } else if (status == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
+ showDvrMissingStorageErrorDialog(activity, inputId);
+ return false;
+ } else if (status == DvrStorageStatusManager.STORAGE_STATUS_FREE_SPACE_INSUFFICIENT) {
+ // TODO: handle insufficient storage case.
+ return true;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * Shows the schedule dialog.
+ */
+ public static void showScheduleDialog(MainActivity activity, Program program) {
+ if (SoftPreconditions.checkNotNull(program) == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
+ showDialogFragment(activity, new DvrScheduleDialogFragment(), args, true, true);
+ }
+
+ /**
+ * Shows the recording duration options dialog.
+ */
+ public static void showChannelRecordDurationOptions(MainActivity activity, Channel channel) {
+ if (SoftPreconditions.checkNotNull(channel) == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channel.getId());
+ showDialogFragment(activity, new DvrChannelRecordDurationOptionDialogFragment(), args);
+ }
+
+ /**
+ * Shows the dialog which says that the new schedule conflicts with others.
+ */
+ public static void showScheduleConflictDialog(MainActivity activity, Program program) {
+ if (program == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
+ showDialogFragment(activity, new DvrProgramConflictDialogFragment(), args, false, true);
+ }
+
+ /**
+ * Shows the conflict dialog for the channel watching.
+ */
+ public static void showChannelWatchConflictDialog(MainActivity activity, Channel channel) {
+ if (channel == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channel.getId());
+ showDialogFragment(activity, new DvrChannelWatchConflictDialogFragment(), args);
+ }
+
+ /**
+ * Shows DVR insufficient space error dialog.
+ */
+ public static void showDvrInsufficientSpaceErrorDialog(MainActivity activity) {
+ showDialogFragment(activity, new DvrInsufficientSpaceErrorDialogFragment(), null);
+ Utils.clearRecordingFailedReason(activity,
+ TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ }
+
+ /**
+ * Shows DVR missing storage error dialog.
+ */
+ private static void showDvrMissingStorageErrorDialog(Activity activity, String inputId) {
+ SoftPreconditions.checkArgument(!TextUtils.isEmpty(inputId));
+ Bundle args = new Bundle();
+ args.putString(DvrHalfSizedDialogFragment.KEY_INPUT_ID, inputId);
+ showDialogFragment(activity, new DvrMissingStorageErrorDialogFragment(), args);
+ }
+
+ /**
+ * Shows DVR small sized storage error dialog.
+ */
+ public static void showDvrSmallSizedStorageErrorDialog(Activity activity) {
+ showDialogFragment(activity, new DvrSmallSizedStorageErrorDialogFragment(), null);
+ }
+
+ /**
+ * Shows stop recording dialog.
+ */
+ public static void showStopRecordingDialog(Activity activity, long channelId, int reason,
+ HalfSizedDialogFragment.OnActionClickListener listener) {
+ Bundle args = new Bundle();
+ args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, channelId);
+ args.putInt(DvrStopRecordingFragment.KEY_REASON, reason);
+ DvrHalfSizedDialogFragment fragment = new DvrStopRecordingDialogFragment();
+ fragment.setOnActionClickListener(listener);
+ showDialogFragment(activity, fragment, args);
+ }
+
+ /**
+ * Shows "already scheduled" dialog.
+ */
+ public static void showAlreadyScheduleDialog(MainActivity activity, Program program) {
+ if (program == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
+ showDialogFragment(activity, new DvrAlreadyScheduledDialogFragment(), args, false, true);
+ }
+
+ /**
+ * Shows "already recorded" dialog.
+ */
+ public static void showAlreadyRecordedDialog(MainActivity activity, Program program) {
+ if (program == null) {
+ return;
+ }
+ Bundle args = new Bundle();
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
+ showDialogFragment(activity, new DvrAlreadyRecordedDialogFragment(), args, false, true);
+ }
+
+ private static void showDialogFragment(Activity activity,
+ DvrHalfSizedDialogFragment dialogFragment, Bundle args) {
+ showDialogFragment(activity, dialogFragment, args, false, false);
+ }
+
+ private static void showDialogFragment(Activity activity,
+ DvrHalfSizedDialogFragment dialogFragment, Bundle args, boolean keepSidePanelHistory,
+ boolean keepProgramGuide) {
+ dialogFragment.setArguments(args);
+ if (activity instanceof MainActivity) {
+ ((MainActivity) activity).getOverlayManager()
+ .showDialogFragment(DvrHalfSizedDialogFragment.DIALOG_TAG, dialogFragment,
+ keepSidePanelHistory, keepProgramGuide);
+ } else {
+ dialogFragment.show(activity.getFragmentManager(),
+ DvrHalfSizedDialogFragment.DIALOG_TAG);
+ }
+ }
+
+ /**
+ * Checks whether channel watch conflict dialog is open or not.
+ */
+ public static boolean isChannelWatchConflictDialogShown(MainActivity activity) {
+ return activity.getOverlayManager().getCurrentDialog() instanceof
+ DvrChannelWatchConflictDialogFragment;
+ }
+
+ private static ScheduledRecording getEarliestScheduledRecording(List<ScheduledRecording>
+ recordings) {
+ ScheduledRecording earlistScheduledRecording = null;
+ if (!recordings.isEmpty()) {
+ Collections.sort(recordings,
+ ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR);
+ earlistScheduledRecording = recordings.get(0);
+ }
+ return earlistScheduledRecording;
+ }
+
+ /**
+ * Shows the schedules activity to resolve the tune conflict.
+ */
+ public static void startSchedulesActivityForTuneConflict(Context context, Channel channel) {
+ if (channel == null) {
+ return;
+ }
+ List<ScheduledRecording> conflicts = TvApplication.getSingletons(context).getDvrManager()
+ .getConflictingSchedulesForTune(channel.getId());
+ startSchedulesActivity(context, getEarliestScheduledRecording(conflicts));
+ }
+
+ /**
+ * Shows the schedules activity to resolve the one time recording conflict.
+ */
+ public static void startSchedulesActivityForOneTimeRecordingConflict(Context context,
+ List<ScheduledRecording> conflicts) {
+ startSchedulesActivity(context, getEarliestScheduledRecording(conflicts));
+ }
+
+ /**
+ * Shows the schedules activity with full schedule.
+ */
+ public static void startSchedulesActivity(Context context, ScheduledRecording
+ focusedScheduledRecording) {
+ Intent intent = new Intent(context, DvrSchedulesActivity.class);
+ intent.putExtra(DvrSchedulesActivity.KEY_SCHEDULES_TYPE,
+ DvrSchedulesActivity.TYPE_FULL_SCHEDULE);
+ if (focusedScheduledRecording != null) {
+ intent.putExtra(DvrSchedulesFragment.SCHEDULES_KEY_SCHEDULED_RECORDING,
+ focusedScheduledRecording);
+ }
+ context.startActivity(intent);
+ }
+
+ /**
+ * Shows the schedules activity for series recording.
+ */
+ public static void startSchedulesActivityForSeries(Context context,
+ SeriesRecording seriesRecording) {
+ Intent intent = new Intent(context, DvrSchedulesActivity.class);
+ intent.putExtra(DvrSchedulesActivity.KEY_SCHEDULES_TYPE,
+ DvrSchedulesActivity.TYPE_SERIES_SCHEDULE);
+ intent.putExtra(DvrSeriesSchedulesFragment.SERIES_SCHEDULES_KEY_SERIES_RECORDING,
+ seriesRecording);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Shows the series settings activity.
+ *
+ * @param channelIds Channel ID list which has programs belonging to the series.
+ */
+ public static void startSeriesSettingsActivity(Context context, long seriesRecordingId,
+ @Nullable long[] channelIds, boolean removeEmptySeriesSchedule,
+ boolean isWindowTranslucent, boolean showViewScheduleOptionInDialog) {
+ Intent intent = new Intent(context, DvrSeriesSettingsActivity.class);
+ intent.putExtra(DvrSeriesSettingsActivity.SERIES_RECORDING_ID, seriesRecordingId);
+ intent.putExtra(DvrSeriesSettingsActivity.CHANNEL_ID_LIST, channelIds);
+ intent.putExtra(DvrSeriesSettingsActivity.REMOVE_EMPTY_SERIES_RECORDING,
+ removeEmptySeriesSchedule);
+ intent.putExtra(DvrSeriesSettingsActivity.IS_WINDOW_TRANSLUCENT, isWindowTranslucent);
+ intent.putExtra(DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG,
+ showViewScheduleOptionInDialog);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Shows "series recording scheduled" dialog activity.
+ */
+ public static void StartSeriesScheduledDialogActivity(Context context,
+ SeriesRecording seriesRecording, boolean showViewScheduleOptionInDialog) {
+ if (seriesRecording == null) {
+ return;
+ }
+ Intent intent = new Intent(context, DvrSeriesScheduledDialogActivity.class);
+ intent.putExtra(DvrSeriesScheduledDialogActivity.SERIES_RECORDING_ID,
+ seriesRecording.getId());
+ intent.putExtra(DvrSeriesScheduledDialogActivity.SHOW_VIEW_SCHEDULE_OPTION,
+ showViewScheduleOptionInDialog);
+ context.startActivity(intent);
+ }
+
+ /**
+ * Shows the details activity for the DVR items. The type of DVR items may be
+ * {@link ScheduledRecording}, {@link RecordedProgram}, or {@link SeriesRecording}.
+ */
+ public static void startDetailsActivity(Activity activity, Object dvrItem,
+ @Nullable ImageView imageView, boolean hideViewSchedule) {
+ if (dvrItem == null) {
+ return;
+ }
+ Intent intent = new Intent(activity, DvrDetailsActivity.class);
+ long recordingId;
+ int viewType;
+ if (dvrItem instanceof ScheduledRecording) {
+ ScheduledRecording schedule = (ScheduledRecording) dvrItem;
+ recordingId = schedule.getId();
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ viewType = DvrDetailsActivity.SCHEDULED_RECORDING_VIEW;
+ } else if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ viewType = DvrDetailsActivity.CURRENT_RECORDING_VIEW;
+ } else {
+ return;
+ }
+ } else if (dvrItem instanceof RecordedProgram) {
+ recordingId = ((RecordedProgram) dvrItem).getId();
+ viewType = DvrDetailsActivity.RECORDED_PROGRAM_VIEW;
+ } else if (dvrItem instanceof SeriesRecording) {
+ recordingId = ((SeriesRecording) dvrItem).getId();
+ viewType = DvrDetailsActivity.SERIES_RECORDING_VIEW;
+ } else {
+ return;
+ }
+ intent.putExtra(DvrDetailsActivity.RECORDING_ID, recordingId);
+ intent.putExtra(DvrDetailsActivity.DETAILS_VIEW_TYPE, viewType);
+ intent.putExtra(DvrDetailsActivity.HIDE_VIEW_SCHEDULE, hideViewSchedule);
+ Bundle bundle = null;
+ if (imageView != null) {
+ bundle = ActivityOptionsCompat.makeSceneTransitionAnimation(activity, imageView,
+ DvrDetailsActivity.SHARED_ELEMENT_NAME).toBundle();
+ }
+ activity.startActivity(intent, bundle);
+ }
+
+ /**
+ * Shows the cancel all dialog for series schedules list.
+ */
+ public static void showCancelAllSeriesRecordingDialog(DvrSchedulesActivity activity,
+ SeriesRecording seriesRecording) {
+ DvrStopSeriesRecordingDialogFragment dvrStopSeriesRecordingDialogFragment =
+ new DvrStopSeriesRecordingDialogFragment();
+ Bundle arguments = new Bundle();
+ arguments.putParcelable(DvrStopSeriesRecordingFragment.KEY_SERIES_RECORDING,
+ seriesRecording);
+ dvrStopSeriesRecordingDialogFragment.setArguments(arguments);
+ dvrStopSeriesRecordingDialogFragment.show(activity.getFragmentManager(),
+ DvrStopSeriesRecordingDialogFragment.DIALOG_TAG);
+ }
+
+ /**
+ * Shows the series deletion activity.
+ */
+ public static void startSeriesDeletionActivity(Context context, long seriesRecordingId) {
+ Intent intent = new Intent(context, DvrSeriesDeletionActivity.class);
+ intent.putExtra(DvrSeriesDeletionActivity.SERIES_RECORDING_ID, seriesRecordingId);
+ context.startActivity(intent);
+ }
+
+ public static void showAddScheduleToast(Context context,
+ String title, long startTimeMs, long endTimeMs) {
+ String msg = (startTimeMs > System.currentTimeMillis()) ?
+ context.getString(R.string.dvr_msg_program_scheduled, title)
+ : context.getString(R.string.dvr_msg_current_program_scheduled, title,
+ Utils.toTimeString(endTimeMs, false));
+ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show();
+ }
+}
diff --git a/src/com/android/tv/dvr/DvrWatchedPositionManager.java b/src/com/android/tv/dvr/DvrWatchedPositionManager.java
new file mode 100644
index 00000000..4eada742
--- /dev/null
+++ b/src/com/android/tv/dvr/DvrWatchedPositionManager.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.media.tv.TvInputManager;
+import android.support.annotation.IntDef;
+
+import com.android.tv.common.SharedPreferencesUtils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CopyOnWriteArraySet;
+
+/**
+ * A class to manage DVR watched state.
+ * It will remember and provides previous watched position of DVR playback.
+ */
+public class DvrWatchedPositionManager {
+ private final static String TAG = "DvrWatchedPositionManager";
+ private final boolean DEBUG = false;
+
+ private SharedPreferences mWatchedPositions;
+ private final Map<Long, Set> mListeners = new HashMap<>();
+
+ /**
+ * The minimum percentage of recorded program being watched that will be considered as being
+ * completely watched.
+ */
+ public static final float DVR_WATCHED_THRESHOLD_RATE = 0.98f;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({DVR_WATCHED_STATUS_NEW, DVR_WATCHED_STATUS_WATCHING, DVR_WATCHED_STATUS_WATCHED})
+ public @interface DvrWatchedStatus {}
+ /**
+ * The status indicates the recorded program has not been watched at all.
+ */
+ public static final int DVR_WATCHED_STATUS_NEW = 0;
+ /**
+ * The status indicates the recorded program is being watched.
+ */
+ public static final int DVR_WATCHED_STATUS_WATCHING = 1;
+ /**
+ * The status indicates the recorded program was completely watched.
+ */
+ public static final int DVR_WATCHED_STATUS_WATCHED = 2;
+
+ public DvrWatchedPositionManager(Context context) {
+ mWatchedPositions = context.getSharedPreferences(
+ SharedPreferencesUtils.SHARED_PREF_DVR_WATCHED_POSITION, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Sets the watched position of the give program.
+ */
+ public void setWatchedPosition(long recordedProgramId, long positionMs) {
+ mWatchedPositions.edit().putLong(Long.toString(recordedProgramId), positionMs).apply();
+ notifyWatchedPositionChanged(recordedProgramId, positionMs);
+ }
+
+ /**
+ * Gets the watched position of the give program.
+ */
+ public long getWatchedPosition(long recordedProgramId) {
+ return mWatchedPositions.getLong(Long.toString(recordedProgramId),
+ TvInputManager.TIME_SHIFT_INVALID_TIME);
+ }
+
+ @DvrWatchedStatus public int getWatchedStatus(RecordedProgram recordedProgram) {
+ long watchedPosition = getWatchedPosition(recordedProgram.getId());
+ if (watchedPosition == TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ return DVR_WATCHED_STATUS_NEW;
+ } else if (watchedPosition > recordedProgram
+ .getDurationMillis() * DVR_WATCHED_THRESHOLD_RATE) {
+ return DVR_WATCHED_STATUS_WATCHED;
+ } else {
+ return DVR_WATCHED_STATUS_WATCHING;
+ }
+ }
+
+ /**
+ * Adds {@link WatchedPositionChangedListener}.
+ */
+ public void addListener(WatchedPositionChangedListener listener, long recordedProgramId) {
+ if (recordedProgramId == RecordedProgram.ID_NOT_SET) {
+ return;
+ }
+ Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
+ if (listenerSet == null) {
+ listenerSet = new CopyOnWriteArraySet<>();
+ mListeners.put(recordedProgramId, listenerSet);
+ }
+ listenerSet.add(listener);
+ }
+
+ /**
+ * Removes {@link WatchedPositionChangedListener}.
+ */
+ public void removeListener(WatchedPositionChangedListener listener) {
+ for (long recordedProgramId : new ArrayList<>(mListeners.keySet())) {
+ removeListener(listener, recordedProgramId);
+ }
+ }
+
+ /**
+ * Removes {@link WatchedPositionChangedListener}.
+ */
+ public void removeListener(WatchedPositionChangedListener listener, long recordedProgramId) {
+ Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
+ if (listenerSet == null) {
+ return;
+ }
+ listenerSet.remove(listener);
+ if (listenerSet.isEmpty()) {
+ mListeners.remove(recordedProgramId);
+ }
+ }
+
+ private void notifyWatchedPositionChanged(long recordedProgramId, long positionMs) {
+ Set<WatchedPositionChangedListener> listenerSet = mListeners.get(recordedProgramId);
+ if (listenerSet == null) {
+ return;
+ }
+ for (WatchedPositionChangedListener listener : listenerSet) {
+ listener.onWatchedPositionChanged(recordedProgramId, positionMs);
+ }
+ }
+
+ public interface WatchedPositionChangedListener {
+ /**
+ * Called when the watched position of some program is changed.
+ */
+ void onWatchedPositionChanged(long recordedProgramId, long positionMs);
+ }
+}
diff --git a/src/com/android/tv/dvr/EpisodicProgramLoadTask.java b/src/com/android/tv/dvr/EpisodicProgramLoadTask.java
new file mode 100644
index 00000000..15ca2700
--- /dev/null
+++ b/src/com/android/tv/dvr/EpisodicProgramLoadTask.java
@@ -0,0 +1,382 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.media.tv.TvContract.Programs;
+import android.net.Uri;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.support.annotation.WorkerThread;
+import android.text.TextUtils;
+
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Program;
+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;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A wrapper of AsyncProgramQueryTask to load the episodic programs for the series recordings.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+abstract public class EpisodicProgramLoadTask {
+ private static final String TAG = "EpisodicProgramLoadTask";
+
+ private static final int PROGRAM_ID_INDEX = Program.getColumnIndex(Programs._ID);
+ private static final int START_TIME_INDEX =
+ Program.getColumnIndex(Programs.COLUMN_START_TIME_UTC_MILLIS);
+ private static final int RECORDING_PROHIBITED_INDEX =
+ Program.getColumnIndex(Programs.COLUMN_RECORDING_PROHIBITED);
+
+ private static final String PARAM_START_TIME = "start_time";
+ private static final String PARAM_END_TIME = "end_time";
+
+ private static final String PROGRAM_PREDICATE =
+ Programs.COLUMN_START_TIME_UTC_MILLIS + ">? AND "
+ + Programs.COLUMN_RECORDING_PROHIBITED + "=0";
+ private static final String PROGRAM_PREDICATE_WITH_CURRENT_PROGRAM =
+ Programs.COLUMN_END_TIME_UTC_MILLIS + ">? AND "
+ + Programs.COLUMN_RECORDING_PROHIBITED + "=0";
+ private static final String CHANNEL_ID_PREDICATE = Programs.COLUMN_CHANNEL_ID + "=?";
+ private static final String PROGRAM_TITLE_PREDICATE = Programs.COLUMN_TITLE + "=?";
+
+ private final Context mContext;
+ private final DvrDataManager mDataManager;
+ private boolean mQueryAllChannels;
+ private boolean mLoadCurrentProgram;
+ private boolean mLoadScheduledEpisode;
+ private boolean mLoadDisallowedProgram;
+ // If true, match programs with OPTION_CHANNEL_ALL.
+ private boolean mIgnoreChannelOption;
+ private final ArrayList<SeriesRecording> mSeriesRecordings = new ArrayList<>();
+ private AsyncProgramQueryTask mProgramQueryTask;
+
+ /**
+ *
+ * Constructor used to load programs for one series recording with the given channel option.
+ */
+ public EpisodicProgramLoadTask(Context context, SeriesRecording seriesRecording) {
+ this(context, Collections.singletonList(seriesRecording));
+ }
+
+ /**
+ * Constructor used to load programs for multiple series recordings. The channel option is
+ * {@link SeriesRecording#OPTION_CHANNEL_ALL}.
+ */
+ public EpisodicProgramLoadTask(Context context, Collection<SeriesRecording> seriesRecordings) {
+ mContext = context.getApplicationContext();
+ mDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mSeriesRecordings.addAll(seriesRecordings);
+ }
+
+ /**
+ * Returns the series recordings.
+ */
+ public List<SeriesRecording> getSeriesRecordings() {
+ return mSeriesRecordings;
+ }
+
+ /**
+ * Returns the program query task. It is {@code null} until it is executed.
+ */
+ @Nullable
+ public AsyncProgramQueryTask getTask() {
+ return mProgramQueryTask;
+ }
+
+ /**
+ * Enables loading current programs. The default value is {@code false}.
+ */
+ public EpisodicProgramLoadTask setLoadCurrentProgram(boolean loadCurrentProgram) {
+ SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
+ "Can't change setting after execution.");
+ mLoadCurrentProgram = loadCurrentProgram;
+ return this;
+ }
+
+ /**
+ * Enables already schedules episodes. The default value is {@code false}.
+ */
+ public EpisodicProgramLoadTask setLoadScheduledEpisode(boolean loadScheduledEpisode) {
+ SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
+ "Can't change setting after execution.");
+ mLoadScheduledEpisode = loadScheduledEpisode;
+ return this;
+ }
+
+ /**
+ * Enables loading disallowed programs whose schedules were removed manually by the user.
+ * The default value is {@code false}.
+ */
+ public EpisodicProgramLoadTask setLoadDisallowedProgram(boolean loadDisallowedProgram) {
+ SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
+ "Can't change setting after execution.");
+ mLoadDisallowedProgram = loadDisallowedProgram;
+ return this;
+ }
+
+ /**
+ * Gives the option whether to ignore the channel option when matching programs.
+ * If {@code ignoreChannelOption} is {@code true}, the program will be matched with
+ * {@link SeriesRecording#OPTION_CHANNEL_ALL} option.
+ */
+ public EpisodicProgramLoadTask setIgnoreChannelOption(boolean ignoreChannelOption) {
+ SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
+ "Can't change setting after execution.");
+ mIgnoreChannelOption = ignoreChannelOption;
+ return this;
+ }
+
+ /**
+ * Executes the task.
+ *
+ * @see com.android.tv.util.AsyncDbTask#executeOnDbThread
+ */
+ public void execute() {
+ if (SoftPreconditions.checkState(mProgramQueryTask == null, TAG,
+ "Can't execute task: the task is already running.")) {
+ mQueryAllChannels = mSeriesRecordings.size() > 1
+ || mSeriesRecordings.get(0).getChannelOption()
+ == SeriesRecording.OPTION_CHANNEL_ALL
+ || mIgnoreChannelOption;
+ mProgramQueryTask = createTask();
+ mProgramQueryTask.executeOnDbThread();
+ }
+ }
+
+ /**
+ * Cancels the task.
+ *
+ * @see android.os.AsyncTask#cancel
+ */
+ public void cancel(boolean mayInterruptIfRunning) {
+ if (mProgramQueryTask != null) {
+ mProgramQueryTask.cancel(mayInterruptIfRunning);
+ }
+ }
+
+ /**
+ * Runs on the UI thread after the program loading finishes successfully.
+ */
+ protected void onPostExecute(List<Program> programs) {
+ }
+
+ /**
+ * Runs on the UI thread after the program loading was canceled.
+ */
+ protected void onCancelled(List<Program> programs) {
+ }
+
+ private AsyncProgramQueryTask createTask() {
+ SqlParams sqlParams = createSqlParams();
+ return new AsyncProgramQueryTask(mContext.getContentResolver(), sqlParams.uri,
+ sqlParams.selection, sqlParams.selectionArgs, null, sqlParams.filter) {
+ @Override
+ protected void onPostExecute(List<Program> programs) {
+ EpisodicProgramLoadTask.this.onPostExecute(programs);
+ }
+
+ @Override
+ protected void onCancelled(List<Program> programs) {
+ EpisodicProgramLoadTask.this.onCancelled(programs);
+ }
+ };
+ }
+
+ private SqlParams createSqlParams() {
+ SqlParams sqlParams = new SqlParams();
+ if (PermissionUtils.hasAccessAllEpg(mContext)) {
+ sqlParams.uri = Programs.CONTENT_URI;
+ // Base
+ StringBuilder selection = new StringBuilder(mLoadCurrentProgram
+ ? PROGRAM_PREDICATE_WITH_CURRENT_PROGRAM : PROGRAM_PREDICATE);
+ List<String> args = new ArrayList<>();
+ args.add(Long.toString(System.currentTimeMillis()));
+ // Channel option
+ if (!mQueryAllChannels) {
+ selection.append(" AND ").append(CHANNEL_ID_PREDICATE);
+ args.add(Long.toString(mSeriesRecordings.get(0).getChannelId()));
+ }
+ // Title
+ if (mSeriesRecordings.size() == 1) {
+ selection.append(" AND ").append(PROGRAM_TITLE_PREDICATE);
+ args.add(mSeriesRecordings.get(0).getTitle());
+ }
+ sqlParams.selection = selection.toString();
+ sqlParams.selectionArgs = args.toArray(new String[args.size()]);
+ sqlParams.filter = new SeriesRecordingCursorFilter(mSeriesRecordings);
+ } else {
+ // The query includes the current program. Will be filtered if needed.
+ if (mQueryAllChannels) {
+ sqlParams.uri = Programs.CONTENT_URI.buildUpon()
+ .appendQueryParameter(PARAM_START_TIME,
+ String.valueOf(System.currentTimeMillis()))
+ .appendQueryParameter(PARAM_END_TIME, String.valueOf(Long.MAX_VALUE))
+ .build();
+ } else {
+ sqlParams.uri = TvContract.buildProgramsUriForChannel(
+ mSeriesRecordings.get(0).getChannelId(),
+ System.currentTimeMillis(), Long.MAX_VALUE);
+ }
+ sqlParams.selection = null;
+ sqlParams.selectionArgs = null;
+ sqlParams.filter = new SeriesRecordingCursorFilterForNonSystem(mSeriesRecordings);
+ }
+ return sqlParams;
+ }
+
+ @VisibleForTesting
+ static boolean isEpisodeScheduled(Collection<ScheduledEpisode> scheduledEpisodes,
+ ScheduledEpisode episode) {
+ // The episode whose season number or episode number is null will always be scheduled.
+ return scheduledEpisodes.contains(episode) && !TextUtils.isEmpty(episode.seasonNumber)
+ && !TextUtils.isEmpty(episode.episodeNumber);
+ }
+
+ /**
+ * Filter the programs which match the series recording. The episodes which the schedules are
+ * already created for are filtered out too.
+ */
+ private class SeriesRecordingCursorFilter implements CursorFilter {
+ private final Set<Long> mDisallowedProgramIds = new HashSet<>();
+ private final Set<ScheduledEpisode> mScheduledEpisodes = new HashSet<>();
+
+ SeriesRecordingCursorFilter(List<SeriesRecording> seriesRecordings) {
+ if (!mLoadDisallowedProgram) {
+ mDisallowedProgramIds.addAll(mDataManager.getDisallowedProgramIds());
+ }
+ if (!mLoadScheduledEpisode) {
+ Set<Long> seriesRecordingIds = new HashSet<>();
+ for (SeriesRecording r : seriesRecordings) {
+ seriesRecordingIds.add(r.getId());
+ }
+ for (ScheduledRecording r : mDataManager.getAllScheduledRecordings()) {
+ if (seriesRecordingIds.contains(r.getSeriesRecordingId())
+ && r.getState() != ScheduledRecording.STATE_RECORDING_FAILED
+ && r.getState() != ScheduledRecording.STATE_RECORDING_CLIPPED) {
+ mScheduledEpisodes.add(new ScheduledEpisode(r));
+ }
+ }
+ }
+ }
+
+ @Override
+ @WorkerThread
+ public boolean filter(Cursor c) {
+ if (!mLoadDisallowedProgram
+ && mDisallowedProgramIds.contains(c.getLong(PROGRAM_ID_INDEX))) {
+ return false;
+ }
+ Program program = Program.fromCursor(c);
+ for (SeriesRecording seriesRecording : mSeriesRecordings) {
+ boolean programMatches;
+ if (mIgnoreChannelOption) {
+ programMatches = seriesRecording.matchProgram(program,
+ SeriesRecording.OPTION_CHANNEL_ALL);
+ } else {
+ programMatches = seriesRecording.matchProgram(program);
+ }
+ if (programMatches) {
+ return mLoadScheduledEpisode
+ || !isEpisodeScheduled(mScheduledEpisodes, new ScheduledEpisode(
+ seriesRecording.getId(), program.getSeasonNumber(),
+ program.getEpisodeNumber()));
+ }
+ }
+ return false;
+ }
+ }
+
+ private class SeriesRecordingCursorFilterForNonSystem extends SeriesRecordingCursorFilter {
+ SeriesRecordingCursorFilterForNonSystem(List<SeriesRecording> seriesRecordings) {
+ super(seriesRecordings);
+ }
+
+ @Override
+ public boolean filter(Cursor c) {
+ return (mLoadCurrentProgram || c.getLong(START_TIME_INDEX) > System.currentTimeMillis())
+ && c.getInt(RECORDING_PROHIBITED_INDEX) != 0 && super.filter(c);
+ }
+ }
+
+ private static class SqlParams {
+ public Uri uri;
+ public String selection;
+ public String[] selectionArgs;
+ public CursorFilter filter;
+ }
+
+ /**
+ * A plain java object which includes the season/episode number for the series recording.
+ */
+ public static class ScheduledEpisode {
+ public final long seriesRecordingId;
+ public final String seasonNumber;
+ public final String episodeNumber;
+
+ /**
+ * Create a new Builder with the values set from an existing {@link ScheduledRecording}.
+ */
+ ScheduledEpisode(ScheduledRecording r) {
+ this(r.getSeriesRecordingId(), r.getSeasonNumber(), r.getEpisodeNumber());
+ }
+
+ public ScheduledEpisode(long seriesRecordingId, String seasonNumber, String episodeNumber) {
+ this.seriesRecordingId = seriesRecordingId;
+ this.seasonNumber = seasonNumber;
+ this.episodeNumber = episodeNumber;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof ScheduledEpisode)) return false;
+ ScheduledEpisode that = (ScheduledEpisode) o;
+ return seriesRecordingId == that.seriesRecordingId
+ && Objects.equals(seasonNumber, that.seasonNumber)
+ && Objects.equals(episodeNumber, that.episodeNumber);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(seriesRecordingId, seasonNumber, episodeNumber);
+ }
+
+ @Override
+ public String toString() {
+ return "ScheduledEpisode{" +
+ "seriesRecordingId=" + seriesRecordingId +
+ ", seasonNumber='" + seasonNumber +
+ ", episodeNumber=" + episodeNumber +
+ '}';
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/IdGenerator.java b/src/com/android/tv/dvr/IdGenerator.java
new file mode 100644
index 00000000..0ed6362c
--- /dev/null
+++ b/src/com/android/tv/dvr/IdGenerator.java
@@ -0,0 +1,50 @@
+/*
+ * 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 java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A class which generate the ID which increases sequentially.
+ */
+public class IdGenerator {
+ /**
+ * ID generator for the scheduled recording.
+ */
+ public static final IdGenerator SCHEDULED_RECORDING = new IdGenerator();
+
+ /**
+ * ID generator for the series recording.
+ */
+ public static final IdGenerator SERIES_RECORDING = new IdGenerator();
+
+ private final AtomicLong mMaxId = new AtomicLong(0);
+
+ /**
+ * Sets the new maximum ID.
+ */
+ public void setMaxId(long maxId) {
+ mMaxId.set(maxId);
+ }
+
+ /**
+ * Returns the new ID which is greater than the existing maximum ID by 1.
+ */
+ public long newId() {
+ return mMaxId.incrementAndGet();
+ }
+}
diff --git a/src/com/android/tv/dvr/InputTaskScheduler.java b/src/com/android/tv/dvr/InputTaskScheduler.java
new file mode 100644
index 00000000..53c89ebc
--- /dev/null
+++ b/src/com/android/tv/dvr/InputTaskScheduler.java
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.content.Context;
+import android.media.tv.TvInputInfo;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArrayMap;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+import com.android.tv.InputSessionManager;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.util.Clock;
+import com.android.tv.util.CompositeComparator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * The scheduler for a TV input.
+ */
+public class InputTaskScheduler {
+ private static final String TAG = "InputTaskScheduler";
+ private static final boolean DEBUG = false;
+
+ private static final int MSG_ADD_SCHEDULED_RECORDING = 1;
+ private static final int MSG_REMOVE_SCHEDULED_RECORDING = 2;
+ private static final int MSG_UPDATE_SCHEDULED_RECORDING = 3;
+ private static final int MSG_BUILD_SCHEDULE = 4;
+ private static final int MSG_STOP_SCHEDULE = 5;
+
+ private static final float MIN_REMAIN_DURATION_PERCENT = 0.05f;
+
+ // The candidate comparator should be the consistent with
+ // DvrScheduleManager#CANDIDATE_COMPARATOR.
+ private static final Comparator<RecordingTask> CANDIDATE_COMPARATOR =
+ new CompositeComparator<>(
+ RecordingTask.PRIORITY_COMPARATOR,
+ RecordingTask.END_TIME_COMPARATOR,
+ RecordingTask.ID_COMPARATOR);
+
+ /**
+ * Returns the comparator which the schedules are sorted with when executed.
+ */
+ public static Comparator<ScheduledRecording> getRecordingOrderComparator() {
+ return ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR;
+ }
+
+ /**
+ * Wraps a {@link RecordingTask} removing it from {@link #mPendingRecordings} when it is done.
+ */
+ public final class HandlerWrapper extends Handler {
+ public static final int MESSAGE_REMOVE = 999;
+ private final long mId;
+ private final RecordingTask mTask;
+
+ HandlerWrapper(Looper looper, ScheduledRecording scheduledRecording,
+ RecordingTask recordingTask) {
+ super(looper, recordingTask);
+ mId = scheduledRecording.getId();
+ mTask = recordingTask;
+ mTask.setHandler(this);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ // The RecordingTask gets a chance first.
+ // It must return false to pass this message to here.
+ if (msg.what == MESSAGE_REMOVE) {
+ if (DEBUG) Log.d(TAG, "done " + mId);
+ mPendingRecordings.remove(mId);
+ }
+ removeCallbacksAndMessages(null);
+ mHandler.removeMessages(MSG_BUILD_SCHEDULE);
+ mHandler.sendEmptyMessage(MSG_BUILD_SCHEDULE);
+ super.handleMessage(msg);
+ }
+ }
+
+ private TvInputInfo mInput;
+ private final Looper mLooper;
+ private final ChannelDataManager mChannelDataManager;
+ private final DvrManager mDvrManager;
+ private final WritableDvrDataManager mDataManager;
+ private final InputSessionManager mSessionManager;
+ private final Clock mClock;
+ private final Context mContext;
+
+ private final LongSparseArray<HandlerWrapper> mPendingRecordings = new LongSparseArray<>();
+ private final Map<Long, ScheduledRecording> mWaitingSchedules = new ArrayMap<>();
+ private final Handler mMainThreadHandler;
+ private final Handler mHandler;
+ private final Object mInputLock = new Object();
+ private final RecordingTaskFactory mRecordingTaskFactory;
+
+ public InputTaskScheduler(Context context, TvInputInfo input, Looper looper,
+ ChannelDataManager channelDataManager, DvrManager dvrManager,
+ DvrDataManager dataManager, InputSessionManager sessionManager, Clock clock) {
+ this(context, input, looper, channelDataManager, dvrManager, dataManager, sessionManager,
+ clock, new Handler(Looper.getMainLooper()), null, null);
+ }
+
+ @VisibleForTesting
+ InputTaskScheduler(Context context, TvInputInfo input, Looper looper,
+ ChannelDataManager channelDataManager, DvrManager dvrManager,
+ DvrDataManager dataManager, InputSessionManager sessionManager, Clock clock,
+ Handler mainThreadHandler, @Nullable Handler workerThreadHandler,
+ RecordingTaskFactory recordingTaskFactory) {
+ if (DEBUG) Log.d(TAG, "Creating scheduler for " + input);
+ mContext = context;
+ mInput = input;
+ mLooper = looper;
+ mChannelDataManager = channelDataManager;
+ mDvrManager = dvrManager;
+ mDataManager = (WritableDvrDataManager) dataManager;
+ mSessionManager = sessionManager;
+ mClock = clock;
+ mMainThreadHandler = mainThreadHandler;
+ mRecordingTaskFactory = recordingTaskFactory != null ? recordingTaskFactory
+ : new RecordingTaskFactory() {
+ @Override
+ public RecordingTask createRecordingTask(ScheduledRecording schedule, Channel channel,
+ DvrManager dvrManager, InputSessionManager sessionManager,
+ WritableDvrDataManager dataManager, Clock clock) {
+ return new RecordingTask(mContext, schedule, channel, mDvrManager, mSessionManager,
+ mDataManager, mClock);
+ }
+ };
+ if (workerThreadHandler == null) {
+ mHandler = new WorkerThreadHandler(looper);
+ } else {
+ mHandler = workerThreadHandler;
+ }
+ }
+
+ /**
+ * Adds a {@link ScheduledRecording}.
+ */
+ public void addSchedule(ScheduledRecording schedule) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ADD_SCHEDULED_RECORDING, schedule));
+ }
+
+ @VisibleForTesting
+ void handleAddSchedule(ScheduledRecording schedule) {
+ if (mPendingRecordings.get(schedule.getId()) != null
+ || mWaitingSchedules.containsKey(schedule.getId())) {
+ return;
+ }
+ mWaitingSchedules.put(schedule.getId(), schedule);
+ mHandler.removeMessages(MSG_BUILD_SCHEDULE);
+ mHandler.sendEmptyMessage(MSG_BUILD_SCHEDULE);
+ }
+
+ /**
+ * Removes the {@link ScheduledRecording}.
+ */
+ public void removeSchedule(ScheduledRecording schedule) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_REMOVE_SCHEDULED_RECORDING, schedule));
+ }
+
+ @VisibleForTesting
+ void handleRemoveSchedule(ScheduledRecording schedule) {
+ HandlerWrapper wrapper = mPendingRecordings.get(schedule.getId());
+ if (wrapper != null) {
+ wrapper.mTask.cancel();
+ return;
+ }
+ if (mWaitingSchedules.containsKey(schedule.getId())) {
+ mWaitingSchedules.remove(schedule.getId());
+ mHandler.removeMessages(MSG_BUILD_SCHEDULE);
+ mHandler.sendEmptyMessage(MSG_BUILD_SCHEDULE);
+ }
+ }
+
+ /**
+ * Updates the {@link ScheduledRecording}.
+ */
+ public void updateSchedule(ScheduledRecording schedule) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_SCHEDULED_RECORDING, schedule));
+ }
+
+ @VisibleForTesting
+ void handleUpdateSchedule(ScheduledRecording schedule) {
+ HandlerWrapper wrapper = mPendingRecordings.get(schedule.getId());
+ if (wrapper != null) {
+ if (schedule.getStartTimeMs() > mClock.currentTimeMillis()
+ && schedule.getStartTimeMs() > wrapper.mTask.getStartTimeMs()) {
+ // It shouldn't have started. Cancel and put to the waiting list.
+ // The schedules will be rebuilt when the task is removed.
+ // The reschedule is called in Scheduler.
+ wrapper.mTask.cancel();
+ mWaitingSchedules.put(schedule.getId(), schedule);
+ return;
+ }
+ wrapper.sendMessage(wrapper.obtainMessage(RecordingTask.MSG_UDPATE_SCHEDULE, schedule));
+ return;
+ }
+ if (mWaitingSchedules.containsKey(schedule.getId())) {
+ mWaitingSchedules.put(schedule.getId(), schedule);
+ mHandler.removeMessages(MSG_BUILD_SCHEDULE);
+ mHandler.sendEmptyMessage(MSG_BUILD_SCHEDULE);
+ }
+ }
+
+ /**
+ * Updates the TV input.
+ */
+ public void updateTvInputInfo(TvInputInfo input) {
+ synchronized (mInputLock) {
+ mInput = input;
+ }
+ }
+
+ /**
+ * Stops the input task scheduler.
+ */
+ public void stop() {
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.sendEmptyMessage(MSG_STOP_SCHEDULE);
+ }
+
+ private void handleStopSchedule() {
+ mWaitingSchedules.clear();
+ int size = mPendingRecordings.size();
+ for (int i = 0; i < size; ++i) {
+ RecordingTask task = mPendingRecordings.get(mPendingRecordings.keyAt(i)).mTask;
+ task.cleanUp();
+ }
+ }
+
+ @VisibleForTesting
+ void handleBuildSchedule() {
+ if (mWaitingSchedules.isEmpty()) {
+ return;
+ }
+ long currentTimeMs = mClock.currentTimeMillis();
+ // Remove past schedules.
+ for (Iterator<ScheduledRecording> iter = mWaitingSchedules.values().iterator();
+ iter.hasNext(); ) {
+ ScheduledRecording schedule = iter.next();
+ if (schedule.getEndTimeMs() - currentTimeMs
+ <= MIN_REMAIN_DURATION_PERCENT * schedule.getDuration()) {
+ fail(schedule);
+ iter.remove();
+ }
+ }
+ if (mWaitingSchedules.isEmpty()) {
+ return;
+ }
+ // Record the schedules which should start now.
+ List<ScheduledRecording> schedulesToStart = new ArrayList<>();
+ for (ScheduledRecording schedule : mWaitingSchedules.values()) {
+ if (schedule.getState() != ScheduledRecording.STATE_RECORDING_CANCELED
+ && schedule.getStartTimeMs() - RecordingTask.RECORDING_EARLY_START_OFFSET_MS
+ <= currentTimeMs && schedule.getEndTimeMs() > currentTimeMs) {
+ schedulesToStart.add(schedule);
+ }
+ }
+ // The schedules will be executed with the following order.
+ // 1. The schedule which starts early. It can be replaced later when the schedule with the
+ // higher priority needs to start.
+ // 2. The schedule with the higher priority. It can be replaced later when the schedule with
+ // the higher priority needs to start.
+ // 3. The schedule which was created recently.
+ Collections.sort(schedulesToStart, getRecordingOrderComparator());
+ int tunerCount;
+ synchronized (mInputLock) {
+ tunerCount = mInput.canRecord() ? mInput.getTunerCount() : 0;
+ }
+ for (ScheduledRecording schedule : schedulesToStart) {
+ if (hasTaskWhichFinishEarlier(schedule)) {
+ // If there is a schedule which finishes earlier than the new schedule, rebuild the
+ // schedules after it finishes.
+ return;
+ }
+ if (mPendingRecordings.size() < tunerCount) {
+ // Tuners available.
+ createRecordingTask(schedule).start();
+ mWaitingSchedules.remove(schedule.getId());
+ } else {
+ // No available tuners.
+ RecordingTask task = getReplacableTask(schedule);
+ if (task != null) {
+ task.stop();
+ // Just return. The schedules will be rebuilt after the task is stopped.
+ return;
+ }
+ }
+ }
+ if (mWaitingSchedules.isEmpty()) {
+ return;
+ }
+ // Set next scheduling.
+ long earliest = Long.MAX_VALUE;
+ for (ScheduledRecording schedule : mWaitingSchedules.values()) {
+ // The conflicting schedules will be removed if they end before conflicting resolved.
+ if (schedulesToStart.contains(schedule)) {
+ if (earliest > schedule.getEndTimeMs()) {
+ earliest = schedule.getEndTimeMs();
+ }
+ } else {
+ if (earliest > schedule.getStartTimeMs()
+ - RecordingTask.RECORDING_EARLY_START_OFFSET_MS) {
+ earliest = schedule.getStartTimeMs()
+ - RecordingTask.RECORDING_EARLY_START_OFFSET_MS;
+ }
+ }
+ }
+ mHandler.sendEmptyMessageDelayed(MSG_BUILD_SCHEDULE, earliest - currentTimeMs);
+ }
+
+ private RecordingTask createRecordingTask(ScheduledRecording schedule) {
+ Channel channel = mChannelDataManager.getChannel(schedule.getChannelId());
+ RecordingTask recordingTask = mRecordingTaskFactory.createRecordingTask(schedule, channel,
+ mDvrManager, mSessionManager, mDataManager, mClock);
+ HandlerWrapper handlerWrapper = new HandlerWrapper(mLooper, schedule, recordingTask);
+ mPendingRecordings.put(schedule.getId(), handlerWrapper);
+ return recordingTask;
+ }
+
+ private boolean hasTaskWhichFinishEarlier(ScheduledRecording schedule) {
+ int size = mPendingRecordings.size();
+ for (int i = 0; i < size; ++i) {
+ RecordingTask task = mPendingRecordings.get(mPendingRecordings.keyAt(i)).mTask;
+ if (task.getEndTimeMs() <= schedule.getStartTimeMs()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private RecordingTask getReplacableTask(ScheduledRecording schedule) {
+ // Returns the recording with the following priority.
+ // 1. The recording with the lowest priority is returned.
+ // 2. If the priorities are the same, the recording which finishes early is returned.
+ // 3. If 1) and 2) are the same, the early created schedule is returned.
+ int size = mPendingRecordings.size();
+ RecordingTask candidate = null;
+ for (int i = 0; i < size; ++i) {
+ RecordingTask task = mPendingRecordings.get(mPendingRecordings.keyAt(i)).mTask;
+ if (schedule.getPriority() > task.getPriority()) {
+ if (candidate == null || CANDIDATE_COMPARATOR.compare(candidate, task) > 0) {
+ candidate = task;
+ }
+ }
+ }
+ return candidate;
+ }
+
+ private void fail(ScheduledRecording schedule) {
+ // It's called when the scheduling has been failed without creating RecordingTask.
+ runOnMainHandler(new Runnable() {
+ @Override
+ public void run() {
+ ScheduledRecording scheduleInManager =
+ mDataManager.getScheduledRecording(schedule.getId());
+ if (scheduleInManager != null) {
+ // The schedule should be updated based on the object from DataManager in case
+ // when it has been updated.
+ mDataManager.changeState(scheduleInManager,
+ ScheduledRecording.STATE_RECORDING_FAILED);
+ }
+ }
+ });
+ }
+
+ private void runOnMainHandler(Runnable runnable) {
+ if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
+ runnable.run();
+ } else {
+ mMainThreadHandler.post(runnable);
+ }
+ }
+
+ @VisibleForTesting
+ interface RecordingTaskFactory {
+ RecordingTask createRecordingTask(ScheduledRecording scheduledRecording, Channel channel,
+ DvrManager dvrManager, InputSessionManager sessionManager,
+ WritableDvrDataManager dataManager, Clock clock);
+ }
+
+ private class WorkerThreadHandler extends Handler {
+ public WorkerThreadHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ADD_SCHEDULED_RECORDING:
+ handleAddSchedule((ScheduledRecording) msg.obj);
+ break;
+ case MSG_REMOVE_SCHEDULED_RECORDING:
+ handleRemoveSchedule((ScheduledRecording) msg.obj);
+ break;
+ case MSG_UPDATE_SCHEDULED_RECORDING:
+ handleUpdateSchedule((ScheduledRecording) msg.obj);
+ case MSG_BUILD_SCHEDULE:
+ handleBuildSchedule();
+ break;
+ case MSG_STOP_SCHEDULE:
+ handleStopSchedule();
+ break;
+ }
+ }
+ }
+}
diff --git a/common/src/com/android/tv/common/recording/RecordedProgram.java b/src/com/android/tv/dvr/RecordedProgram.java
index 63ce6ff9..dd744f80 100644
--- a/common/src/com/android/tv/common/recording/RecordedProgram.java
+++ b/src/com/android/tv/dvr/RecordedProgram.java
@@ -14,34 +14,44 @@
* limitations under the License
*/
-package com.android.tv.common.recording;
+package com.android.tv.dvr;
import static android.media.tv.TvContract.RecordedPrograms;
+import android.annotation.TargetApi;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.media.tv.TvContract;
import android.net.Uri;
+import android.os.Build;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.common.R;
+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;
import java.util.Objects;
+import java.util.concurrent.TimeUnit;
/**
* Immutable instance of {@link android.media.tv.TvContract.RecordedPrograms}.
*/
-public class RecordedProgram {
+@TargetApi(Build.VERSION_CODES.N)
+public class RecordedProgram extends BaseProgram {
public static final int ID_NOT_SET = -1;
public final static String[] PROJECTION = {
// These are in exactly the order listed in RecordedPrograms
RecordedPrograms._ID,
+ RecordedPrograms.COLUMN_PACKAGE_NAME,
RecordedPrograms.COLUMN_INPUT_ID,
RecordedPrograms.COLUMN_CHANNEL_ID,
RecordedPrograms.COLUMN_TITLE,
@@ -66,18 +76,19 @@ public class RecordedProgram {
RecordedPrograms.COLUMN_RECORDING_DATA_BYTES,
RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS,
RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS,
- RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG3,
RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG4,
RecordedPrograms.COLUMN_VERSION_NUMBER,
+ RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
};
- public static final RecordedProgram fromCursor(Cursor cursor) {
+ public static RecordedProgram fromCursor(Cursor cursor) {
int index = 0;
- return builder()
+ Builder builder = builder()
.setId(cursor.getLong(index++))
+ .setPackageName(cursor.getString(index++))
.setInputId(cursor.getString(index++))
.setChannelId(cursor.getLong(index++))
.setTitle(cursor.getString(index++))
@@ -95,20 +106,22 @@ public class RecordedProgram {
.setVideoHeight(cursor.getInt(index++))
.setAudioLanguage(cursor.getString(index++))
.setContentRating(cursor.getString(index++))
- .setPosterArt(cursor.getString(index++))
- .setThumbnail(cursor.getString(index++))
+ .setPosterArtUri(cursor.getString(index++))
+ .setThumbnailUri(cursor.getString(index++))
.setSearchable(cursor.getInt(index++) == 1)
.setDataUri(cursor.getString(index++))
.setDataBytes(cursor.getLong(index++))
.setDurationMillis(cursor.getLong(index++))
.setExpireTimeUtcMillis(cursor.getLong(index++))
- .setInternalProviderData(cursor.getBlob(index++))
.setInternalProviderFlag1(cursor.getInt(index++))
.setInternalProviderFlag2(cursor.getInt(index++))
.setInternalProviderFlag3(cursor.getInt(index++))
.setInternalProviderFlag4(cursor.getInt(index++))
- .setVersionNumber(cursor.getInt(index++))
- .build();
+ .setVersionNumber(cursor.getInt(index++));
+ if (Utils.isInBundledPackageSet(builder.mPackageName)) {
+ InternalDataUtils.deserializeInternalProviderData(cursor.getBlob(index), builder);
+ }
+ return builder.build();
}
public static ContentValues toValues(RecordedProgram recordedProgram) {
@@ -144,9 +157,8 @@ public class RecordedProgram {
}
values.put(RecordedPrograms.COLUMN_AUDIO_LANGUAGE, recordedProgram.mAudioLanguage);
values.put(RecordedPrograms.COLUMN_CONTENT_RATING, recordedProgram.mContentRating);
- values.put(RecordedPrograms.COLUMN_POSTER_ART_URI,
- safeToString(recordedProgram.mPosterArt));
- values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, safeToString(recordedProgram.mThumbnail));
+ values.put(RecordedPrograms.COLUMN_POSTER_ART_URI, recordedProgram.mPosterArtUri);
+ values.put(RecordedPrograms.COLUMN_THUMBNAIL_URI, recordedProgram.mThumbnailUri);
values.put(RecordedPrograms.COLUMN_SEARCHABLE, recordedProgram.mSearchable ? 1 : 0);
values.put(RecordedPrograms.COLUMN_RECORDING_DATA_URI,
safeToString(recordedProgram.mDataUri));
@@ -156,7 +168,7 @@ public class RecordedProgram {
values.put(RecordedPrograms.COLUMN_RECORDING_EXPIRE_TIME_UTC_MILLIS,
recordedProgram.mExpireTimeUtcMillis);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_DATA,
- recordedProgram.mInternalProviderData);
+ InternalDataUtils.serializeInternalProviderData(recordedProgram));
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG1,
recordedProgram.mInternalProviderFlag1);
values.put(RecordedPrograms.COLUMN_INTERNAL_PROVIDER_FLAG2,
@@ -171,9 +183,11 @@ public class RecordedProgram {
public static class Builder{
private long mId = ID_NOT_SET;
+ private String mPackageName;
private String mInputId;
private long mChannelId;
private String mTitle;
+ private String mSeriesId;
private String mSeasonNumber;
private String mSeasonTitle;
private String mEpisodeNumber;
@@ -188,14 +202,13 @@ public class RecordedProgram {
private int mVideoHeight;
private String mAudioLanguage;
private String mContentRating;
- private Uri mPosterArt;
- private Uri mThumbnail;
+ private String mPosterArtUri;
+ private String mThumbnailUri;
private boolean mSearchable = true;
private Uri mDataUri;
private long mDataBytes;
private long mDurationMillis;
private long mExpireTimeUtcMillis;
- private byte[] mInternalProviderData;
private int mInternalProviderFlag1;
private int mInternalProviderFlag2;
private int mInternalProviderFlag3;
@@ -207,6 +220,11 @@ public class RecordedProgram {
return this;
}
+ public Builder setPackageName(String packageName) {
+ mPackageName = packageName;
+ return this;
+ }
+
public Builder setInputId(String inputId) {
mInputId = inputId;
return this;
@@ -222,6 +240,11 @@ public class RecordedProgram {
return this;
}
+ public Builder setSeriesId(String seriesId) {
+ mSeriesId = seriesId;
+ return this;
+ }
+
public Builder setSeasonNumber(String seasonNumber) {
mSeasonNumber = seasonNumber;
return this;
@@ -316,21 +339,13 @@ public class RecordedProgram {
}
}
- public Builder setPosterArt(String posterArtUri) {
- return setPosterArt(toUri(posterArtUri));
- }
-
- public Builder setPosterArt(Uri posterArt) {
- mPosterArt = posterArt;
+ public Builder setPosterArtUri(String posterArtUri) {
+ mPosterArtUri = posterArtUri;
return this;
}
- public Builder setThumbnail(String thumbnailUri) {
- return setThumbnail(toUri(thumbnailUri));
- }
-
- public Builder setThumbnail(Uri thumbnail) {
- mThumbnail = thumbnail;
+ public Builder setThumbnailUri(String thumbnailUri) {
+ mThumbnailUri = thumbnailUri;
return this;
}
@@ -363,11 +378,6 @@ public class RecordedProgram {
return this;
}
- public Builder setInternalProviderData(byte[] internalProviderData) {
- mInternalProviderData = internalProviderData;
- return this;
- }
-
public Builder setInternalProviderFlag1(int internalProviderFlag1) {
mInternalProviderFlag1 = internalProviderFlag1;
return this;
@@ -394,12 +404,17 @@ public class RecordedProgram {
}
public RecordedProgram build() {
- return new RecordedProgram(mId, mInputId, mChannelId, mTitle, mSeasonNumber,
- mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis,
+ // Generate the series ID for the episodic program of other TV input.
+ if (TextUtils.isEmpty(mSeriesId)
+ && !TextUtils.isEmpty(mEpisodeNumber)) {
+ setSeriesId(BaseProgram.generateSeriesId(mPackageName, mTitle));
+ }
+ return new RecordedProgram(mId, mPackageName, mInputId, mChannelId, mTitle, mSeriesId,
+ mSeasonNumber, mSeasonTitle, mEpisodeNumber, mEpisodeTitle, mStartTimeUtcMillis,
mEndTimeUtcMillis, mBroadcastGenres, mCanonicalGenres, mShortDescription,
mLongDescription, mVideoWidth, mVideoHeight, mAudioLanguage, mContentRating,
- mPosterArt, mThumbnail, mSearchable, mDataUri, mDataBytes, mDurationMillis,
- mExpireTimeUtcMillis, mInternalProviderData, mInternalProviderFlag1,
+ mPosterArtUri, mThumbnailUri, mSearchable, mDataUri, mDataBytes,
+ mDurationMillis, mExpireTimeUtcMillis, mInternalProviderFlag1,
mInternalProviderFlag2, mInternalProviderFlag3, mInternalProviderFlag4,
mVersionNumber);
}
@@ -410,9 +425,11 @@ public class RecordedProgram {
public static Builder buildFrom(RecordedProgram orig) {
return builder()
.setId(orig.getId())
+ .setPackageName(orig.getPackageName())
.setInputId(orig.getInputId())
.setChannelId(orig.getChannelId())
.setTitle(orig.getTitle())
+ .setSeriesId(orig.getSeriesId())
.setSeasonNumber(orig.getSeasonNumber())
.setSeasonTitle(orig.getSeasonTitle())
.setEpisodeNumber(orig.getEpisodeNumber())
@@ -421,16 +438,15 @@ public class RecordedProgram {
.setEndTimeUtcMillis(orig.getEndTimeUtcMillis())
.setBroadcastGenres(orig.getBroadcastGenres())
.setCanonicalGenres(orig.getCanonicalGenres())
- .setShortDescription(orig.getShortDescription())
+ .setShortDescription(orig.getDescription())
.setLongDescription(orig.getLongDescription())
.setVideoWidth(orig.getVideoWidth())
.setVideoHeight(orig.getVideoHeight())
.setAudioLanguage(orig.getAudioLanguage())
.setContentRating(orig.getContentRating())
- .setPosterArt(orig.getPosterArt())
- .setThumbnail(orig.getThumbnail())
+ .setPosterArtUri(orig.getPosterArtUri())
+ .setThumbnailUri(orig.getThumbnailUri())
.setSearchable(orig.isSearchable())
- .setInternalProviderData(orig.getInternalProviderData())
.setInternalProviderFlag1(orig.getInternalProviderFlag1())
.setInternalProviderFlag2(orig.getInternalProviderFlag2())
.setInternalProviderFlag3(orig.getInternalProviderFlag3())
@@ -438,22 +454,27 @@ public class RecordedProgram {
.setVersionNumber(orig.getVersionNumber());
}
- public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR
- = new Comparator<RecordedProgram>() {
- @Override
- public int compare(RecordedProgram lhs, RecordedProgram rhs) {
- int res = Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis());
- if (res != 0) {
- return res;
- }
- return Long.compare(lhs.mId, rhs.mId);
- }
+ public static final Comparator<RecordedProgram> START_TIME_THEN_ID_COMPARATOR =
+ new Comparator<RecordedProgram>() {
+ @Override
+ public int compare(RecordedProgram lhs, RecordedProgram rhs) {
+ int res =
+ Long.compare(lhs.getStartTimeUtcMillis(), rhs.getStartTimeUtcMillis());
+ if (res != 0) {
+ return res;
+ }
+ return Long.compare(lhs.mId, rhs.mId);
+ }
};
+ private static final long CLIPPED_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(5);
+
private final long mId;
+ private final String mPackageName;
private final String mInputId;
private final long mChannelId;
private final String mTitle;
+ private final String mSeriesId;
private final String mSeasonNumber;
private final String mSeasonTitle;
private final String mEpisodeNumber;
@@ -468,33 +489,34 @@ public class RecordedProgram {
private final int mVideoHeight;
private final String mAudioLanguage;
private final String mContentRating;
- private final Uri mPosterArt;
- private final Uri mThumbnail;
+ private final String mPosterArtUri;
+ private final String mThumbnailUri;
private final boolean mSearchable;
private final Uri mDataUri;
private final long mDataBytes;
private final long mDurationMillis;
private final long mExpireTimeUtcMillis;
- private final byte[] mInternalProviderData;
private final int mInternalProviderFlag1;
private final int mInternalProviderFlag2;
private final int mInternalProviderFlag3;
private final int mInternalProviderFlag4;
private final int mVersionNumber;
- private RecordedProgram(long id, String inputId, long channelId, String title,
- String seasonNumber, String seasonTitle, String episodeNumber, String episodeTitle,
- long startTimeUtcMillis, long endTimeUtcMillis, String[] broadcastGenres,
- String[] canonicalGenres, String shortDescription, String longDescription,
- int videoWidth, int videoHeight, String audioLanguage, String contentRating,
- Uri posterArt, Uri thumbnail, boolean searchable, Uri dataUri, long dataBytes,
- long durationMillis, long expireTimeUtcMillis, byte[] internalProviderData,
- int internalProviderFlag1, int internalProviderFlag2, int internalProviderFlag3,
- int internalProviderFlag4, int versionNumber) {
+ private RecordedProgram(long id, String packageName, String inputId, long channelId,
+ String title, String seriesId, String seasonNumber, String seasonTitle,
+ String episodeNumber, String episodeTitle, long startTimeUtcMillis,
+ long endTimeUtcMillis, String[] broadcastGenres, String[] canonicalGenres,
+ String shortDescription, String longDescription, int videoWidth, int videoHeight,
+ String audioLanguage, String contentRating, String posterArtUri, String thumbnailUri,
+ boolean searchable, Uri dataUri, long dataBytes, long durationMillis,
+ long expireTimeUtcMillis, int internalProviderFlag1, int internalProviderFlag2,
+ int internalProviderFlag3, int internalProviderFlag4, int versionNumber) {
mId = id;
+ mPackageName = packageName;
mInputId = inputId;
mChannelId = channelId;
mTitle = title;
+ mSeriesId = seriesId;
mSeasonNumber = seasonNumber;
mSeasonTitle = seasonTitle;
mEpisodeNumber = episodeNumber;
@@ -510,14 +532,13 @@ public class RecordedProgram {
mAudioLanguage = audioLanguage;
mContentRating = contentRating;
- mPosterArt = posterArt;
- mThumbnail = thumbnail;
+ mPosterArtUri = posterArtUri;
+ mThumbnailUri = thumbnailUri;
mSearchable = searchable;
mDataUri = dataUri;
mDataBytes = dataBytes;
mDurationMillis = durationMillis;
mExpireTimeUtcMillis = expireTimeUtcMillis;
- mInternalProviderData = internalProviderData;
mInternalProviderFlag1 = internalProviderFlag1;
mInternalProviderFlag2 = internalProviderFlag2;
mInternalProviderFlag3 = internalProviderFlag3;
@@ -537,6 +558,22 @@ public class RecordedProgram {
return mCanonicalGenres;
}
+ /**
+ * Returns array of canonical genre ID's for this recorded program.
+ */
+ @Override
+ public int[] getCanonicalGenreIds() {
+ if (mCanonicalGenres == null) {
+ return null;
+ }
+ int[] genreIds = new int[mCanonicalGenres.length];
+ for (int i = 0; i < mCanonicalGenres.length; i++) {
+ genreIds[i] = GenreItems.getId(mCanonicalGenres[i]);
+ }
+ return genreIds;
+ }
+
+ @Override
public long getChannelId() {
return mChannelId;
}
@@ -553,14 +590,17 @@ public class RecordedProgram {
return mDataBytes;
}
+ @Override
public long getDurationMillis() {
return mDurationMillis;
}
+ @Override
public long getEndTimeUtcMillis() {
return mEndTimeUtcMillis;
}
+ @Override
public String getEpisodeNumber() {
return mEpisodeNumber;
}
@@ -569,15 +609,54 @@ public class RecordedProgram {
return mEpisodeTitle;
}
+ @Override
public String getEpisodeDisplayTitle(Context context) {
- if (!TextUtils.isEmpty(mSeasonNumber) && !TextUtils.isEmpty(mEpisodeNumber)
- && !TextUtils.isEmpty(mEpisodeTitle)) {
- return String.format(context.getResources().getString(R.string.episode_format),
- mSeasonNumber, mEpisodeNumber, mEpisodeTitle);
+ if (!TextUtils.isEmpty(mEpisodeNumber)) {
+ String episodeTitle = mEpisodeTitle == null ? "" : mEpisodeTitle;
+ if (TextUtils.equals(mSeasonNumber, "0")) {
+ // Do not show "S0: ".
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format_no_season_number),
+ mEpisodeNumber, episodeTitle);
+ } else {
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format),
+ mSeasonNumber, mEpisodeNumber, episodeTitle);
+ }
}
return mEpisodeTitle;
}
+ @Nullable
+ @Override
+ public String getTitleWithEpisodeNumber(Context context) {
+ if (TextUtils.isEmpty(mTitle)) {
+ return mTitle;
+ }
+ if (TextUtils.isEmpty(mSeasonNumber) || mSeasonNumber.equals("0")) {
+ return TextUtils.isEmpty(mEpisodeNumber) ? mTitle : context.getString(
+ R.string.program_title_with_episode_number_no_season, mTitle, mEpisodeNumber);
+ } else {
+ return context.getString(R.string.program_title_with_episode_number, mTitle,
+ mSeasonNumber, mEpisodeNumber);
+ }
+ }
+
+ @Nullable
+ public String getEpisodeDisplayNumber(Context context) {
+ if (!TextUtils.isEmpty(mEpisodeNumber)) {
+ if (TextUtils.equals(mSeasonNumber, "0")) {
+ // Do not show "S0: ".
+ return String.format(context.getResources().getString(
+ R.string.display_episode_number_format_no_season_number), mEpisodeNumber);
+ } else {
+ return String.format(context.getResources().getString(
+ R.string.display_episode_number_format), mSeasonNumber, mEpisodeNumber);
+ }
+ }
+ return null;
+ }
+
public long getExpireTimeUtcMillis() {
return mExpireTimeUtcMillis;
}
@@ -586,12 +665,12 @@ public class RecordedProgram {
return mId;
}
- public String getInputId() {
- return mInputId;
+ public String getPackageName() {
+ return mPackageName;
}
- public byte[] getInternalProviderData() {
- return mInternalProviderData;
+ public String getInputId() {
+ return mInputId;
}
public int getInternalProviderFlag1() {
@@ -610,18 +689,36 @@ public class RecordedProgram {
return mInternalProviderFlag4;
}
+ @Override
+ public String getDescription() {
+ return mShortDescription;
+ }
+
+ @Override
public String getLongDescription() {
return mLongDescription;
}
- public Uri getPosterArt() {
- return mPosterArt;
+ @Override
+ public String getPosterArtUri() {
+ return mPosterArtUri;
+ }
+
+ @Override
+ public boolean isValid() {
+ return true;
}
public boolean isSearchable() {
return mSearchable;
}
+ @Override
+ public String getSeriesId() {
+ return mSeriesId;
+ }
+
+ @Override
public String getSeasonNumber() {
return mSeasonNumber;
}
@@ -630,18 +727,17 @@ public class RecordedProgram {
return mSeasonTitle;
}
- public String getShortDescription() {
- return mShortDescription;
- }
-
+ @Override
public long getStartTimeUtcMillis() {
return mStartTimeUtcMillis;
}
- public Uri getThumbnail() {
- return mThumbnail;
+ @Override
+ public String getThumbnailUri() {
+ return mThumbnailUri;
}
+ @Override
public String getTitle() {
return mTitle;
}
@@ -663,8 +759,12 @@ public class RecordedProgram {
}
/**
- * Compares everything except {@link #getInternalProviderData()}
+ * Checks whether the recording has been clipped or not.
*/
+ public boolean isClipped() {
+ return mEndTimeUtcMillis - mStartTimeUtcMillis - mDurationMillis > CLIPPED_THRESHOLD_MS;
+ }
+
@Override
public boolean equals(Object o) {
if (this == o) return true;
@@ -672,6 +772,7 @@ public class RecordedProgram {
RecordedProgram that = (RecordedProgram) o;
return Objects.equals(mId, that.mId) &&
Objects.equals(mChannelId, that.mChannelId) &&
+ Objects.equals(mSeriesId, that.mSeriesId) &&
Objects.equals(mSeasonNumber, that.mSeasonNumber) &&
Objects.equals(mSeasonTitle, that.mSeasonTitle) &&
Objects.equals(mEpisodeNumber, that.mEpisodeNumber) &&
@@ -696,8 +797,8 @@ public class RecordedProgram {
Objects.equals(mLongDescription, that.mLongDescription) &&
Objects.equals(mAudioLanguage, that.mAudioLanguage) &&
Objects.equals(mContentRating, that.mContentRating) &&
- Objects.equals(mPosterArt, that.mPosterArt) &&
- Objects.equals(mThumbnail, that.mThumbnail);
+ Objects.equals(mPosterArtUri, that.mPosterArtUri) &&
+ Objects.equals(mThumbnailUri, that.mThumbnailUri);
}
/**
@@ -712,9 +813,11 @@ public class RecordedProgram {
public String toString() {
return "RecordedProgram"
+ "[" + mId +
- "]{ mInputId=" + mInputId +
+ "]{ mPackageName=" + mPackageName +
+ ", mInputId='" + mInputId + '\'' +
", mChannelId='" + mChannelId + '\'' +
", mTitle='" + mTitle + '\'' +
+ ", mSeriesId='" + mSeriesId + '\'' +
", mEpisodeNumber=" + mEpisodeNumber +
", mEpisodeTitle='" + mEpisodeTitle + '\'' +
", mStartTimeUtcMillis=" + mStartTimeUtcMillis +
@@ -729,15 +832,13 @@ public class RecordedProgram {
", mVideoWidth=" + mVideoWidth +
", mAudioLanguage='" + mAudioLanguage + '\'' +
", mContentRating='" + mContentRating + '\'' +
- ", mPosterArt=" + mPosterArt +
- ", mThumbnail=" + mThumbnail +
+ ", mPosterArtUri=" + mPosterArtUri +
+ ", mThumbnailUri=" + mThumbnailUri +
", mSearchable=" + mSearchable +
", mDataUri=" + mDataUri +
", mDataBytes=" + mDataBytes +
", mDurationMillis=" + mDurationMillis +
", mExpireTimeUtcMillis=" + mExpireTimeUtcMillis +
- ", mInternalProviderData.length=" +
- (mInternalProviderData == null ? "null" : mInternalProviderData.length) +
", mInternalProviderFlag1=" + mInternalProviderFlag1 +
", mInternalProviderFlag2=" + mInternalProviderFlag2 +
", mInternalProviderFlag3=" + mInternalProviderFlag3 +
@@ -757,4 +858,11 @@ public class RecordedProgram {
private static String safeEncode(@Nullable String[] genres) {
return genres == null ? null : TvContract.Programs.Genres.encode(genres);
}
+
+ /**
+ * Returns an array containing all of the elements in the list.
+ */
+ public static RecordedProgram[] toArray(Collection<RecordedProgram> recordedPrograms) {
+ return recordedPrograms.toArray(new RecordedProgram[recordedPrograms.size()]);
+ }
}
diff --git a/src/com/android/tv/dvr/RecordingTask.java b/src/com/android/tv/dvr/RecordingTask.java
index 804485b3..c3d236b0 100644
--- a/src/com/android/tv/dvr/RecordingTask.java
+++ b/src/com/android/tv/dvr/RecordingTask.java
@@ -16,21 +16,32 @@
package com.android.tv.dvr;
+import android.annotation.TargetApi;
+import android.content.Context;
import android.media.tv.TvContract;
-import android.media.tv.TvRecordingClient;
+import android.media.tv.TvInputManager;
+import android.media.tv.TvRecordingClient.RecordingCallback;
import android.net.Uri;
+import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.util.Log;
+import android.widget.Toast;
+import com.android.tv.InputSessionManager;
+import com.android.tv.InputSessionManager.RecordingSession;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
+import com.android.tv.dvr.InputTaskScheduler.HandlerWrapper;
import com.android.tv.util.Clock;
import com.android.tv.util.Utils;
+import java.util.Comparator;
import java.util.concurrent.TimeUnit;
/**
@@ -40,22 +51,66 @@ import java.util.concurrent.TimeUnit;
* There is only one looper so messages must be handled quickly or start a separate thread.
*/
@WorkerThread
-class RecordingTask extends TvRecordingClient.RecordingCallback
- implements Handler.Callback, DvrManager.Listener {
+@VisibleForTesting
+@TargetApi(Build.VERSION_CODES.N)
+public class RecordingTask extends RecordingCallback implements Handler.Callback,
+ DvrManager.Listener {
private static final String TAG = "RecordingTask";
private static final boolean DEBUG = false;
- @VisibleForTesting
- static final int MESSAGE_INIT = 1;
- @VisibleForTesting
- static final int MESSAGE_START_RECORDING = 2;
- @VisibleForTesting
- static final int MESSAGE_STOP_RECORDING = 3;
+ /**
+ * Compares the end time in ascending order.
+ */
+ public static final Comparator<RecordingTask> END_TIME_COMPARATOR
+ = new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getEndTimeMs(), rhs.getEndTimeMs());
+ }
+ };
+
+ /**
+ * Compares ID in ascending order.
+ */
+ public static final Comparator<RecordingTask> ID_COMPARATOR
+ = new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getScheduleId(), rhs.getScheduleId());
+ }
+ };
+
+ /**
+ * Compares the priority in ascending order.
+ */
+ public static final Comparator<RecordingTask> PRIORITY_COMPARATOR
+ = new Comparator<RecordingTask>() {
+ @Override
+ public int compare(RecordingTask lhs, RecordingTask rhs) {
+ return Long.compare(lhs.getPriority(), rhs.getPriority());
+ }
+ };
@VisibleForTesting
- static final long MS_BEFORE_START = TimeUnit.SECONDS.toMillis(5);
+ static final int MSG_INITIALIZE = 1;
@VisibleForTesting
- static final long MS_AFTER_END = TimeUnit.SECONDS.toMillis(5);
+ static final int MSG_START_RECORDING = 2;
+ @VisibleForTesting
+ static final int MSG_STOP_RECORDING = 3;
+ /**
+ * Message to update schedule.
+ */
+ public static final int MSG_UDPATE_SCHEDULE = 4;
+
+ /**
+ * The time when the start command will be sent before the recording starts.
+ */
+ public static final long RECORDING_EARLY_START_OFFSET_MS = TimeUnit.SECONDS.toMillis(3);
+ /**
+ * If the recording starts later than the scheduled start time or ends before the scheduled end
+ * time, it's considered as clipped.
+ */
+ private static final long CLIPPED_THRESHOLD_MS = TimeUnit.MINUTES.toMillis(5);
@VisibleForTesting
enum State {
@@ -63,27 +118,32 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
SESSION_ACQUIRED,
CONNECTION_PENDING,
CONNECTED,
- RECORDING_START_REQUESTED,
RECORDING_STARTED,
RECORDING_STOP_REQUESTED,
+ FINISHED,
ERROR,
RELEASED,
}
- private final DvrSessionManager mSessionManager;
+ private final InputSessionManager mSessionManager;
private final DvrManager mDvrManager;
+ private final Context mContext;
private final WritableDvrDataManager mDataManager;
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
- private TvRecordingClient mTvRecordingClient;
+ private RecordingSession mRecordingSession;
private Handler mHandler;
private ScheduledRecording mScheduledRecording;
private final Channel mChannel;
private State mState = State.NOT_STARTED;
private final Clock mClock;
+ private boolean mStartedWithClipping;
+ private Uri mRecordedProgramUri;
+ private boolean mCanceled;
- RecordingTask(ScheduledRecording scheduledRecording, Channel channel,
- DvrManager dvrManager, DvrSessionManager sessionManager,
+ RecordingTask(Context context, ScheduledRecording scheduledRecording, Channel channel,
+ DvrManager dvrManager, InputSessionManager sessionManager,
WritableDvrDataManager dataManager, Clock clock) {
+ mContext = context;
mScheduledRecording = scheduledRecording;
mChannel = channel;
mSessionManager = sessionManager;
@@ -101,27 +161,30 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
@Override
public boolean handleMessage(Message msg) {
if (DEBUG) Log.d(TAG, "handleMessage " + msg);
- SoftPreconditions
- .checkState(msg.what == Scheduler.HandlerWrapper.MESSAGE_REMOVE || mHandler != null,
- TAG, "Null handler trying to handle " + msg);
+ SoftPreconditions.checkState(msg.what == HandlerWrapper.MESSAGE_REMOVE || mHandler != null,
+ TAG, "Null handler trying to handle " + msg);
try {
switch (msg.what) {
- case MESSAGE_INIT:
+ case MSG_INITIALIZE:
handleInit();
break;
- case MESSAGE_START_RECORDING:
+ case MSG_START_RECORDING:
handleStartRecording();
break;
- case MESSAGE_STOP_RECORDING:
+ case MSG_STOP_RECORDING:
handleStopRecording();
break;
- case Scheduler.HandlerWrapper.MESSAGE_REMOVE:
- // Clear the handler
+ case MSG_UDPATE_SCHEDULE:
+ handleUpdateSchedule((ScheduledRecording) msg.obj);
+ break;
+ case HandlerWrapper.MESSAGE_REMOVE:
+ mHandler.removeCallbacksAndMessages(null);
mHandler = null;
release();
return false;
default:
SoftPreconditions.checkArgument(false, TAG, "unexpected message type " + msg);
+ break;
}
return true;
} catch (Exception e) {
@@ -132,54 +195,91 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
}
@Override
+ public void onDisconnected(String inputId) {
+ if (DEBUG) Log.d(TAG, "onDisconnected(" + inputId + ")");
+ if (mRecordingSession != null && mState != State.FINISHED) {
+ failAndQuit();
+ }
+ }
+
+ @Override
+ public void onConnectionFailed(String inputId) {
+ if (DEBUG) Log.d(TAG, "onConnectionFailed(" + inputId + ")");
+ if (mRecordingSession != null) {
+ failAndQuit();
+ }
+ }
+
+ @Override
public void onTuned(Uri channelUri) {
- if (DEBUG) {
- Log.d(TAG, "onTuned");
+ if (DEBUG) Log.d(TAG, "onTuned");
+ if (mRecordingSession == null) {
+ return;
}
- super.onTuned(channelUri);
mState = State.CONNECTED;
- if (mHandler == null || !sendEmptyMessageAtAbsoluteTime(MESSAGE_START_RECORDING,
- mScheduledRecording.getStartTimeMs() - MS_BEFORE_START)) {
- mState = State.ERROR;
- return;
+ if (mHandler == null || !sendEmptyMessageAtAbsoluteTime(MSG_START_RECORDING,
+ mScheduledRecording.getStartTimeMs() - RECORDING_EARLY_START_OFFSET_MS)) {
+ failAndQuit();
}
}
-
@Override
public void onRecordingStopped(Uri recordedProgramUri) {
- super.onRecordingStopped(recordedProgramUri);
- mState = State.CONNECTED;
- updateRecording(ScheduledRecording.buildFrom(mScheduledRecording)
- .setState(ScheduledRecording.STATE_RECORDING_FINISHED).build());
+ if (DEBUG) Log.d(TAG, "onRecordingStopped");
+ if (mRecordingSession == null) {
+ return;
+ }
+ mRecordedProgramUri = recordedProgramUri;
+ mState = State.FINISHED;
+ int state = ScheduledRecording.STATE_RECORDING_FINISHED;
+ if (mStartedWithClipping || mScheduledRecording.getEndTimeMs() - CLIPPED_THRESHOLD_MS
+ > mClock.currentTimeMillis()) {
+ state = ScheduledRecording.STATE_RECORDING_CLIPPED;
+ }
+ updateRecordingState(state);
sendRemove();
+ if (mCanceled) {
+ removeRecordedProgram();
+ }
}
@Override
public void onError(int reason) {
if (DEBUG) Log.d(TAG, "onError reason " + reason);
- super.onError(reason);
- // TODO(dvr) handle success
+ if (mRecordingSession == null) {
+ return;
+ }
switch (reason) {
+ case TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE:
+ mMainThreadHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (TvApplication.getSingletons(mContext).getMainActivityWrapper()
+ .isResumed()) {
+ Toast.makeText(mContext.getApplicationContext(),
+ R.string.dvr_error_insufficient_space_description,
+ Toast.LENGTH_LONG)
+ .show();
+ } else {
+ Utils.setRecordingFailedReason(mContext.getApplicationContext(),
+ TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ }
+ }
+ });
+ // Pass through
default:
- updateRecording(ScheduledRecording.buildFrom(mScheduledRecording)
- .setState(ScheduledRecording.STATE_RECORDING_FAILED)
- .build());
+ failAndQuit();
+ break;
}
- release();
- sendRemove();
}
private void handleInit() {
if (DEBUG) Log.d(TAG, "handleInit " + mScheduledRecording);
- //TODO check recording preconditions
-
if (mScheduledRecording.getEndTimeMs() < mClock.currentTimeMillis()) {
Log.w(TAG, "End time already past, not recording " + mScheduledRecording);
failAndQuit();
return;
}
-
if (mChannel == null) {
Log.w(TAG, "Null channel for " + mScheduledRecording);
failAndQuit();
@@ -193,18 +293,12 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
}
String inputId = mChannel.getInputId();
- if (mSessionManager.canAcquireDvrSession(inputId, mChannel)) {
- mTvRecordingClient = mSessionManager
- .createTvRecordingClient("recordingTask-" + mScheduledRecording.getId(), this,
- mHandler);
- mState = State.SESSION_ACQUIRED;
- } else {
- Log.w(TAG, "Unable to acquire a session for " + mScheduledRecording);
- failAndQuit();
- return;
- }
+ mRecordingSession = mSessionManager.createRecordingSession(inputId,
+ "recordingTask-" + mScheduledRecording.getId(), this,
+ mHandler, mScheduledRecording.getEndTimeMs());
+ mState = State.SESSION_ACQUIRED;
mDvrManager.addListener(this, mHandler);
- mTvRecordingClient.tune(inputId, mChannel.getUri());
+ mRecordingSession.tune(inputId, mChannel.getUri());
mState = State.CONNECTION_PENDING;
}
@@ -218,41 +312,86 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
private void sendRemove() {
if (DEBUG) Log.d(TAG, "sendRemove");
if (mHandler != null) {
- mHandler.sendEmptyMessage(Scheduler.HandlerWrapper.MESSAGE_REMOVE);
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(
+ HandlerWrapper.MESSAGE_REMOVE));
}
}
private void handleStartRecording() {
if (DEBUG) Log.d(TAG, "handleStartRecording " + mScheduledRecording);
- // TODO(DVR) handle errors
long programId = mScheduledRecording.getProgramId();
- mTvRecordingClient.startRecording(programId == ScheduledRecording.ID_NOT_SET ? null
+ mRecordingSession.startRecording(programId == ScheduledRecording.ID_NOT_SET ? null
: TvContract.buildProgramUri(programId));
- updateRecording(ScheduledRecording.buildFrom(mScheduledRecording)
- .setState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS).build());
+ updateRecordingState(ScheduledRecording.STATE_RECORDING_IN_PROGRESS);
+ // If it starts late, it's clipped.
+ if (mScheduledRecording.getStartTimeMs() + CLIPPED_THRESHOLD_MS
+ < mClock.currentTimeMillis()) {
+ mStartedWithClipping = true;
+ }
mState = State.RECORDING_STARTED;
- if (mHandler == null || !sendEmptyMessageAtAbsoluteTime(MESSAGE_STOP_RECORDING,
- mScheduledRecording.getEndTimeMs() + MS_AFTER_END)) {
- mState = State.ERROR;
- return;
+ if (!sendEmptyMessageAtAbsoluteTime(MSG_STOP_RECORDING,
+ mScheduledRecording.getEndTimeMs())) {
+ failAndQuit();
}
}
private void handleStopRecording() {
if (DEBUG) Log.d(TAG, "handleStopRecording " + mScheduledRecording);
- mTvRecordingClient.stopRecording();
+ mRecordingSession.stopRecording();
mState = State.RECORDING_STOP_REQUESTED;
}
+ private void handleUpdateSchedule(ScheduledRecording schedule) {
+ mScheduledRecording = schedule;
+ // Check end time only. The start time is checked in InputTaskScheduler.
+ if (schedule.getEndTimeMs() != mScheduledRecording.getEndTimeMs()) {
+ if (mRecordingSession != null) {
+ mRecordingSession.setEndTimeMs(schedule.getEndTimeMs());
+ }
+ if (mState == State.RECORDING_STARTED) {
+ mHandler.removeMessages(MSG_STOP_RECORDING);
+ if (!sendEmptyMessageAtAbsoluteTime(MSG_STOP_RECORDING, schedule.getEndTimeMs())) {
+ failAndQuit();
+ }
+ }
+ }
+ }
+
@VisibleForTesting
State getState() {
return mState;
}
+ private long getScheduleId() {
+ return mScheduledRecording.getId();
+ }
+
+ /**
+ * Returns the priority.
+ */
+ public long getPriority() {
+ return mScheduledRecording.getPriority();
+ }
+
+ /**
+ * Returns the start time of the recording.
+ */
+ public long getStartTimeMs() {
+ return mScheduledRecording.getStartTimeMs();
+ }
+
+ /**
+ * Returns the end time of the recording.
+ */
+ public long getEndTimeMs() {
+ return mScheduledRecording.getEndTimeMs();
+ }
+
private void release() {
- if (mTvRecordingClient != null) {
- mSessionManager.releaseTvRecordingClient(mTvRecordingClient);
+ if (mRecordingSession != null) {
+ mSessionManager.releaseRecordingSession(mRecordingSession);
+ mRecordingSession = null;
}
mDvrManager.removeListener(this);
}
@@ -268,22 +407,24 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
}
private void updateRecordingState(@ScheduledRecording.RecordingState int state) {
- updateRecording(ScheduledRecording.buildFrom(mScheduledRecording).setState(state).build());
- }
-
- @VisibleForTesting
- static Uri getIdAsMediaUri(ScheduledRecording scheduledRecording) {
- // TODO define the URI format
- return new Uri.Builder().appendPath(String.valueOf(scheduledRecording.getId())).build();
- }
-
- private void updateRecording(ScheduledRecording updatedScheduledRecording) {
- if (DEBUG) Log.d(TAG, "updateScheduledRecording " + updatedScheduledRecording);
- mScheduledRecording = updatedScheduledRecording;
- mMainThreadHandler.post(new Runnable() {
+ if (DEBUG) Log.d(TAG, "Updating the state of " + mScheduledRecording + " to " + state);
+ mScheduledRecording = ScheduledRecording.buildFrom(mScheduledRecording).setState(state)
+ .build();
+ runOnMainThread(new Runnable() {
@Override
public void run() {
- mDataManager.updateScheduledRecording(mScheduledRecording);
+ ScheduledRecording schedule = mDataManager.getScheduledRecording(
+ mScheduledRecording.getId());
+ if (schedule == null) {
+ // Schedule has been deleted. Delete the recorded program.
+ removeRecordedProgram();
+ } else {
+ // Update the state based on the object in DataManager in case when it has been
+ // updated. mScheduledRecording will be updated from
+ // onScheduledRecordingStateChanged.
+ mDataManager.updateScheduledRecording(ScheduledRecording.buildFrom(schedule)
+ .setState(state).build());
+ }
}
});
}
@@ -293,9 +434,24 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
if (recording.getId() != mScheduledRecording.getId()) {
return;
}
+ stop();
+ }
+
+ /**
+ * Starts the task.
+ */
+ public void start() {
+ mHandler.sendEmptyMessage(MSG_INITIALIZE);
+ }
+
+ /**
+ * Stops the task.
+ */
+ public void stop() {
+ if (DEBUG) Log.d(TAG, "stop");
switch (mState) {
case RECORDING_STARTED:
- mHandler.removeMessages(MESSAGE_STOP_RECORDING);
+ mHandler.removeMessages(MSG_STOP_RECORDING);
handleStopRecording();
break;
case RECORDING_STOP_REQUESTED:
@@ -305,7 +461,7 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
case SESSION_ACQUIRED:
case CONNECTION_PENDING:
case CONNECTED:
- case RECORDING_START_REQUESTED:
+ case FINISHED:
case ERROR:
case RELEASED:
default:
@@ -314,8 +470,50 @@ class RecordingTask extends TvRecordingClient.RecordingCallback
}
}
+ /**
+ * Cancels the task
+ */
+ public void cancel() {
+ if (DEBUG) Log.d(TAG, "cancel");
+ mCanceled = true;
+ stop();
+ removeRecordedProgram();
+ }
+
+ /**
+ * Clean up the task.
+ */
+ public void cleanUp() {
+ if (mState == State.RECORDING_STARTED || mState == State.RECORDING_STOP_REQUESTED) {
+ updateRecordingState(ScheduledRecording.STATE_RECORDING_FAILED);
+ }
+ release();
+ if (mHandler != null) {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+ }
+
@Override
public String toString() {
return getClass().getName() + "(" + mScheduledRecording + ")";
}
+
+ private void removeRecordedProgram() {
+ runOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ if (mRecordedProgramUri != null) {
+ mDvrManager.removeRecordedProgram(mRecordedProgramUri);
+ }
+ }
+ });
+ }
+
+ private void runOnMainThread(Runnable runnable) {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ runnable.run();
+ } else {
+ mMainThreadHandler.post(runnable);
+ }
+ }
}
diff --git a/src/com/android/tv/dvr/ScheduledProgramReaper.java b/src/com/android/tv/dvr/ScheduledProgramReaper.java
index 9053eaec..cd79a631 100644
--- a/src/com/android/tv/dvr/ScheduledProgramReaper.java
+++ b/src/com/android/tv/dvr/ScheduledProgramReaper.java
@@ -21,6 +21,7 @@ import android.support.annotation.VisibleForTesting;
import com.android.tv.util.Clock;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -42,12 +43,25 @@ class ScheduledProgramReaper implements Runnable {
@Override
@MainThread
public void run() {
- List<ScheduledRecording> recordings = mDvrDataManager.getAllScheduledRecordings();
long cutoff = mClock.currentTimeMillis() - TimeUnit.DAYS.toMillis(DAYS);
- for (ScheduledRecording r : recordings) {
+ List<ScheduledRecording> toRemove = new ArrayList<>();
+ for (ScheduledRecording r : mDvrDataManager.getAllScheduledRecordings()) {
+ // Do not remove the schedules if it belongs to the series recording and was finished
+ // successfully. The schedule is necessary for checking the scheduled episode of the
+ // series recording.
+ if (r.getEndTimeMs() < cutoff
+ && (r.getSeriesRecordingId() == SeriesRecording.ID_NOT_SET
+ || r.getState() != ScheduledRecording.STATE_RECORDING_FINISHED)) {
+ toRemove.add(r);
+ }
+ }
+ for (ScheduledRecording r : mDvrDataManager.getDeletedSchedules()) {
if (r.getEndTimeMs() < cutoff) {
- mDvrDataManager.removeScheduledRecording(r);
+ toRemove.add(r);
}
}
+ if (!toRemove.isEmpty()) {
+ mDvrDataManager.removeScheduledRecording(ScheduledRecording.toArray(toRemove));
+ }
}
}
diff --git a/src/com/android/tv/dvr/ScheduledRecording.java b/src/com/android/tv/dvr/ScheduledRecording.java
index 01b00459..2bda10ea 100644
--- a/src/com/android/tv/dvr/ScheduledRecording.java
+++ b/src/com/android/tv/dvr/ScheduledRecording.java
@@ -17,87 +17,169 @@
package com.android.tv.dvr;
import android.content.ContentValues;
+import android.content.Context;
import android.database.Cursor;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.support.annotation.IntDef;
import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
import android.util.Range;
+import com.android.tv.R;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
-import com.android.tv.dvr.provider.DvrContract;
+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;
import java.util.Comparator;
+import java.util.Objects;
/**
* A data class for one recording contents.
*/
@VisibleForTesting
-public final class ScheduledRecording {
- private static final String TAG = "Recording";
+public final class ScheduledRecording implements Parcelable {
+ private static final String TAG = "ScheduledRecording";
- public static final String RECORDING_ID_EXTRA = "extra.dvr.recording.id"; //TODO(DVR) move
- public static final String PARAM_INPUT_ID = "input_id";
+ /**
+ * Indicates that the ID is not assigned yet.
+ */
+ public static final long ID_NOT_SET = 0;
- public static final long ID_NOT_SET = -1;
+ /**
+ * The default priority of the recording.
+ */
+ public static final long DEFAULT_PRIORITY = Long.MAX_VALUE >> 1;
- public static final Comparator<ScheduledRecording> START_TIME_COMPARATOR = new Comparator<ScheduledRecording>() {
+ /**
+ * Compares the start time in ascending order.
+ */
+ public static final Comparator<ScheduledRecording> START_TIME_COMPARATOR
+ = new Comparator<ScheduledRecording>() {
@Override
public int compare(ScheduledRecording lhs, ScheduledRecording rhs) {
return Long.compare(lhs.mStartTimeMs, rhs.mStartTimeMs);
}
};
- public static final Comparator<ScheduledRecording> PRIORITY_COMPARATOR = new Comparator<ScheduledRecording>() {
+ /**
+ * Compares the end time in ascending order.
+ */
+ public static final Comparator<ScheduledRecording> END_TIME_COMPARATOR
+ = new Comparator<ScheduledRecording>() {
@Override
public int compare(ScheduledRecording lhs, ScheduledRecording rhs) {
- int value = Long.compare(lhs.mPriority, rhs.mPriority);
- if (value == 0) {
- value = Long.compare(lhs.mId, rhs.mId);
- }
- return value;
+ return Long.compare(lhs.mEndTimeMs, rhs.mEndTimeMs);
+ }
+ };
+
+ /**
+ * Compares ID in ascending order. The schedule with the larger ID was created later.
+ */
+ public static final Comparator<ScheduledRecording> ID_COMPARATOR
+ = new Comparator<ScheduledRecording>() {
+ @Override
+ public int compare(ScheduledRecording lhs, ScheduledRecording rhs) {
+ return Long.compare(lhs.mId, rhs.mId);
}
};
- public static final Comparator<ScheduledRecording> START_TIME_THEN_PRIORITY_COMPARATOR
+ /**
+ * Compares the priority in ascending order.
+ */
+ public static final Comparator<ScheduledRecording> PRIORITY_COMPARATOR
= new Comparator<ScheduledRecording>() {
@Override
public int compare(ScheduledRecording lhs, ScheduledRecording rhs) {
- int value = START_TIME_COMPARATOR.compare(lhs, rhs);
- if (value == 0) {
- value = PRIORITY_COMPARATOR.compare(lhs, rhs);
- }
- return value;
+ return Long.compare(lhs.mPriority, rhs.mPriority);
}
};
- public static Builder builder(Program p) {
+ /**
+ * Compares start time in ascending order and then priority in descending order and then ID in
+ * descending order.
+ */
+ public static final Comparator<ScheduledRecording> START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR
+ = new CompositeComparator<>(START_TIME_COMPARATOR, PRIORITY_COMPARATOR.reversed(),
+ ID_COMPARATOR.reversed());
+
+ /**
+ * Builds scheduled recordings from programs.
+ */
+ public static Builder builder(String inputId, Program p) {
return new Builder()
- .setStartTime(p.getStartTimeUtcMillis()).setEndTime(p.getEndTimeUtcMillis())
+ .setInputId(inputId)
+ .setChannelId(p.getChannelId())
+ .setStartTimeMs(p.getStartTimeUtcMillis()).setEndTimeMs(p.getEndTimeUtcMillis())
.setProgramId(p.getId())
+ .setProgramTitle(p.getTitle())
+ .setSeasonNumber(p.getSeasonNumber())
+ .setEpisodeNumber(p.getEpisodeNumber())
+ .setEpisodeTitle(p.getEpisodeTitle())
+ .setProgramDescription(p.getDescription())
+ .setProgramLongDescription(p.getLongDescription())
+ .setProgramPosterArtUri(p.getPosterArtUri())
+ .setProgramThumbnailUri(p.getThumbnailUri())
.setType(TYPE_PROGRAM);
}
- public static Builder builder(long startTime, long endTime) {
+ public static Builder builder(String inputId, long channelId, long startTime, long endTime) {
return new Builder()
- .setStartTime(startTime)
- .setEndTime(endTime)
+ .setInputId(inputId)
+ .setChannelId(channelId)
+ .setStartTimeMs(startTime)
+ .setEndTimeMs(endTime)
.setType(TYPE_TIMED);
}
+ /**
+ * Creates a new Builder with the values set from the {@link RecordedProgram}.
+ */
+ @VisibleForTesting
+ public static Builder builder(RecordedProgram p) {
+ boolean isProgramRecording = !TextUtils.isEmpty(p.getTitle());
+ return new Builder()
+ .setInputId(p.getInputId())
+ .setChannelId(p.getChannelId())
+ .setType(isProgramRecording ? TYPE_PROGRAM : TYPE_TIMED)
+ .setStartTimeMs(p.getStartTimeUtcMillis())
+ .setEndTimeMs(p.getEndTimeUtcMillis())
+ .setProgramTitle(p.getTitle())
+ .setSeasonNumber(p.getSeasonNumber())
+ .setEpisodeNumber(p.getEpisodeNumber())
+ .setEpisodeTitle(p.getEpisodeTitle())
+ .setProgramDescription(p.getDescription())
+ .setProgramLongDescription(p.getLongDescription())
+ .setProgramPosterArtUri(p.getPosterArtUri())
+ .setProgramThumbnailUri(p.getThumbnailUri())
+ .setState(STATE_RECORDING_FINISHED);
+ }
+
public static final class Builder {
private long mId = ID_NOT_SET;
- private long mPriority = Long.MAX_VALUE;
+ private long mPriority = DvrScheduleManager.DEFAULT_PRIORITY;
+ private String mInputId;
private long mChannelId;
private long mProgramId = ID_NOT_SET;
+ private String mProgramTitle;
private @RecordingType int mType;
- private long mStartTime;
- private long mEndTime;
+ private long mStartTimeMs;
+ private long mEndTimeMs;
+ private String mSeasonNumber;
+ private String mEpisodeNumber;
+ private String mEpisodeTitle;
+ private String mProgramDescription;
+ private String mProgramLongDescription;
+ private String mProgramPosterArtUri;
+ private String mProgramThumbnailUri;
private @RecordingState int mState;
- private SeasonRecording mParentSeasonRecording;
+ private long mSeriesRecordingId = ID_NOT_SET;
private Builder() { }
@@ -111,6 +193,11 @@ public final class ScheduledRecording {
return this;
}
+ public Builder setInputId(String inputId) {
+ mInputId = inputId;
+ return this;
+ }
+
public Builder setChannelId(long channelId) {
mChannelId = channelId;
return this;
@@ -121,18 +208,58 @@ public final class ScheduledRecording {
return this;
}
+ public Builder setProgramTitle(String programTitle) {
+ mProgramTitle = programTitle;
+ return this;
+ }
+
private Builder setType(@RecordingType int type) {
mType = type;
return this;
}
- public Builder setStartTime(long startTime) {
- mStartTime = startTime;
+ public Builder setStartTimeMs(long startTimeMs) {
+ mStartTimeMs = startTimeMs;
+ return this;
+ }
+
+ public Builder setEndTimeMs(long endTimeMs) {
+ mEndTimeMs = endTimeMs;
+ return this;
+ }
+
+ public Builder setSeasonNumber(String seasonNumber) {
+ mSeasonNumber = seasonNumber;
+ return this;
+ }
+
+ public Builder setEpisodeNumber(String episodeNumber) {
+ mEpisodeNumber = episodeNumber;
return this;
}
- public Builder setEndTime(long endTime) {
- mEndTime = endTime;
+ public Builder setEpisodeTitle(String episodeTitle) {
+ mEpisodeTitle = episodeTitle;
+ return this;
+ }
+
+ public Builder setProgramDescription(String description) {
+ mProgramDescription = description;
+ return this;
+ }
+
+ public Builder setProgramLongDescription(String longDescription) {
+ mProgramLongDescription = longDescription;
+ return this;
+ }
+
+ public Builder setProgramPosterArtUri(String programPosterArtUri) {
+ mProgramPosterArtUri = programPosterArtUri;
+ return this;
+ }
+
+ public Builder setProgramThumbnailUri(String programThumbnailUri) {
+ mProgramThumbnailUri = programThumbnailUri;
return this;
}
@@ -141,14 +268,16 @@ public final class ScheduledRecording {
return this;
}
- public Builder setParentSeasonRecording(SeasonRecording parentSeasonRecording) {
- mParentSeasonRecording = parentSeasonRecording;
+ public Builder setSeriesRecordingId(long seriesRecordingId) {
+ mSeriesRecordingId = seriesRecordingId;
return this;
}
public ScheduledRecording build() {
- return new ScheduledRecording(mId, mPriority, mChannelId, mProgramId, mType, mStartTime,
- mEndTime, mState, mParentSeasonRecording);
+ return new ScheduledRecording(mId, mPriority, mInputId, mChannelId, mProgramId,
+ mProgramTitle, mType, mStartTimeMs, mEndTimeMs, mSeasonNumber, mEpisodeNumber,
+ mEpisodeTitle, mProgramDescription, mProgramLongDescription,
+ mProgramPosterArtUri, mProgramThumbnailUri, mState, mSeriesRecordingId);
}
}
@@ -157,22 +286,37 @@ public final class ScheduledRecording {
*/
public static Builder buildFrom(ScheduledRecording orig) {
return new Builder()
- .setId(orig.mId).setChannelId(orig.mChannelId)
- .setEndTime(orig.mEndTimeMs).setParentSeasonRecording(orig.mParentSeasonRecording)
+ .setId(orig.mId)
+ .setInputId(orig.mInputId)
+ .setChannelId(orig.mChannelId)
+ .setEndTimeMs(orig.mEndTimeMs)
+ .setSeriesRecordingId(orig.mSeriesRecordingId)
+ .setPriority(orig.mPriority)
.setProgramId(orig.mProgramId)
- .setStartTime(orig.mStartTimeMs).setState(orig.mState).setType(orig.mType);
+ .setProgramTitle(orig.mProgramTitle)
+ .setStartTimeMs(orig.mStartTimeMs)
+ .setSeasonNumber(orig.getSeasonNumber())
+ .setEpisodeNumber(orig.getEpisodeNumber())
+ .setEpisodeTitle(orig.getEpisodeTitle())
+ .setProgramDescription(orig.getProgramDescription())
+ .setProgramLongDescription(orig.getProgramLongDescription())
+ .setProgramPosterArtUri(orig.getProgramPosterArtUri())
+ .setProgramThumbnailUri(orig.getProgramThumbnailUri())
+ .setState(orig.mState).setType(orig.mType);
}
@Retention(RetentionPolicy.SOURCE)
- @IntDef({STATE_RECORDING_NOT_STARTED, STATE_RECORDING_IN_PROGRESS,
- STATE_RECORDING_UNEXPECTEDLY_STOPPED, STATE_RECORDING_FINISHED, STATE_RECORDING_FAILED})
+ @IntDef({STATE_RECORDING_NOT_STARTED, STATE_RECORDING_IN_PROGRESS, STATE_RECORDING_FINISHED,
+ STATE_RECORDING_FAILED, STATE_RECORDING_CLIPPED, STATE_RECORDING_DELETED,
+ STATE_RECORDING_CANCELED})
public @interface RecordingState {}
public static final int STATE_RECORDING_NOT_STARTED = 0;
public static final int STATE_RECORDING_IN_PROGRESS = 1;
- @Deprecated // It is not used.
- public static final int STATE_RECORDING_UNEXPECTEDLY_STOPPED = 2;
- public static final int STATE_RECORDING_FINISHED = 3;
- public static final int STATE_RECORDING_FAILED = 4;
+ public static final int STATE_RECORDING_FINISHED = 2;
+ public static final int STATE_RECORDING_FAILED = 3;
+ public static final int STATE_RECORDING_CLIPPED = 4;
+ public static final int STATE_RECORDING_DELETED = 5;
+ public static final int STATE_RECORDING_CANCELED = 6;
@Retention(RetentionPolicy.SOURCE)
@IntDef({TYPE_TIMED, TYPE_PROGRAM})
@@ -180,27 +324,39 @@ public final class ScheduledRecording {
/**
* Record with given time range.
*/
- static final int TYPE_TIMED = 1;
+ public static final int TYPE_TIMED = 1;
/**
* Record with a given program.
*/
- static final int TYPE_PROGRAM = 2;
+ public static final int TYPE_PROGRAM = 2;
@RecordingType private final int mType;
/**
- * Use this projection if you want to create {@link ScheduledRecording} object using {@link #fromCursor}.
+ * Use this projection if you want to create {@link ScheduledRecording} object using
+ * {@link #fromCursor}.
*/
public static final String[] PROJECTION = {
- // Columns must match what is read in Recording.fromCursor()
- DvrContract.Recordings._ID,
- DvrContract.Recordings.COLUMN_PRIORITY,
- DvrContract.Recordings.COLUMN_TYPE,
- DvrContract.Recordings.COLUMN_CHANNEL_ID,
- DvrContract.Recordings.COLUMN_PROGRAM_ID,
- DvrContract.Recordings.COLUMN_START_TIME_UTC_MILLIS,
- DvrContract.Recordings.COLUMN_END_TIME_UTC_MILLIS,
- DvrContract.Recordings.COLUMN_STATE};
+ // Columns must match what is read in #fromCursor
+ Schedules._ID,
+ Schedules.COLUMN_PRIORITY,
+ Schedules.COLUMN_TYPE,
+ Schedules.COLUMN_INPUT_ID,
+ Schedules.COLUMN_CHANNEL_ID,
+ Schedules.COLUMN_PROGRAM_ID,
+ Schedules.COLUMN_PROGRAM_TITLE,
+ Schedules.COLUMN_START_TIME_UTC_MILLIS,
+ Schedules.COLUMN_END_TIME_UTC_MILLIS,
+ Schedules.COLUMN_SEASON_NUMBER,
+ Schedules.COLUMN_EPISODE_NUMBER,
+ Schedules.COLUMN_EPISODE_TITLE,
+ Schedules.COLUMN_PROGRAM_DESCRIPTION,
+ Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION,
+ Schedules.COLUMN_PROGRAM_POST_ART_URI,
+ Schedules.COLUMN_PROGRAM_THUMBNAIL_URI,
+ Schedules.COLUMN_STATE,
+ Schedules.COLUMN_SERIES_RECORDING_ID};
+
/**
* Creates {@link ScheduledRecording} object from the given {@link Cursor}.
*/
@@ -210,65 +366,145 @@ public final class ScheduledRecording {
.setId(c.getLong(++index))
.setPriority(c.getLong(++index))
.setType(recordingType(c.getString(++index)))
+ .setInputId(c.getString(++index))
.setChannelId(c.getLong(++index))
.setProgramId(c.getLong(++index))
- .setStartTime(c.getLong(++index))
- .setEndTime(c.getLong(++index))
+ .setProgramTitle(c.getString(++index))
+ .setStartTimeMs(c.getLong(++index))
+ .setEndTimeMs(c.getLong(++index))
+ .setSeasonNumber(c.getString(++index))
+ .setEpisodeNumber(c.getString(++index))
+ .setEpisodeTitle(c.getString(++index))
+ .setProgramDescription(c.getString(++index))
+ .setProgramLongDescription(c.getString(++index))
+ .setProgramPosterArtUri(c.getString(++index))
+ .setProgramThumbnailUri(c.getString(++index))
.setState(recordingState(c.getString(++index)))
+ .setSeriesRecordingId(c.getLong(++index))
.build();
}
public static ContentValues toContentValues(ScheduledRecording r) {
ContentValues values = new ContentValues();
- values.put(DvrContract.Recordings.COLUMN_CHANNEL_ID, r.getChannelId());
- values.put(DvrContract.Recordings.COLUMN_PROGRAM_ID, r.getProgramId());
- values.put(DvrContract.Recordings.COLUMN_PRIORITY, r.getPriority());
- values.put(DvrContract.Recordings.COLUMN_START_TIME_UTC_MILLIS, r.getStartTimeMs());
- values.put(DvrContract.Recordings.COLUMN_END_TIME_UTC_MILLIS, r.getEndTimeMs());
- values.put(DvrContract.Recordings.COLUMN_STATE, r.getState());
- values.put(DvrContract.Recordings.COLUMN_TYPE, r.getType());
+ if (r.getId() != ID_NOT_SET) {
+ values.put(Schedules._ID, r.getId());
+ }
+ values.put(Schedules.COLUMN_INPUT_ID, r.getInputId());
+ values.put(Schedules.COLUMN_CHANNEL_ID, r.getChannelId());
+ values.put(Schedules.COLUMN_PROGRAM_ID, r.getProgramId());
+ values.put(Schedules.COLUMN_PROGRAM_TITLE, r.getProgramTitle());
+ values.put(Schedules.COLUMN_PRIORITY, r.getPriority());
+ values.put(Schedules.COLUMN_START_TIME_UTC_MILLIS, r.getStartTimeMs());
+ values.put(Schedules.COLUMN_END_TIME_UTC_MILLIS, r.getEndTimeMs());
+ values.put(Schedules.COLUMN_SEASON_NUMBER, r.getSeasonNumber());
+ values.put(Schedules.COLUMN_EPISODE_NUMBER, r.getEpisodeNumber());
+ values.put(Schedules.COLUMN_EPISODE_TITLE, r.getEpisodeTitle());
+ values.put(Schedules.COLUMN_PROGRAM_DESCRIPTION, r.getProgramDescription());
+ values.put(Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION, r.getProgramLongDescription());
+ values.put(Schedules.COLUMN_PROGRAM_POST_ART_URI, r.getProgramPosterArtUri());
+ values.put(Schedules.COLUMN_PROGRAM_THUMBNAIL_URI, r.getProgramThumbnailUri());
+ values.put(Schedules.COLUMN_STATE, recordingState(r.getState()));
+ values.put(Schedules.COLUMN_TYPE, recordingType(r.getType()));
+ if (r.getSeriesRecordingId() != ID_NOT_SET) {
+ values.put(Schedules.COLUMN_SERIES_RECORDING_ID, r.getSeriesRecordingId());
+ } else {
+ values.putNull(Schedules.COLUMN_SERIES_RECORDING_ID);
+ }
return values;
}
+ public static ScheduledRecording fromParcel(Parcel in) {
+ return new Builder()
+ .setId(in.readLong())
+ .setPriority(in.readLong())
+ .setInputId(in.readString())
+ .setChannelId(in.readLong())
+ .setProgramId(in.readLong())
+ .setProgramTitle(in.readString())
+ .setType(in.readInt())
+ .setStartTimeMs(in.readLong())
+ .setEndTimeMs(in.readLong())
+ .setSeasonNumber(in.readString())
+ .setEpisodeNumber(in.readString())
+ .setEpisodeTitle(in.readString())
+ .setProgramDescription(in.readString())
+ .setProgramLongDescription(in.readString())
+ .setProgramPosterArtUri(in.readString())
+ .setProgramThumbnailUri(in.readString())
+ .setState(in.readInt())
+ .setSeriesRecordingId(in.readLong())
+ .build();
+ }
+
+ public static final Parcelable.Creator<ScheduledRecording> CREATOR =
+ new Parcelable.Creator<ScheduledRecording>() {
+ @Override
+ public ScheduledRecording createFromParcel(Parcel in) {
+ return ScheduledRecording.fromParcel(in);
+ }
+
+ @Override
+ public ScheduledRecording[] newArray(int size) {
+ return new ScheduledRecording[size];
+ }
+ };
+
/**
* The ID internal to Live TV
*/
- private final long mId;
+ private long mId;
/**
* The priority of this recording.
*
- * <p> The lowest number is recorded first. If there is a tie in priority then the lower id
+ * <p> The highest number is recorded first. If there is a tie in priority then the higher id
* wins.
*/
private final long mPriority;
-
+ private final String mInputId;
private final long mChannelId;
/**
* Optional id of the associated program.
- *
*/
private final long mProgramId;
+ private final String mProgramTitle;
private final long mStartTimeMs;
private final long mEndTimeMs;
+ private final String mSeasonNumber;
+ private final String mEpisodeNumber;
+ private final String mEpisodeTitle;
+ private final String mProgramDescription;
+ private final String mProgramLongDescription;
+ private final String mProgramPosterArtUri;
+ private final String mProgramThumbnailUri;
@RecordingState private final int mState;
+ private final long mSeriesRecordingId;
- private final SeasonRecording mParentSeasonRecording;
-
- private ScheduledRecording(long id, long priority, long channelId, long programId,
- @RecordingType int type, long startTime, long endTime,
- @RecordingState int state, SeasonRecording parentSeasonRecording) {
+ private ScheduledRecording(long id, long priority, String inputId, long channelId, long programId,
+ String programTitle, @RecordingType int type, long startTime, long endTime,
+ String seasonNumber, String episodeNumber, String episodeTitle,
+ String programDescription, String programLongDescription, String programPosterArtUri,
+ String programThumbnailUri, @RecordingState int state, long seriesRecordingId) {
mId = id;
mPriority = priority;
+ mInputId = inputId;
mChannelId = channelId;
mProgramId = programId;
+ mProgramTitle = programTitle;
mType = type;
mStartTimeMs = startTime;
mEndTimeMs = endTime;
+ mSeasonNumber = seasonNumber;
+ mEpisodeNumber = episodeNumber;
+ mEpisodeTitle = episodeTitle;
+ mProgramDescription = programDescription;
+ mProgramLongDescription = programLongDescription;
+ mProgramPosterArtUri = programPosterArtUri;
+ mProgramThumbnailUri = programThumbnailUri;
mState = state;
- mParentSeasonRecording = parentSeasonRecording;
+ mSeriesRecordingId = seriesRecordingId;
}
/**
@@ -281,6 +517,13 @@ public final class ScheduledRecording {
}
/**
+ * Returns schedules' input id.
+ */
+ public String getInputId() {
+ return mInputId;
+ }
+
+ /**
* Returns recorded {@link Channel}.
*/
public long getChannelId() {
@@ -295,6 +538,13 @@ public final class ScheduledRecording {
}
/**
+ * Return the optional program Title
+ */
+ public String getProgramTitle() {
+ return mProgramTitle;
+ }
+
+ /**
* Returns started time.
*/
public long getStartTimeMs() {
@@ -309,6 +559,55 @@ public final class ScheduledRecording {
}
/**
+ * Returns the season number.
+ */
+ public String getSeasonNumber() {
+ return mSeasonNumber;
+ }
+
+ /**
+ * Returns the episode number.
+ */
+ public String getEpisodeNumber() {
+ return mEpisodeNumber;
+ }
+
+ /**
+ * Returns the episode title.
+ */
+ public String getEpisodeTitle() {
+ return mEpisodeTitle;
+ }
+
+ /**
+ * Returns the description of program.
+ */
+ public String getProgramDescription() {
+ return mProgramDescription;
+ }
+
+ /**
+ * Returns the long description of program.
+ */
+ public String getProgramLongDescription() {
+ return mProgramLongDescription;
+ }
+
+ /**
+ * Returns the poster uri of program.
+ */
+ public String getProgramPosterArtUri() {
+ return mProgramPosterArtUri;
+ }
+
+ /**
+ * Returns the thumb nail uri of program.
+ */
+ public String getProgramThumbnailUri() {
+ return mProgramThumbnailUri;
+ }
+
+ /**
* Returns duration.
*/
public long getDuration() {
@@ -316,43 +615,83 @@ public final class ScheduledRecording {
}
/**
- * Returns the state. The possible states are {@link #STATE_RECORDING_FINISHED},
- * {@link #STATE_RECORDING_IN_PROGRESS} and {@link #STATE_RECORDING_UNEXPECTEDLY_STOPPED}.
+ * Returns the state. The possible states are {@link #STATE_RECORDING_NOT_STARTED},
+ * {@link #STATE_RECORDING_IN_PROGRESS}, {@link #STATE_RECORDING_FINISHED},
+ * {@link #STATE_RECORDING_FAILED}, {@link #STATE_RECORDING_CLIPPED} and
+ * {@link #STATE_RECORDING_DELETED}.
*/
@RecordingState public int getState() {
return mState;
}
/**
- * Returns {@link SeasonRecording} including this schedule.
+ * Returns the ID of the {@link SeriesRecording} including this schedule.
*/
- public SeasonRecording getParentSeasonRecording() {
- return mParentSeasonRecording;
+ public long getSeriesRecordingId() {
+ return mSeriesRecordingId;
}
public long getId() {
return mId;
}
+ /**
+ * Sets the ID;
+ */
+ public void setId(long id) {
+ mId = id;
+ }
+
public long getPriority() {
return mPriority;
}
/**
+ * Returns season number, episode number and episode title for display.
+ */
+ public String getEpisodeDisplayTitle(Context context) {
+ if (!TextUtils.isEmpty(mEpisodeNumber)) {
+ String episodeTitle = mEpisodeTitle == null ? "" : mEpisodeTitle;
+ if (TextUtils.equals(mSeasonNumber, "0")) {
+ // Do not show "S0: ".
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format_no_season_number),
+ mEpisodeNumber, episodeTitle);
+ } else {
+ return String.format(context.getResources().getString(
+ R.string.display_episode_title_format),
+ mSeasonNumber, mEpisodeNumber, episodeTitle);
+ }
+ }
+ return mEpisodeTitle;
+ }
+
+ /**
+ * Returns the program's title withe its season and episode number.
+ */
+ public String getProgramTitleWithEpisodeNumber(Context context) {
+ if (TextUtils.isEmpty(mProgramTitle)) {
+ return mProgramTitle;
+ }
+ if (TextUtils.isEmpty(mSeasonNumber) || mSeasonNumber.equals("0")) {
+ return TextUtils.isEmpty(mEpisodeNumber) ? mProgramTitle : context.getString(
+ R.string.program_title_with_episode_number_no_season, mProgramTitle,
+ mEpisodeNumber);
+ } else {
+ return context.getString(R.string.program_title_with_episode_number, mProgramTitle,
+ mSeasonNumber, mEpisodeNumber);
+ }
+ }
+
+
+ /**
* Converts a string to a @RecordingType int, defaulting to {@link #TYPE_TIMED}.
*/
private static @RecordingType int recordingType(String type) {
- int t;
- try {
- t = Integer.valueOf(type);
- } catch (NullPointerException | NumberFormatException e) {
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type);
- return TYPE_TIMED;
- }
- switch (t) {
- case TYPE_TIMED:
+ switch (type) {
+ case Schedules.TYPE_TIMED:
return TYPE_TIMED;
- case TYPE_PROGRAM:
+ case Schedules.TYPE_PROGRAM:
return TYPE_PROGRAM;
default:
SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type);
@@ -361,28 +700,40 @@ public final class ScheduledRecording {
}
/**
+ * Converts a @RecordingType int to a string, defaulting to {@link Schedules#TYPE_TIMED}.
+ */
+ private static String recordingType(@RecordingType int type) {
+ switch (type) {
+ case TYPE_TIMED:
+ return Schedules.TYPE_TIMED;
+ case TYPE_PROGRAM:
+ return Schedules.TYPE_PROGRAM;
+ default:
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording type " + type);
+ return Schedules.TYPE_TIMED;
+ }
+ }
+
+ /**
* Converts a string to a @RecordingState int, defaulting to
* {@link #STATE_RECORDING_NOT_STARTED}.
*/
private static @RecordingState int recordingState(String state) {
- int s;
- try {
- s = Integer.valueOf(state);
- } catch (NullPointerException | NumberFormatException e) {
- SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state);
- return STATE_RECORDING_NOT_STARTED;
- }
- switch (s) {
- case STATE_RECORDING_NOT_STARTED:
+ switch (state) {
+ case Schedules.STATE_RECORDING_NOT_STARTED:
return STATE_RECORDING_NOT_STARTED;
- case STATE_RECORDING_IN_PROGRESS:
+ case Schedules.STATE_RECORDING_IN_PROGRESS:
return STATE_RECORDING_IN_PROGRESS;
- case STATE_RECORDING_FINISHED:
+ case Schedules.STATE_RECORDING_FINISHED:
return STATE_RECORDING_FINISHED;
- case STATE_RECORDING_UNEXPECTEDLY_STOPPED:
- return STATE_RECORDING_UNEXPECTEDLY_STOPPED;
- case STATE_RECORDING_FAILED:
+ case Schedules.STATE_RECORDING_FAILED:
return STATE_RECORDING_FAILED;
+ case Schedules.STATE_RECORDING_CLIPPED:
+ return STATE_RECORDING_CLIPPED;
+ case Schedules.STATE_RECORDING_DELETED:
+ return STATE_RECORDING_DELETED;
+ case Schedules.STATE_RECORDING_CANCELED:
+ return STATE_RECORDING_CANCELED;
default:
SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state);
return STATE_RECORDING_NOT_STARTED;
@@ -390,20 +741,147 @@ public final class ScheduledRecording {
}
/**
+ * Converts a @RecordingState int to string, defaulting to
+ * {@link Schedules#STATE_RECORDING_NOT_STARTED}.
+ */
+ private static String recordingState(@RecordingState int state) {
+ switch (state) {
+ case STATE_RECORDING_NOT_STARTED:
+ return Schedules.STATE_RECORDING_NOT_STARTED;
+ case STATE_RECORDING_IN_PROGRESS:
+ return Schedules.STATE_RECORDING_IN_PROGRESS;
+ case STATE_RECORDING_FINISHED:
+ return Schedules.STATE_RECORDING_FINISHED;
+ case STATE_RECORDING_FAILED:
+ return Schedules.STATE_RECORDING_FAILED;
+ case STATE_RECORDING_CLIPPED:
+ return Schedules.STATE_RECORDING_CLIPPED;
+ case STATE_RECORDING_DELETED:
+ return Schedules.STATE_RECORDING_DELETED;
+ case STATE_RECORDING_CANCELED:
+ return Schedules.STATE_RECORDING_CANCELED;
+ default:
+ SoftPreconditions.checkArgument(false, TAG, "Unknown recording state" + state);
+ return Schedules.STATE_RECORDING_NOT_STARTED;
+ }
+ }
+
+ /**
* Checks if the {@code period} overlaps with the recording time.
*/
public boolean isOverLapping(Range<Long> period) {
- return mStartTimeMs <= period.getUpper() && mEndTimeMs >= period.getLower();
+ return mStartTimeMs < period.getUpper() && mEndTimeMs > period.getLower();
+ }
+
+ /**
+ * Checks if the {@code schedule} overlaps with this schedule.
+ */
+ public boolean isOverLapping(ScheduledRecording schedule) {
+ return mStartTimeMs < schedule.getEndTimeMs() && mEndTimeMs > schedule.getStartTimeMs();
}
@Override
public String toString() {
return "ScheduledRecording[" + mId
+ "]"
- + "(startTime=" + Utils.toIsoDateTimeString(mStartTimeMs)
- + ",endTime=" + Utils.toIsoDateTimeString(mEndTimeMs)
+ + "(inputId=" + mInputId
+ + ",channelId=" + mChannelId
+ + ",programId=" + mProgramId
+ + ",programTitle=" + mProgramTitle
+ + ",type=" + mType
+ + ",startTime=" + Utils.toIsoDateTimeString(mStartTimeMs) + "(" + mStartTimeMs + ")"
+ + ",endTime=" + Utils.toIsoDateTimeString(mEndTimeMs) + "(" + mEndTimeMs + ")"
+ + ",seasonNumber=" + mSeasonNumber
+ + ",episodeNumber=" + mEpisodeNumber
+ + ",episodeTitle=" + mEpisodeTitle
+ + ",programDescription=" + mProgramDescription
+ + ",programLongDescription=" + mProgramLongDescription
+ + ",programPosterArtUri=" + mProgramPosterArtUri
+ + ",programThumbnailUri=" + mProgramThumbnailUri
+ ",state=" + mState
+ ",priority=" + mPriority
+ + ",seriesRecordingId=" + mSeriesRecordingId
+ ")";
}
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int paramInt) {
+ out.writeLong(mId);
+ out.writeLong(mPriority);
+ out.writeString(mInputId);
+ out.writeLong(mChannelId);
+ out.writeLong(mProgramId);
+ out.writeString(mProgramTitle);
+ out.writeInt(mType);
+ out.writeLong(mStartTimeMs);
+ out.writeLong(mEndTimeMs);
+ out.writeString(mSeasonNumber);
+ out.writeString(mEpisodeNumber);
+ out.writeString(mEpisodeTitle);
+ out.writeString(mProgramDescription);
+ out.writeString(mProgramLongDescription);
+ out.writeString(mProgramPosterArtUri);
+ out.writeString(mProgramThumbnailUri);
+ out.writeInt(mState);
+ out.writeLong(mSeriesRecordingId);
+ }
+
+ /**
+ * Returns {@code true} if the recording is not started yet, otherwise @{code false}.
+ */
+ public boolean isNotStarted() {
+ return mState == STATE_RECORDING_NOT_STARTED;
+ }
+
+ /**
+ * Returns {@code true} if the recording is in progress, otherwise @{code false}.
+ */
+ public boolean isInProgress() {
+ return mState == STATE_RECORDING_IN_PROGRESS;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof ScheduledRecording)) {
+ return false;
+ }
+ ScheduledRecording r = (ScheduledRecording) obj;
+ return mId == r.mId
+ && mPriority == r.mPriority
+ && mChannelId == r.mChannelId
+ && mProgramId == r.mProgramId
+ && Objects.equals(mProgramTitle, r.mProgramTitle)
+ && mType == r.mType
+ && mStartTimeMs == r.mStartTimeMs
+ && mEndTimeMs == r.mEndTimeMs
+ && Objects.equals(mSeasonNumber, r.mSeasonNumber)
+ && Objects.equals(mEpisodeNumber, r.mEpisodeNumber)
+ && Objects.equals(mEpisodeTitle, r.mEpisodeTitle)
+ && Objects.equals(mProgramDescription, r.getProgramDescription())
+ && Objects.equals(mProgramLongDescription, r.getProgramLongDescription())
+ && Objects.equals(mProgramPosterArtUri, r.getProgramPosterArtUri())
+ && Objects.equals(mProgramThumbnailUri, r.getProgramThumbnailUri())
+ && mState == r.mState
+ && mSeriesRecordingId == r.mSeriesRecordingId;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mId, mPriority, mChannelId, mProgramId, mProgramTitle, mType,
+ mStartTimeMs, mEndTimeMs, mSeasonNumber, mEpisodeNumber, mEpisodeTitle,
+ mProgramDescription, mProgramLongDescription, mProgramPosterArtUri,
+ mProgramThumbnailUri, mState, mSeriesRecordingId);
+ }
+
+ /**
+ * Returns an array containing all of the elements in the list.
+ */
+ public static ScheduledRecording[] toArray(Collection<ScheduledRecording> schedules) {
+ return schedules.toArray(new ScheduledRecording[schedules.size()]);
+ }
}
diff --git a/src/com/android/tv/dvr/Scheduler.java b/src/com/android/tv/dvr/Scheduler.java
index ff9bde68..ce78e1be 100644
--- a/src/com/android/tv/dvr/Scheduler.java
+++ b/src/com/android/tv/dvr/Scheduler.java
@@ -20,86 +20,121 @@ import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.os.Handler;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager.TvInputCallback;
import android.os.Looper;
-import android.os.Message;
+import android.support.annotation.MainThread;
import android.support.annotation.VisibleForTesting;
+import android.util.ArrayMap;
import android.util.Log;
-import android.util.LongSparseArray;
import android.util.Range;
-import com.android.tv.data.Channel;
+import com.android.tv.InputSessionManager;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.ChannelDataManager.Listener;
+import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.util.Clock;
+import com.android.tv.util.TvInputManagerHelper;
+import com.android.tv.util.Utils;
+import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.TimeUnit;
/**
* The core class to manage schedule and run actual recording.
*/
-@VisibleForTesting
-public class Scheduler implements DvrDataManager.ScheduledRecordingListener {
+@MainThread
+public class Scheduler extends TvInputCallback implements ScheduledRecordingListener {
private static final String TAG = "Scheduler";
private static final boolean DEBUG = false;
private final static long SOON_DURATION_IN_MS = TimeUnit.MINUTES.toMillis(5);
@VisibleForTesting final static long MS_TO_WAKE_BEFORE_START = TimeUnit.MINUTES.toMillis(1);
- /**
- * Wraps a {@link RecordingTask} removing it from {@link #mPendingRecordings} when it is done.
- */
- public final class HandlerWrapper extends Handler {
- public static final int MESSAGE_REMOVE = 999;
- private final long mId;
-
- HandlerWrapper(Looper looper, ScheduledRecording scheduledRecording, RecordingTask recordingTask) {
- super(looper, recordingTask);
- mId = scheduledRecording.getId();
- }
-
- @Override
- public void handleMessage(Message msg) {
- // The RecordingTask gets a chance first.
- // It must return false to pass this message to here.
- if (msg.what == MESSAGE_REMOVE) {
- if (DEBUG) Log.d(TAG, "done " + mId);
- mPendingRecordings.remove(mId);
- }
- removeCallbacksAndMessages(null);
- super.handleMessage(msg);
- }
- }
-
- private final LongSparseArray<HandlerWrapper> mPendingRecordings = new LongSparseArray<>();
private final Looper mLooper;
- private final DvrSessionManager mSessionManager;
+ private final InputSessionManager mSessionManager;
private final WritableDvrDataManager mDataManager;
private final DvrManager mDvrManager;
private final ChannelDataManager mChannelDataManager;
+ private final TvInputManagerHelper mInputManager;
private final Context mContext;
private final Clock mClock;
private final AlarmManager mAlarmManager;
- public Scheduler(Looper looper, DvrManager dvrManager, DvrSessionManager sessionManager,
+ private final Map<String, InputTaskScheduler> mInputSchedulerMap = new ArrayMap<>();
+ private long mLastStartTimePendingMs;
+
+ public Scheduler(Looper looper, DvrManager dvrManager, InputSessionManager sessionManager,
WritableDvrDataManager dataManager, ChannelDataManager channelDataManager,
- Context context, Clock clock,
+ TvInputManagerHelper inputManager, Context context, Clock clock,
AlarmManager alarmManager) {
mLooper = looper;
mDvrManager = dvrManager;
mSessionManager = sessionManager;
mDataManager = dataManager;
mChannelDataManager = channelDataManager;
+ mInputManager = inputManager;
mContext = context;
mClock = clock;
mAlarmManager = alarmManager;
}
+ /**
+ * Starts the scheduler.
+ */
+ public void start() {
+ mDataManager.addScheduledRecordingListener(this);
+ mInputManager.addCallback(this);
+ if (mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished()) {
+ updateInternal();
+ } else {
+ if (!mDataManager.isDvrScheduleLoadFinished()) {
+ mDataManager.addDvrScheduleLoadFinishedListener(
+ new OnDvrScheduleLoadFinishedListener() {
+ @Override
+ public void onDvrScheduleLoadFinished() {
+ mDataManager.removeDvrScheduleLoadFinishedListener(this);
+ updateInternal();
+ }
+ });
+ }
+ if (!mChannelDataManager.isDbLoadFinished()) {
+ mChannelDataManager.addListener(new Listener() {
+ @Override
+ public void onLoadFinished() {
+ mChannelDataManager.removeListener(this);
+ updateInternal();
+ }
+
+ @Override
+ public void onChannelListUpdated() { }
+
+ @Override
+ public void onChannelBrowsableChanged() { }
+ });
+ }
+ }
+ }
+
+ /**
+ * Stops the scheduler.
+ */
+ public void stop() {
+ for (InputTaskScheduler inputTaskScheduler : mInputSchedulerMap.values()) {
+ inputTaskScheduler.stop();
+ }
+ mInputManager.removeCallback(this);
+ mDataManager.removeScheduledRecordingListener(this);
+ }
+
private void updatePendingRecordings() {
- List<ScheduledRecording> scheduledRecordings = mDataManager.getRecordingsThatOverlapWith(
- new Range(mClock.currentTimeMillis(),
- mClock.currentTimeMillis() + SOON_DURATION_IN_MS));
- // TODO(DVR): handle removing and updating exiting recordings.
+ List<ScheduledRecording> scheduledRecordings = mDataManager
+ .getScheduledRecordings(new Range<>(mLastStartTimePendingMs,
+ mClock.currentTimeMillis() + SOON_DURATION_IN_MS),
+ ScheduledRecording.STATE_RECORDING_NOT_STARTED);
for (ScheduledRecording r : scheduledRecordings) {
scheduleRecordingSoon(r);
}
@@ -110,70 +145,139 @@ public class Scheduler implements DvrDataManager.ScheduledRecordingListener {
*/
public void update() {
if (DEBUG) Log.d(TAG, "update");
- updatePendingRecordings();
- updateNextAlarm();
+ updateInternal();
}
- @Override
- public void onScheduledRecordingAdded(ScheduledRecording scheduledRecording) {
- if (DEBUG) Log.d(TAG, "added " + scheduledRecording);
- if (startsWithin(scheduledRecording, SOON_DURATION_IN_MS)) {
- scheduleRecordingSoon(scheduledRecording);
- } else {
+ private void updateInternal() {
+ if (isInitialized()) {
+ updatePendingRecordings();
updateNextAlarm();
}
}
+ private boolean isInitialized() {
+ return mDataManager.isDvrScheduleLoadFinished() && mChannelDataManager.isDbLoadFinished();
+ }
+
@Override
- public void onScheduledRecordingRemoved(ScheduledRecording scheduledRecording) {
- long id = scheduledRecording.getId();
- HandlerWrapper wrapper = mPendingRecordings.get(id);
- if (wrapper != null) {
- wrapper.removeCallbacksAndMessages(null);
- mPendingRecordings.remove(id);
- } else {
+ public void onScheduledRecordingAdded(ScheduledRecording... schedules) {
+ if (DEBUG) Log.d(TAG, "added " + Arrays.asList(schedules));
+ if (!isInitialized()) {
+ return;
+ }
+ handleScheduleChange(schedules);
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... schedules) {
+ if (DEBUG) Log.d(TAG, "removed " + Arrays.asList(schedules));
+ if (!isInitialized()) {
+ return;
+ }
+ boolean needToUpdateAlarm = false;
+ for (ScheduledRecording schedule : schedules) {
+ InputTaskScheduler scheduler = mInputSchedulerMap.get(schedule.getInputId());
+ if (scheduler != null) {
+ scheduler.removeSchedule(schedule);
+ needToUpdateAlarm = true;
+ }
+ }
+ if (needToUpdateAlarm) {
updateNextAlarm();
}
}
@Override
- public void onScheduledRecordingStatusChanged(ScheduledRecording scheduledRecording) {
- //TODO(DVR): implement
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... schedules) {
+ if (DEBUG) Log.d(TAG, "state changed " + Arrays.asList(schedules));
+ if (!isInitialized()) {
+ return;
+ }
+ // Update the recordings.
+ for (ScheduledRecording schedule : schedules) {
+ InputTaskScheduler scheduler = mInputSchedulerMap.get(schedule.getInputId());
+ if (scheduler != null) {
+ scheduler.updateSchedule(schedule);
+ }
+ }
+ handleScheduleChange(schedules);
+ }
+
+ private void handleScheduleChange(ScheduledRecording... schedules) {
+ boolean needToUpdateAlarm = false;
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ if (startsWithin(schedule, SOON_DURATION_IN_MS)) {
+ scheduleRecordingSoon(schedule);
+ } else {
+ needToUpdateAlarm = true;
+ }
+ }
+ }
+ if (needToUpdateAlarm) {
+ updateNextAlarm();
+ }
}
- private void scheduleRecordingSoon(ScheduledRecording scheduledRecording) {
- Channel channel = mChannelDataManager.getChannel(scheduledRecording.getChannelId());
- RecordingTask recordingTask = new RecordingTask(scheduledRecording, channel, mDvrManager,
- mSessionManager, mDataManager, mClock);
- HandlerWrapper handlerWrapper = new HandlerWrapper(mLooper, scheduledRecording,
- recordingTask);
- recordingTask.setHandler(handlerWrapper);
- mPendingRecordings.put(scheduledRecording.getId(), handlerWrapper);
- handlerWrapper.sendEmptyMessage(RecordingTask.MESSAGE_INIT);
+ private void scheduleRecordingSoon(ScheduledRecording schedule) {
+ TvInputInfo input = Utils.getTvInputInfoForInputId(mContext, schedule.getInputId());
+ if (input == null) {
+ Log.e(TAG, "Can't find input for " + schedule);
+ mDataManager.changeState(schedule, ScheduledRecording.STATE_RECORDING_FAILED);
+ return;
+ }
+ if (!input.canRecord() || input.getTunerCount() <= 0) {
+ Log.e(TAG, "TV input doesn't support recording: " + input);
+ mDataManager.changeState(schedule, ScheduledRecording.STATE_RECORDING_FAILED);
+ return;
+ }
+ InputTaskScheduler scheduler = mInputSchedulerMap.get(input.getId());
+ if (scheduler == null) {
+ scheduler = new InputTaskScheduler(mContext, input, mLooper, mChannelDataManager,
+ mDvrManager, mDataManager, mSessionManager, mClock);
+ mInputSchedulerMap.put(input.getId(), scheduler);
+ }
+ scheduler.addSchedule(schedule);
+ if (mLastStartTimePendingMs < schedule.getStartTimeMs()) {
+ mLastStartTimePendingMs = schedule.getStartTimeMs();
+ }
}
private void updateNextAlarm() {
- long lastStartTimePending = getLastStartTimePending();
- long nextStartTime = mDataManager.getNextScheduledStartTimeAfter(lastStartTimePending);
+ long nextStartTime = mDataManager.getNextScheduledStartTimeAfter(
+ Math.max(mLastStartTimePendingMs, mClock.currentTimeMillis()));
if (nextStartTime != DvrDataManager.NEXT_START_TIME_NOT_FOUND) {
long wakeAt = nextStartTime - MS_TO_WAKE_BEFORE_START;
if (DEBUG) Log.d(TAG, "Set alarm to record at " + wakeAt);
Intent intent = new Intent(mContext, DvrStartRecordingReceiver.class);
PendingIntent alarmIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- //This will cancel the previous alarm.
- mAlarmManager.set(AlarmManager.RTC_WAKEUP, wakeAt, alarmIntent);
+ // This will cancel the previous alarm.
+ mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, wakeAt, alarmIntent);
} else {
if (DEBUG) Log.d(TAG, "No future recording, alarm not set");
}
}
- private long getLastStartTimePending() {
- // TODO(DVR): implement
- return mClock.currentTimeMillis();
- }
-
@VisibleForTesting
boolean startsWithin(ScheduledRecording scheduledRecording, long durationInMs) {
return mClock.currentTimeMillis() >= scheduledRecording.getStartTimeMs() - durationInMs;
}
+
+ // No need to remove input task scheduler when the input is removed. If the input is removed
+ // temporarily, the scheduler should keep the non-started schedules.
+ @Override
+ public void onInputUpdated(String inputId) {
+ InputTaskScheduler scheduler = mInputSchedulerMap.get(inputId);
+ if (scheduler != null) {
+ scheduler.updateTvInputInfo(Utils.getTvInputInfoForInputId(mContext, inputId));
+ }
+ }
+
+ @Override
+ public void onTvInputInfoUpdated(TvInputInfo input) {
+ InputTaskScheduler scheduler = mInputSchedulerMap.get(input.getId());
+ if (scheduler != null) {
+ scheduler.updateTvInputInfo(input);
+ }
+ }
}
diff --git a/src/com/android/tv/dvr/SeriesInfo.java b/src/com/android/tv/dvr/SeriesInfo.java
new file mode 100644
index 00000000..30256dc5
--- /dev/null
+++ b/src/com/android/tv/dvr/SeriesInfo.java
@@ -0,0 +1,76 @@
+/*
+ * 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;
+
+/**
+ * Series information.
+ */
+public class SeriesInfo {
+ private final String mId;
+ private final String mTitle;
+ private final String mDescription;
+ private final String mLongDescription;
+ private final int[] mCanonicalGenreIds;
+ private final String mPosterUri;
+ private final String mPhotoUri;
+
+ public SeriesInfo(String id, String title, String description, String longDescription,
+ int[] canonicalGenreIds, String posterUri, String photoUri) {
+ this.mId = id;
+ this.mTitle = title;
+ this.mDescription = description;
+ this.mLongDescription = longDescription;
+ this.mCanonicalGenreIds = canonicalGenreIds;
+ this.mPosterUri = posterUri;
+ this.mPhotoUri = photoUri;
+ }
+
+ /** Returns the ID. **/
+ public String getId() {
+ return mId;
+ }
+
+ /** Returns the title. **/
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /** Returns the description. **/
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /** Returns the description. **/
+ public String getLongDescription() {
+ return mLongDescription;
+ }
+
+ /** Returns the canonical genre IDs. **/
+ public int[] getCanonicalGenreIds() {
+ return mCanonicalGenreIds;
+ }
+
+ /** Returns the poster URI. **/
+ public String getPosterUri() {
+ return mPosterUri;
+ }
+
+ /** Returns the photo URI. **/
+ public String getPhotoUri() {
+ return mPhotoUri;
+ }
+}
diff --git a/src/com/android/tv/dvr/SeriesRecording.java b/src/com/android/tv/dvr/SeriesRecording.java
new file mode 100644
index 00000000..f0690f5f
--- /dev/null
+++ b/src/com/android/tv/dvr/SeriesRecording.java
@@ -0,0 +1,755 @@
+/*
+ * 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.ContentValues;
+import android.database.Cursor;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.IntDef;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+
+import com.android.tv.data.BaseProgram;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.provider.DvrContract.SeriesRecordings;
+import com.android.tv.util.Utils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Objects;
+
+/**
+ * Schedules the recording of a Series of Programs.
+ *
+ * <p>
+ * Contains the data needed to create new ScheduleRecordings as the programs become available in
+ * the EPG.
+ */
+public class SeriesRecording implements Parcelable {
+ /**
+ * Indicates that the ID is not assigned yet.
+ */
+ public static final long ID_NOT_SET = 0;
+
+ /**
+ * The default priority of this recording.
+ */
+ public static final long DEFAULT_PRIORITY = Long.MAX_VALUE >> 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {OPTION_CHANNEL_ONE, OPTION_CHANNEL_ALL})
+ public @interface ChannelOption {}
+ /**
+ * An option which indicates that the episodes in one channel are recorded.
+ */
+ public static final int OPTION_CHANNEL_ONE = 0;
+ /**
+ * An option which indicates that the episodes in all the channels are recorded.
+ */
+ public static final int OPTION_CHANNEL_ALL = 1;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true,
+ value = {STATE_SERIES_NORMAL, STATE_SERIES_STOPPED})
+ public @interface SeriesState {}
+
+ /**
+ * The state indicates that the series recording is a normal one.
+ */
+ public static final int STATE_SERIES_NORMAL = 0;
+
+ /**
+ * The state indicates that the series recording is stopped.
+ */
+ public static final int STATE_SERIES_STOPPED = 1;
+
+ /**
+ * Compare priority in descending order.
+ */
+ public static final Comparator<SeriesRecording> PRIORITY_COMPARATOR =
+ new Comparator<SeriesRecording>() {
+ @Override
+ public int compare(SeriesRecording lhs, SeriesRecording rhs) {
+ int value = Long.compare(rhs.mPriority, lhs.mPriority);
+ if (value == 0) {
+ // New recording has the higher priority.
+ value = Long.compare(rhs.mId, lhs.mId);
+ }
+ return value;
+ }
+ };
+
+ /**
+ * Compare ID in ascending order.
+ */
+ public static final Comparator<SeriesRecording> ID_COMPARATOR =
+ new Comparator<SeriesRecording>() {
+ @Override
+ public int compare(SeriesRecording lhs, SeriesRecording rhs) {
+ return Long.compare(lhs.mId, rhs.mId);
+ }
+ };
+
+ /**
+ * Creates a new Builder with the values set from the series information of {@link BaseProgram}.
+ */
+ public static Builder builder(String inputId, BaseProgram p) {
+ return new Builder()
+ .setInputId(inputId)
+ .setSeriesId(p.getSeriesId())
+ .setChannelId(p.getChannelId())
+ .setTitle(p.getTitle())
+ .setDescription(p.getDescription())
+ .setLongDescription(p.getLongDescription())
+ .setCanonicalGenreIds(p.getCanonicalGenreIds())
+ .setPosterUri(p.getPosterArtUri())
+ .setPhotoUri(p.getThumbnailUri());
+ }
+
+ /**
+ * Creates a new Builder with the values set from an existing {@link SeriesRecording}.
+ */
+ @VisibleForTesting
+ public static Builder buildFrom(SeriesRecording r) {
+ return new Builder()
+ .setId(r.mId)
+ .setInputId(r.getInputId())
+ .setChannelId(r.getChannelId())
+ .setPriority(r.getPriority())
+ .setTitle(r.getTitle())
+ .setDescription(r.getDescription())
+ .setLongDescription(r.getLongDescription())
+ .setSeriesId(r.getSeriesId())
+ .setStartFromEpisode(r.getStartFromEpisode())
+ .setStartFromSeason(r.getStartFromSeason())
+ .setChannelOption(r.getChannelOption())
+ .setCanonicalGenreIds(r.getCanonicalGenreIds())
+ .setPosterUri(r.getPosterUri())
+ .setPhotoUri(r.getPhotoUri())
+ .setState(r.getState());
+ }
+
+ /**
+ * Use this projection if you want to create {@link SeriesRecording} object using
+ * {@link #fromCursor}.
+ */
+ public static final String[] PROJECTION = {
+ // Columns must match what is read in fromCursor()
+ SeriesRecordings._ID,
+ SeriesRecordings.COLUMN_INPUT_ID,
+ SeriesRecordings.COLUMN_CHANNEL_ID,
+ SeriesRecordings.COLUMN_PRIORITY,
+ SeriesRecordings.COLUMN_TITLE,
+ SeriesRecordings.COLUMN_SHORT_DESCRIPTION,
+ SeriesRecordings.COLUMN_LONG_DESCRIPTION,
+ SeriesRecordings.COLUMN_SERIES_ID,
+ SeriesRecordings.COLUMN_START_FROM_EPISODE,
+ SeriesRecordings.COLUMN_START_FROM_SEASON,
+ SeriesRecordings.COLUMN_CHANNEL_OPTION,
+ SeriesRecordings.COLUMN_CANONICAL_GENRE,
+ SeriesRecordings.COLUMN_POSTER_URI,
+ SeriesRecordings.COLUMN_PHOTO_URI,
+ SeriesRecordings.COLUMN_STATE
+ };
+ /**
+ * Creates {@link SeriesRecording} object from the given {@link Cursor}.
+ */
+ public static SeriesRecording fromCursor(Cursor c) {
+ int index = -1;
+ return new Builder()
+ .setId(c.getLong(++index))
+ .setInputId(c.getString(++index))
+ .setChannelId(c.getLong(++index))
+ .setPriority(c.getLong(++index))
+ .setTitle(c.getString(++index))
+ .setDescription(c.getString(++index))
+ .setLongDescription(c.getString(++index))
+ .setSeriesId(c.getString(++index))
+ .setStartFromEpisode(c.getInt(++index))
+ .setStartFromSeason(c.getInt(++index))
+ .setChannelOption(channelOption(c.getString(++index)))
+ .setCanonicalGenreIds(c.getString(++index))
+ .setPosterUri(c.getString(++index))
+ .setPhotoUri(c.getString(++index))
+ .setState(seriesRecordingState(c.getString(++index)))
+ .build();
+ }
+
+ /**
+ * Returns the ContentValues with keys as the columns specified in {@link SeriesRecordings}
+ * and the values from {@code r}.
+ */
+ public static ContentValues toContentValues(SeriesRecording r) {
+ ContentValues values = new ContentValues();
+ if (r.getId() != ID_NOT_SET) {
+ values.put(SeriesRecordings._ID, r.getId());
+ } else {
+ values.putNull(SeriesRecordings._ID);
+ }
+ values.put(SeriesRecordings.COLUMN_INPUT_ID, r.getInputId());
+ values.put(SeriesRecordings.COLUMN_CHANNEL_ID, r.getChannelId());
+ values.put(SeriesRecordings.COLUMN_PRIORITY, r.getPriority());
+ values.put(SeriesRecordings.COLUMN_TITLE, r.getTitle());
+ values.put(SeriesRecordings.COLUMN_SHORT_DESCRIPTION, r.getDescription());
+ values.put(SeriesRecordings.COLUMN_LONG_DESCRIPTION, r.getLongDescription());
+ values.put(SeriesRecordings.COLUMN_SERIES_ID, r.getSeriesId());
+ values.put(SeriesRecordings.COLUMN_START_FROM_EPISODE, r.getStartFromEpisode());
+ values.put(SeriesRecordings.COLUMN_START_FROM_SEASON, r.getStartFromSeason());
+ values.put(SeriesRecordings.COLUMN_CHANNEL_OPTION,
+ channelOption(r.getChannelOption()));
+ values.put(SeriesRecordings.COLUMN_CANONICAL_GENRE,
+ Utils.getCanonicalGenre(r.getCanonicalGenreIds()));
+ values.put(SeriesRecordings.COLUMN_POSTER_URI, r.getPosterUri());
+ values.put(SeriesRecordings.COLUMN_PHOTO_URI, r.getPhotoUri());
+ values.put(SeriesRecordings.COLUMN_STATE, seriesRecordingState(r.getState()));
+ return values;
+ }
+
+ private static String channelOption(@ChannelOption int option) {
+ switch (option) {
+ case OPTION_CHANNEL_ONE:
+ return SeriesRecordings.OPTION_CHANNEL_ONE;
+ case OPTION_CHANNEL_ALL:
+ return SeriesRecordings.OPTION_CHANNEL_ALL;
+ }
+ return SeriesRecordings.OPTION_CHANNEL_ONE;
+ }
+
+ @ChannelOption private static int channelOption(String option) {
+ switch (option) {
+ case SeriesRecordings.OPTION_CHANNEL_ONE:
+ return OPTION_CHANNEL_ONE;
+ case SeriesRecordings.OPTION_CHANNEL_ALL:
+ return OPTION_CHANNEL_ALL;
+ }
+ return OPTION_CHANNEL_ONE;
+ }
+
+ private static String seriesRecordingState(@SeriesState int state) {
+ switch (state) {
+ case STATE_SERIES_NORMAL:
+ return SeriesRecordings.STATE_SERIES_NORMAL;
+ case STATE_SERIES_STOPPED:
+ return SeriesRecordings.STATE_SERIES_STOPPED;
+ }
+ return SeriesRecordings.STATE_SERIES_NORMAL;
+ }
+
+ @SeriesState private static int seriesRecordingState(String state) {
+ switch (state) {
+ case SeriesRecordings.STATE_SERIES_NORMAL:
+ return STATE_SERIES_NORMAL;
+ case SeriesRecordings.STATE_SERIES_STOPPED:
+ return STATE_SERIES_STOPPED;
+ }
+ return STATE_SERIES_NORMAL;
+ }
+
+ /**
+ * Builder for {@link SeriesRecording}.
+ */
+ public static class Builder {
+ private long mId = ID_NOT_SET;
+ private long mPriority = DvrScheduleManager.DEFAULT_SERIES_PRIORITY;
+ private String mTitle;
+ private String mDescription;
+ private String mLongDescription;
+ private String mInputId;
+ private long mChannelId;
+ private String mSeriesId;
+ private int mStartFromSeason = SeriesRecordings.THE_BEGINNING;
+ private int mStartFromEpisode = SeriesRecordings.THE_BEGINNING;
+ private int mChannelOption = OPTION_CHANNEL_ONE;
+ private int[] mCanonicalGenreIds;
+ private String mPosterUri;
+ private String mPhotoUri;
+ private int mState = SeriesRecording.STATE_SERIES_NORMAL;
+
+ /**
+ * @see #getId()
+ */
+ public Builder setId(long id) {
+ mId = id;
+ return this;
+ }
+
+ /**
+ * @see #getPriority() ()
+ */
+ public Builder setPriority(long priority) {
+ mPriority = priority;
+ return this;
+ }
+
+ /**
+ * @see #getTitle()
+ */
+ public Builder setTitle(String title) {
+ mTitle = title;
+ return this;
+ }
+
+ /**
+ * @see #getDescription()
+ */
+ public Builder setDescription(String description) {
+ mDescription = description;
+ return this;
+ }
+
+ /**
+ * @see #getLongDescription()
+ */
+ public Builder setLongDescription(String longDescription) {
+ mLongDescription = longDescription;
+ return this;
+ }
+
+ /**
+ * @see #getInputId()
+ */
+ public Builder setInputId(String inputId) {
+ mInputId = inputId;
+ return this;
+ }
+
+ /**
+ * @see #getChannelId()
+ */
+ public Builder setChannelId(long channelId) {
+ mChannelId = channelId;
+ return this;
+ }
+
+ /**
+ * @see #getSeriesId()
+ */
+ public Builder setSeriesId(String seriesId) {
+ mSeriesId = seriesId;
+ return this;
+ }
+
+ /**
+ * @see #getStartFromSeason()
+ */
+ public Builder setStartFromSeason(int startFromSeason) {
+ mStartFromSeason = startFromSeason;
+ return this;
+ }
+
+ /**
+ * @see #getChannelOption()
+ */
+ public Builder setChannelOption(@ChannelOption int option) {
+ mChannelOption = option;
+ return this;
+ }
+
+ /**
+ * @see #getStartFromEpisode()
+ */
+ public Builder setStartFromEpisode(int startFromEpisode) {
+ mStartFromEpisode = startFromEpisode;
+ return this;
+ }
+
+ /**
+ * @see #getCanonicalGenreIds()
+ */
+ public Builder setCanonicalGenreIds(String genres) {
+ mCanonicalGenreIds = Utils.getCanonicalGenreIds(genres);
+ return this;
+ }
+
+ /**
+ * @see #getCanonicalGenreIds()
+ */
+ public Builder setCanonicalGenreIds(int[] canonicalGenreIds) {
+ mCanonicalGenreIds = canonicalGenreIds;
+ return this;
+ }
+
+ /**
+ * @see #getPosterUri()
+ */
+ public Builder setPosterUri(String posterUri) {
+ mPosterUri = posterUri;
+ return this;
+ }
+
+ /**
+ * @see #getPhotoUri()
+ */
+ public Builder setPhotoUri(String photoUri) {
+ mPhotoUri = photoUri;
+ return this;
+ }
+
+ /**
+ * @see #getState()
+ */
+ public Builder setState(@SeriesState int state) {
+ mState = state;
+ return this;
+ }
+
+ /**
+ * Creates a new {@link SeriesRecording}.
+ */
+ public SeriesRecording build() {
+ return new SeriesRecording(mId, mPriority, mTitle, mDescription, mLongDescription,
+ mInputId, mChannelId, mSeriesId, mStartFromSeason, mStartFromEpisode,
+ mChannelOption, mCanonicalGenreIds, mPosterUri, mPhotoUri, mState);
+ }
+ }
+
+ public static SeriesRecording fromParcel(Parcel in) {
+ return new Builder()
+ .setId(in.readLong())
+ .setPriority(in.readLong())
+ .setTitle(in.readString())
+ .setDescription(in.readString())
+ .setLongDescription(in.readString())
+ .setInputId(in.readString())
+ .setChannelId(in.readLong())
+ .setSeriesId(in.readString())
+ .setStartFromSeason(in.readInt())
+ .setStartFromEpisode(in.readInt())
+ .setChannelOption(in.readInt())
+ .setCanonicalGenreIds(in.createIntArray())
+ .setPosterUri(in.readString())
+ .setPhotoUri(in.readString())
+ .setState(in.readInt())
+ .build();
+ }
+
+ public static final Parcelable.Creator<SeriesRecording> CREATOR =
+ new Parcelable.Creator<SeriesRecording>() {
+ @Override
+ public SeriesRecording createFromParcel(Parcel in) {
+ return SeriesRecording.fromParcel(in);
+ }
+
+ @Override
+ public SeriesRecording[] newArray(int size) {
+ return new SeriesRecording[size];
+ }
+ };
+
+ private long mId;
+ private final long mPriority;
+ private final String mTitle;
+ private final String mDescription;
+ private final String mLongDescription;
+ private final String mInputId;
+ private final long mChannelId;
+ private final String mSeriesId;
+ private final int mStartFromSeason;
+ private final int mStartFromEpisode;
+ @ChannelOption private final int mChannelOption;
+ private final int[] mCanonicalGenreIds;
+ private final String mPosterUri;
+ private final String mPhotoUri;
+ @SeriesState private int mState;
+
+ /**
+ * The input id of this SeriesRecording.
+ */
+ public String getInputId() {
+ return mInputId;
+ }
+
+ /**
+ * The channelId to match. The channel ID might not be valid when the channel option is "ALL".
+ */
+ public long getChannelId() {
+ return mChannelId;
+ }
+
+ /**
+ * The id of this SeriesRecording.
+ */
+ public long getId() {
+ return mId;
+ }
+
+ /**
+ * Sets the ID.
+ */
+ public void setId(long id) {
+ mId = id;
+ }
+
+ /**
+ * The priority of this recording.
+ *
+ * <p> The highest number is recorded first. If there is a tie in mPriority then the higher mId
+ * wins.
+ */
+ public long getPriority() {
+ return mPriority;
+ }
+
+ /**
+ * The series title.
+ */
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * The series description.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * The long series description.
+ */
+ public String getLongDescription() {
+ return mLongDescription;
+ }
+
+ /**
+ * SeriesId when not null is used to match programs instead of using title and channelId.
+ *
+ * <p>SeriesId is an opaque but stable string.
+ */
+ public String getSeriesId() {
+ return mSeriesId;
+ }
+
+ /**
+ * If not == {@link SeriesRecordings#THE_BEGINNING} and seasonNumber == startFromSeason then
+ * only record episodes with a episodeNumber >= this
+ */
+ public int getStartFromEpisode() {
+ return mStartFromEpisode;
+ }
+
+ /**
+ * If not == {@link SeriesRecordings#THE_BEGINNING} then only record episodes with a
+ * seasonNumber >= this
+ */
+ public int getStartFromSeason() {
+ return mStartFromSeason;
+ }
+
+ /**
+ * Returns the channel recording option.
+ */
+ @ChannelOption public int getChannelOption() {
+ return mChannelOption;
+ }
+
+ /**
+ * Returns the canonical genre ID's.
+ */
+ public int[] getCanonicalGenreIds() {
+ return mCanonicalGenreIds;
+ }
+
+ /**
+ * Returns the poster URI.
+ */
+ public String getPosterUri() {
+ return mPosterUri;
+ }
+
+ /**
+ * Returns the photo URI.
+ */
+ public String getPhotoUri() {
+ return mPhotoUri;
+ }
+
+ /**
+ * Returns the state of series recording.
+ */
+ @SeriesState public int getState() {
+ return mState;
+ }
+
+ /**
+ * Checks whether the series recording is stopped or not.
+ */
+ public boolean isStopped() {
+ return mState == STATE_SERIES_STOPPED;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof SeriesRecording)) return false;
+ SeriesRecording that = (SeriesRecording) o;
+ return mPriority == that.mPriority
+ && mChannelId == that.mChannelId
+ && mStartFromSeason == that.mStartFromSeason
+ && mStartFromEpisode == that.mStartFromEpisode
+ && Objects.equals(mId, that.mId)
+ && Objects.equals(mTitle, that.mTitle)
+ && Objects.equals(mDescription, that.mDescription)
+ && Objects.equals(mLongDescription, that.mLongDescription)
+ && Objects.equals(mSeriesId, that.mSeriesId)
+ && mChannelOption == that.mChannelOption
+ && Arrays.equals(mCanonicalGenreIds, that.mCanonicalGenreIds)
+ && Objects.equals(mPosterUri, that.mPosterUri)
+ && Objects.equals(mPhotoUri, that.mPhotoUri)
+ && mState == that.mState;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPriority, mChannelId, mStartFromSeason, mStartFromEpisode, mId,
+ mTitle, mDescription, mLongDescription, mSeriesId, mChannelOption,
+ mCanonicalGenreIds, mPosterUri, mPhotoUri, mState);
+ }
+
+ @Override
+ public String toString() {
+ return "SeriesRecording{" +
+ "inputId=" + mInputId +
+ ", channelId=" + mChannelId +
+ ", id='" + mId + '\'' +
+ ", priority=" + mPriority +
+ ", title='" + mTitle + '\'' +
+ ", description='" + mDescription + '\'' +
+ ", longDescription='" + mLongDescription + '\'' +
+ ", startFromSeason=" + mStartFromSeason +
+ ", startFromEpisode=" + mStartFromEpisode +
+ ", channelOption=" + mChannelOption +
+ ", canonicalGenreIds=" + Arrays.toString(mCanonicalGenreIds) +
+ ", posterUri=" + mPosterUri +
+ ", photoUri=" + mPhotoUri +
+ ", state=" + mState +
+ '}';
+ }
+
+ private SeriesRecording(long id, long priority, String title, String description,
+ String longDescription, String inputId, long channelId, String seriesId,
+ int startFromSeason, int startFromEpisode, int channelOption, int[] canonicalGenreIds,
+ String posterUri, String photoUri, int state) {
+ this.mId = id;
+ this.mPriority = priority;
+ this.mTitle = title;
+ this.mDescription = description;
+ this.mLongDescription = longDescription;
+ this.mInputId = inputId;
+ this.mChannelId = channelId;
+ this.mSeriesId = seriesId;
+ this.mStartFromSeason = startFromSeason;
+ this.mStartFromEpisode = startFromEpisode;
+ this.mChannelOption = channelOption;
+ this.mCanonicalGenreIds = canonicalGenreIds;
+ this.mPosterUri = posterUri;
+ this.mPhotoUri = photoUri;
+ this.mState = state;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int paramInt) {
+ out.writeLong(mId);
+ out.writeLong(mPriority);
+ out.writeString(mTitle);
+ out.writeString(mDescription);
+ out.writeString(mLongDescription);
+ out.writeString(mInputId);
+ out.writeLong(mChannelId);
+ out.writeString(mSeriesId);
+ out.writeInt(mStartFromSeason);
+ out.writeInt(mStartFromEpisode);
+ out.writeInt(mChannelOption);
+ out.writeIntArray(mCanonicalGenreIds);
+ out.writeString(mPosterUri);
+ out.writeString(mPhotoUri);
+ out.writeInt(mState);
+ }
+
+ /**
+ * Returns an array containing all of the elements in the list.
+ */
+ public static SeriesRecording[] toArray(Collection<SeriesRecording> series) {
+ return series.toArray(new SeriesRecording[series.size()]);
+ }
+
+ /**
+ * Returns {@code true} if the {@code program} is part of the series and meets the season and
+ * episode constraints.
+ */
+ public boolean matchProgram(Program program) {
+ return matchProgram(program, mChannelOption);
+ }
+
+ /**
+ * Returns {@code true} if the {@code program} is part of the series and meets the season and
+ * episode constraints. It checks the channel option only if {@code checkChannelOption} is
+ * {@code true}.
+ */
+ public boolean matchProgram(Program program, @ChannelOption int channelOption) {
+ String seriesId = program.getSeriesId();
+ long channelId = program.getChannelId();
+ String seasonNumber = program.getSeasonNumber();
+ String episodeNumber = program.getEpisodeNumber();
+ if (!mSeriesId.equals(seriesId) || (channelOption == SeriesRecording.OPTION_CHANNEL_ONE
+ && mChannelId != channelId)) {
+ return false;
+ }
+ // Season number and episode number matches if
+ // start_season_number < program_season_number
+ // || (start_season_number == program_season_number
+ // && start_episode_number <= program_episode_number).
+ if (mStartFromSeason == SeriesRecordings.THE_BEGINNING
+ || TextUtils.isEmpty(seasonNumber)) {
+ return true;
+ } else {
+ int intSeasonNumber;
+ try {
+ intSeasonNumber = Integer.valueOf(seasonNumber);
+ } catch (NumberFormatException e) {
+ return true;
+ }
+ if (intSeasonNumber > mStartFromSeason) {
+ return true;
+ } else if (intSeasonNumber < mStartFromSeason) {
+ return false;
+ }
+ }
+ if (mStartFromEpisode == SeriesRecordings.THE_BEGINNING
+ || TextUtils.isEmpty(episodeNumber)) {
+ return true;
+ } else {
+ int intEpisodeNumber;
+ try {
+ intEpisodeNumber = Integer.valueOf(episodeNumber);
+ } catch (NumberFormatException e) {
+ return true;
+ }
+ return intEpisodeNumber >= mStartFromEpisode;
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/SeriesRecordingScheduler.java b/src/com/android/tv/dvr/SeriesRecordingScheduler.java
new file mode 100644
index 00000000..5ed12ce8
--- /dev/null
+++ b/src/com/android/tv/dvr/SeriesRecordingScheduler.java
@@ -0,0 +1,579 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.AsyncTask;
+import android.os.Build;
+import android.support.annotation.MainThread;
+import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.ArraySet;
+import android.util.Log;
+import android.util.LongSparseArray;
+
+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.data.Program;
+import com.android.tv.data.epg.EpgFetcher;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener;
+import com.android.tv.dvr.EpisodicProgramLoadTask.ScheduledEpisode;
+import com.android.tv.experiments.Experiments;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.Set;
+
+/**
+ * Creates the {@link ScheduledRecording}s for the {@link SeriesRecording}.
+ * <p>
+ * The current implementation assumes that the series recordings are scheduled only for one channel.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class SeriesRecordingScheduler {
+ private static final String TAG = "SeriesRecordingSchd";
+ private static final boolean DEBUG = false;
+
+ private static final String KEY_FETCHED_SERIES_IDS =
+ "SeriesRecordingScheduler.fetched_series_ids";
+
+ @SuppressLint("StaticFieldLeak")
+ private static SeriesRecordingScheduler sInstance;
+
+ /**
+ * Creates and returns the {@link SeriesRecordingScheduler}.
+ */
+ public static synchronized SeriesRecordingScheduler getInstance(Context context) {
+ if (sInstance == null) {
+ sInstance = new SeriesRecordingScheduler(context);
+ }
+ return sInstance;
+ }
+
+ private final Context mContext;
+ private final DvrManager mDvrManager;
+ private final WritableDvrDataManager mDataManager;
+ private final List<SeriesRecordingUpdateTask> mScheduleTasks = new ArrayList<>();
+ private final List<FetchSeriesInfoTask> mFetchSeriesInfoTasks = new ArrayList<>();
+ private final Set<String> mFetchedSeriesIds = new ArraySet<>();
+ private final SharedPreferences mSharedPreferences;
+ private boolean mStarted;
+ private boolean mPaused;
+ private final Set<Long> mPendingSeriesRecordings = new ArraySet<>();
+ private final Set<OnSeriesRecordingUpdatedListener> mOnSeriesRecordingUpdatedListeners =
+ new CopyOnWriteArraySet<>();
+
+
+ private final SeriesRecordingListener mSeriesRecordingListener = new SeriesRecordingListener() {
+ @Override
+ public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ executeFetchSeriesInfoTask(seriesRecording);
+ }
+ }
+
+ @Override
+ public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
+ // Cancel the update.
+ for (Iterator<SeriesRecordingUpdateTask> iter = mScheduleTasks.iterator();
+ iter.hasNext(); ) {
+ SeriesRecordingUpdateTask task = iter.next();
+ if (CollectionUtils.subtract(task.getSeriesRecordings(), seriesRecordings,
+ SeriesRecording.ID_COMPARATOR).isEmpty()) {
+ task.cancel(true);
+ iter.remove();
+ }
+ }
+ }
+
+ @Override
+ public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ List<SeriesRecording> stopped = new ArrayList<>();
+ List<SeriesRecording> normal = new ArrayList<>();
+ for (SeriesRecording r : seriesRecordings) {
+ if (r.isStopped()) {
+ stopped.add(r);
+ } else {
+ normal.add(r);
+ }
+ }
+ if (!stopped.isEmpty()) {
+ onSeriesRecordingRemoved(SeriesRecording.toArray(stopped));
+ }
+ if (!normal.isEmpty()) {
+ updateSchedules(normal);
+ }
+ }
+ };
+
+ private final ScheduledRecordingListener mScheduledRecordingListener =
+ new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... schedules) {
+ // No need to update series recordings when the new schedule is added.
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... schedules) {
+ handleScheduledRecordingChange(Arrays.asList(schedules));
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... schedules) {
+ List<ScheduledRecording> schedulesForUpdate = new ArrayList<>();
+ for (ScheduledRecording r : schedules) {
+ if ((r.getState() == ScheduledRecording.STATE_RECORDING_FAILED
+ || r.getState() == ScheduledRecording.STATE_RECORDING_CLIPPED)
+ && r.getSeriesRecordingId() != SeriesRecording.ID_NOT_SET
+ && !TextUtils.isEmpty(r.getSeasonNumber())
+ && !TextUtils.isEmpty(r.getEpisodeNumber())) {
+ schedulesForUpdate.add(r);
+ }
+ }
+ if (!schedulesForUpdate.isEmpty()) {
+ handleScheduledRecordingChange(schedulesForUpdate);
+ }
+ }
+
+ private void handleScheduledRecordingChange(List<ScheduledRecording> schedules) {
+ if (schedules.isEmpty()) {
+ return;
+ }
+ Set<Long> seriesRecordingIds = new HashSet<>();
+ for (ScheduledRecording r : schedules) {
+ if (r.getSeriesRecordingId() != SeriesRecording.ID_NOT_SET) {
+ seriesRecordingIds.add(r.getSeriesRecordingId());
+ }
+ }
+ if (!seriesRecordingIds.isEmpty()) {
+ List<SeriesRecording> seriesRecordings = new ArrayList<>();
+ for (Long id : seriesRecordingIds) {
+ SeriesRecording seriesRecording = mDataManager.getSeriesRecording(id);
+ if (seriesRecording != null) {
+ seriesRecordings.add(seriesRecording);
+ }
+ }
+ if (!seriesRecordings.isEmpty()) {
+ updateSchedules(seriesRecordings);
+ }
+ }
+ }
+ };
+
+ private SeriesRecordingScheduler(Context context) {
+ mContext = context.getApplicationContext();
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mDvrManager = appSingletons.getDvrManager();
+ mDataManager = (WritableDvrDataManager) appSingletons.getDvrDataManager();
+ mSharedPreferences = context.getSharedPreferences(
+ SharedPreferencesUtils.SHARED_PREF_SERIES_RECORDINGS, Context.MODE_PRIVATE);
+ mFetchedSeriesIds.addAll(mSharedPreferences.getStringSet(KEY_FETCHED_SERIES_IDS,
+ Collections.emptySet()));
+ }
+
+ /**
+ * Starts the scheduler.
+ */
+ @MainThread
+ public void start() {
+ SoftPreconditions.checkState(mDataManager.isInitialized());
+ if (mStarted) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "start");
+ mStarted = true;
+ mDataManager.addSeriesRecordingListener(mSeriesRecordingListener);
+ mDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
+ startFetchingSeriesInfo();
+ updateSchedules(mDataManager.getSeriesRecordings());
+ }
+
+ @MainThread
+ public void stop() {
+ if (!mStarted) {
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "stop");
+ mStarted = false;
+ for (FetchSeriesInfoTask task : mFetchSeriesInfoTasks) {
+ task.cancel(true);
+ }
+ mFetchSeriesInfoTasks.clear();
+ for (SeriesRecordingUpdateTask task : mScheduleTasks) {
+ task.cancel(true);
+ }
+ mScheduleTasks.clear();
+ mDataManager.removeScheduledRecordingListener(mScheduledRecordingListener);
+ mDataManager.removeSeriesRecordingListener(mSeriesRecordingListener);
+ }
+
+ private void startFetchingSeriesInfo() {
+ for (SeriesRecording seriesRecording : mDataManager.getSeriesRecordings()) {
+ if (!mFetchedSeriesIds.contains(seriesRecording.getSeriesId())) {
+ executeFetchSeriesInfoTask(seriesRecording);
+ }
+ }
+ }
+
+ private void executeFetchSeriesInfoTask(SeriesRecording seriesRecording) {
+ if (Experiments.CLOUD_EPG.get()) {
+ FetchSeriesInfoTask task = new FetchSeriesInfoTask(seriesRecording);
+ task.execute();
+ mFetchSeriesInfoTasks.add(task);
+ }
+ }
+
+ /**
+ * Pauses the updates of the series recordings.
+ */
+ public void pauseUpdate() {
+ if (DEBUG) Log.d(TAG, "Schedule paused");
+ if (mPaused) {
+ return;
+ }
+ mPaused = true;
+ if (!mStarted) {
+ return;
+ }
+ for (SeriesRecordingUpdateTask task : mScheduleTasks) {
+ for (SeriesRecording r : task.getSeriesRecordings()) {
+ mPendingSeriesRecordings.add(r.getId());
+ }
+ task.cancel(true);
+ }
+ }
+
+ /**
+ * Resumes the updates of the series recordings.
+ */
+ public void resumeUpdate() {
+ if (DEBUG) Log.d(TAG, "Schedule resumed");
+ if (!mPaused) {
+ return;
+ }
+ mPaused = false;
+ if (!mStarted) {
+ return;
+ }
+ if (!mPendingSeriesRecordings.isEmpty()) {
+ List<SeriesRecording> seriesRecordings = new ArrayList<>();
+ for (long seriesRecordingId : mPendingSeriesRecordings) {
+ SeriesRecording seriesRecording =
+ mDataManager.getSeriesRecording(seriesRecordingId);
+ if (seriesRecording != null) {
+ seriesRecordings.add(seriesRecording);
+ }
+ }
+ if (!seriesRecordings.isEmpty()) {
+ updateSchedules(seriesRecordings);
+ }
+ }
+ }
+
+ /**
+ * Update schedules for the given series recordings. If it's paused, the update will be done
+ * after it's resumed.
+ */
+ public void updateSchedules(Collection<SeriesRecording> seriesRecordings) {
+ if (DEBUG) Log.d(TAG, "updateSchedules:" + seriesRecordings);
+ if (!mStarted) {
+ if (DEBUG) Log.d(TAG, "Not started yet.");
+ return;
+ }
+ if (mPaused) {
+ for (SeriesRecording r : seriesRecordings) {
+ mPendingSeriesRecordings.add(r.getId());
+ }
+ if (DEBUG) {
+ Log.d(TAG, "The scheduler has been paused. Adding to the pending list. size="
+ + mPendingSeriesRecordings.size());
+ }
+ return;
+ }
+ Set<SeriesRecording> previousSeriesRecordings = new HashSet<>();
+ for (Iterator<SeriesRecordingUpdateTask> iter = mScheduleTasks.iterator();
+ iter.hasNext(); ) {
+ SeriesRecordingUpdateTask task = iter.next();
+ if (CollectionUtils.containsAny(task.getSeriesRecordings(), seriesRecordings,
+ SeriesRecording.ID_COMPARATOR)) {
+ // The task is affected by the seriesRecordings
+ task.cancel(true);
+ previousSeriesRecordings.addAll(task.getSeriesRecordings());
+ iter.remove();
+ }
+ }
+ List<SeriesRecording> seriesRecordingsToUpdate = CollectionUtils.union(seriesRecordings,
+ previousSeriesRecordings, SeriesRecording.ID_COMPARATOR);
+ for (Iterator<SeriesRecording> iter = seriesRecordingsToUpdate.iterator();
+ iter.hasNext(); ) {
+ SeriesRecording seriesRecording = mDataManager.getSeriesRecording(iter.next().getId());
+ if (seriesRecording == null || seriesRecording.isStopped()) {
+ // Series recording has been removed or stopped.
+ iter.remove();
+ }
+ }
+ if (seriesRecordingsToUpdate.isEmpty()) {
+ return;
+ }
+ if (needToReadAllChannels(seriesRecordingsToUpdate)) {
+ SeriesRecordingUpdateTask task =
+ new SeriesRecordingUpdateTask(seriesRecordingsToUpdate);
+ mScheduleTasks.add(task);
+ if (DEBUG) Log.d(TAG, "Added schedule task: " + task);
+ task.execute();
+ } else {
+ for (SeriesRecording seriesRecording : seriesRecordingsToUpdate) {
+ SeriesRecordingUpdateTask task = new SeriesRecordingUpdateTask(
+ Collections.singletonList(seriesRecording));
+ mScheduleTasks.add(task);
+ if (DEBUG) Log.d(TAG, "Added schedule task: " + task);
+ task.execute();
+ }
+ }
+ }
+
+ /**
+ * Adds {@link OnSeriesRecordingUpdatedListener}.
+ */
+ public void addOnSeriesRecordingUpdatedListener(OnSeriesRecordingUpdatedListener listener) {
+ mOnSeriesRecordingUpdatedListeners.add(listener);
+ }
+
+ /**
+ * Removes {@link OnSeriesRecordingUpdatedListener}.
+ */
+ public void removeOnSeriesRecordingUpdatedListener(OnSeriesRecordingUpdatedListener listener) {
+ mOnSeriesRecordingUpdatedListeners.remove(listener);
+ }
+
+ private boolean needToReadAllChannels(List<SeriesRecording> seriesRecordingsToUpdate) {
+ for (SeriesRecording seriesRecording : seriesRecordingsToUpdate) {
+ if (seriesRecording.getChannelOption() == SeriesRecording.OPTION_CHANNEL_ALL) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Pick one program per an episode.
+ *
+ * <p>Note that the programs which has been already scheduled have the highest priority, and all
+ * of them are added even though they are the same episodes. That's because the schedules
+ * should be added to the series recording.
+ * <p>If there are no existing schedules for an episode, one program which starts earlier is
+ * picked.
+ */
+ private LongSparseArray<List<Program>> pickOneProgramPerEpisode(
+ List<SeriesRecording> seriesRecordings, List<Program> programs) {
+ return pickOneProgramPerEpisode(mDataManager, seriesRecordings, programs);
+ }
+
+ /**
+ * @see #pickOneProgramPerEpisode(List, List)
+ */
+ @VisibleForTesting
+ static LongSparseArray<List<Program>> pickOneProgramPerEpisode(
+ DvrDataManager dataManager, List<SeriesRecording> seriesRecordings,
+ List<Program> programs) {
+ // Initialize.
+ LongSparseArray<List<Program>> result = new LongSparseArray<>();
+ Map<String, Long> seriesRecordingIds = new HashMap<>();
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ result.put(seriesRecording.getId(), new ArrayList<>());
+ seriesRecordingIds.put(seriesRecording.getSeriesId(), seriesRecording.getId());
+ }
+ // Group programs by the episode.
+ Map<ScheduledEpisode, List<Program>> programsForEpisodeMap = new HashMap<>();
+ for (Program program : programs) {
+ long seriesRecordingId = seriesRecordingIds.get(program.getSeriesId());
+ if (TextUtils.isEmpty(program.getSeasonNumber())
+ || TextUtils.isEmpty(program.getEpisodeNumber())) {
+ // Add all the programs if it doesn't have season number or episode number.
+ result.get(seriesRecordingId).add(program);
+ continue;
+ }
+ ScheduledEpisode episode = new ScheduledEpisode(seriesRecordingId,
+ program.getSeasonNumber(), program.getEpisodeNumber());
+ List<Program> programsForEpisode = programsForEpisodeMap.get(episode);
+ if (programsForEpisode == null) {
+ programsForEpisode = new ArrayList<>();
+ programsForEpisodeMap.put(episode, programsForEpisode);
+ }
+ programsForEpisode.add(program);
+ }
+ // Pick one program.
+ for (Entry<ScheduledEpisode, List<Program>> entry : programsForEpisodeMap.entrySet()) {
+ List<Program> programsForEpisode = entry.getValue();
+ Collections.sort(programsForEpisode, new Comparator<Program>() {
+ @Override
+ public int compare(Program lhs, Program rhs) {
+ // Place the existing schedule first.
+ boolean lhsScheduled = isProgramScheduled(dataManager, lhs);
+ boolean rhsScheduled = isProgramScheduled(dataManager, rhs);
+ if (lhsScheduled && !rhsScheduled) {
+ return -1;
+ }
+ if (!lhsScheduled && rhsScheduled) {
+ return 1;
+ }
+ // Sort by the start time in ascending order.
+ return lhs.compareTo(rhs);
+ }
+ });
+ boolean added = false;
+ // Add all the scheduled programs
+ List<Program> programsForSeries = result.get(entry.getKey().seriesRecordingId);
+ for (Program program : programsForEpisode) {
+ if (isProgramScheduled(dataManager, program)) {
+ programsForSeries.add(program);
+ added = true;
+ } else if (!added) {
+ programsForSeries.add(program);
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ private static boolean isProgramScheduled(DvrDataManager dataManager, Program program) {
+ ScheduledRecording schedule =
+ dataManager.getScheduledRecordingForProgramId(program.getId());
+ return schedule != null && schedule.getState()
+ == ScheduledRecording.STATE_RECORDING_NOT_STARTED;
+ }
+
+ private void updateFetchedSeries() {
+ mSharedPreferences.edit().putStringSet(KEY_FETCHED_SERIES_IDS, mFetchedSeriesIds).apply();
+ }
+
+ /**
+ * This works only for the existing series recordings. Do not use this task for the
+ * "adding series recording" UI.
+ */
+ private class SeriesRecordingUpdateTask extends EpisodicProgramLoadTask {
+ SeriesRecordingUpdateTask(List<SeriesRecording> seriesRecordings) {
+ super(mContext, seriesRecordings);
+ }
+
+ @Override
+ protected void onPostExecute(List<Program> programs) {
+ if (DEBUG) Log.d(TAG, "onPostExecute: updating schedules with programs:" + programs);
+ mScheduleTasks.remove(this);
+ if (programs == null) {
+ Log.e(TAG, "Creating schedules for series recording failed: "
+ + getSeriesRecordings());
+ return;
+ }
+ LongSparseArray<List<Program>> seriesProgramMap = pickOneProgramPerEpisode(
+ getSeriesRecordings(), programs);
+ for (SeriesRecording seriesRecording : getSeriesRecordings()) {
+ // Check the series recording is still valid.
+ SeriesRecording actualSeriesRecording = mDataManager.getSeriesRecording(
+ seriesRecording.getId());
+ if (actualSeriesRecording == null || actualSeriesRecording.isStopped()) {
+ continue;
+ }
+ List<Program> programsToSchedule = seriesProgramMap.get(seriesRecording.getId());
+ if (mDataManager.getSeriesRecording(seriesRecording.getId()) != null
+ && !programsToSchedule.isEmpty()) {
+ mDvrManager.addScheduleToSeriesRecording(seriesRecording, programsToSchedule);
+ }
+ }
+ if (!mOnSeriesRecordingUpdatedListeners.isEmpty()) {
+ for (OnSeriesRecordingUpdatedListener listener
+ : mOnSeriesRecordingUpdatedListeners) {
+ listener.onSeriesRecordingUpdated(
+ SeriesRecording.toArray(getSeriesRecordings()));
+ }
+ }
+ }
+
+ @Override
+ protected void onCancelled(List<Program> programs) {
+ mScheduleTasks.remove(this);
+ }
+
+ @Override
+ public String toString() {
+ return "SeriesRecordingUpdateTask:{"
+ + "series_recordings=" + getSeriesRecordings()
+ + "}";
+ }
+ }
+
+ private class FetchSeriesInfoTask extends AsyncTask<Void, Void, SeriesInfo> {
+ private SeriesRecording mSeriesRecording;
+
+ FetchSeriesInfoTask(SeriesRecording seriesRecording) {
+ mSeriesRecording = seriesRecording;
+ }
+
+ @Override
+ protected SeriesInfo doInBackground(Void... voids) {
+ return EpgFetcher.createEpgReader(mContext)
+ .getSeriesInfo(mSeriesRecording.getSeriesId());
+ }
+
+ @Override
+ protected void onPostExecute(SeriesInfo seriesInfo) {
+ if (seriesInfo != null) {
+ mDataManager.updateSeriesRecording(SeriesRecording.buildFrom(mSeriesRecording)
+ .setTitle(seriesInfo.getTitle())
+ .setDescription(seriesInfo.getDescription())
+ .setLongDescription(seriesInfo.getLongDescription())
+ .setCanonicalGenreIds(seriesInfo.getCanonicalGenreIds())
+ .setPosterUri(seriesInfo.getPosterUri())
+ .setPhotoUri(seriesInfo.getPhotoUri())
+ .build());
+ mFetchedSeriesIds.add(seriesInfo.getId());
+ updateFetchedSeries();
+ }
+ mFetchSeriesInfoTasks.remove(this);
+ }
+
+ @Override
+ protected void onCancelled(SeriesInfo seriesInfo) {
+ mFetchSeriesInfoTasks.remove(this);
+ }
+ }
+
+ /**
+ * A listener to notify when series recording are updated.
+ */
+ public interface OnSeriesRecordingUpdatedListener {
+ void onSeriesRecordingUpdated(SeriesRecording... seriesRecordings);
+ }
+}
diff --git a/src/com/android/tv/dvr/WritableDvrDataManager.java b/src/com/android/tv/dvr/WritableDvrDataManager.java
index 0b8a4c99..bf72d912 100644
--- a/src/com/android/tv/dvr/WritableDvrDataManager.java
+++ b/src/com/android/tv/dvr/WritableDvrDataManager.java
@@ -18,6 +18,8 @@ package com.android.tv.dvr;
import android.support.annotation.MainThread;
+import com.android.tv.dvr.ScheduledRecording.RecordingState;
+
/**
* Full data manager.
*
@@ -27,27 +29,50 @@ import android.support.annotation.MainThread;
@MainThread
interface WritableDvrDataManager extends DvrDataManager {
/**
- * Add a new recording.
+ * Adds new recordings.
+ */
+ void addScheduledRecording(ScheduledRecording... scheduledRecordings);
+
+ /**
+ * Adds new series recordings.
+ */
+ void addSeriesRecording(SeriesRecording... seriesRecordings);
+
+ /**
+ * Removes recordings.
+ */
+ void removeScheduledRecording(ScheduledRecording... scheduledRecordings);
+
+ /**
+ * Removes recordings. If {@code forceRemove} is {@code true}, the schedule will be permanently
+ * removed instead of changing the state to DELETED.
+ */
+ void removeScheduledRecording(boolean forceRemove, ScheduledRecording... scheduledRecordings);
+
+ /**
+ * Removes series recordings.
*/
- void addScheduledRecording(ScheduledRecording scheduledRecording);
+ void removeSeriesRecording(SeriesRecording... seasonSchedules);
/**
- * Add a season recording/
+ * Updates existing recordings.
*/
- void addSeasonRecording(SeasonRecording seasonRecording);
+ void updateScheduledRecording(ScheduledRecording... scheduledRecordings);
/**
- * Remove a recording.
+ * Updates existing series recordings.
*/
- void removeScheduledRecording(ScheduledRecording ScheduledRecording);
+ void updateSeriesRecording(SeriesRecording... seriesRecordings);
/**
- * Remove a season schedule.
+ * Changes the state of the recording.
*/
- void removeSeasonSchedule(SeasonRecording seasonSchedule);
+ void changeState(ScheduledRecording scheduledRecording, @RecordingState int newState);
/**
- * Update an existing recording.
+ * Remove all the records related to the input.
+ * <p>
+ * Note that this should be called after the input was removed.
*/
- void updateScheduledRecording(ScheduledRecording r);
+ void forgetStorage(String inputId);
}
diff --git a/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java b/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
index 6058aa54..1a12fb23 100644
--- a/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
+++ b/src/com/android/tv/dvr/provider/AsyncDvrDbTask.java
@@ -22,7 +22,9 @@ import android.os.AsyncTask;
import android.support.annotation.Nullable;
import com.android.tv.dvr.ScheduledRecording;
-import com.android.tv.dvr.provider.DvrContract.Recordings;
+import com.android.tv.dvr.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;
@@ -76,61 +78,59 @@ public abstract class AsyncDvrDbTask<Params, Progress, Result>
protected abstract Result doInDvrBackground(Params... params);
/**
- * Inserts recordings returning the list of recordings with id set.
- * The id will be -1 if there was an error.
+ * Inserts schedules.
*/
- public abstract static class AsyncAddRecordingTask
- extends AsyncDvrDbTask<ScheduledRecording, Void, List<ScheduledRecording>> {
-
- public AsyncAddRecordingTask(Context context) {
+ public static class AsyncAddScheduleTask
+ extends AsyncDvrDbTask<ScheduledRecording, Void, Void> {
+ public AsyncAddScheduleTask(Context context) {
super(context);
}
@Override
- protected final List<ScheduledRecording> doInDvrBackground(ScheduledRecording... params) {
- return sDbHelper.insertRecordings(params);
+ protected final Void doInDvrBackground(ScheduledRecording... params) {
+ sDbHelper.insertSchedules(params);
+ return null;
}
}
/**
- * Update recordings.
- *
- * @return list of row update counts. The count will be -1 if there was an error or 0
- * if no match was found. The count is expected to be exactly 1 for each recording.
+ * Update schedules.
*/
- public abstract static class AsyncUpdateRecordingTask
- extends AsyncDvrDbTask<ScheduledRecording, Void, List<Integer>> {
- public AsyncUpdateRecordingTask(Context context) {
+ public static class AsyncUpdateScheduleTask
+ extends AsyncDvrDbTask<ScheduledRecording, Void, Void> {
+ public AsyncUpdateScheduleTask(Context context) {
super(context);
}
@Override
- protected final List<Integer> doInDvrBackground(ScheduledRecording... params) {
- return sDbHelper.updateRecordings(params);
+ protected final Void doInDvrBackground(ScheduledRecording... params) {
+ sDbHelper.updateSchedules(params);
+ return null;
}
}
/**
- * Delete recordings.
- *
- * @return list of row delete counts. The count will be -1 if there was an error or 0
- * if no match was found. The count is expected to be exactly 1 for each recording.
+ * Delete schedules.
*/
- public abstract static class AsyncDeleteRecordingTask
- extends AsyncDvrDbTask<ScheduledRecording, Void, List<Integer>> {
- public AsyncDeleteRecordingTask(Context context) {
+ public static class AsyncDeleteScheduleTask
+ extends AsyncDvrDbTask<ScheduledRecording, Void, Void> {
+ public AsyncDeleteScheduleTask(Context context) {
super(context);
}
@Override
- protected final List<Integer> doInDvrBackground(ScheduledRecording... params) {
- return sDbHelper.deleteRecordings(params);
+ protected final Void doInDvrBackground(ScheduledRecording... params) {
+ sDbHelper.deleteSchedules(params);
+ return null;
}
}
- public abstract static class AsyncDvrQueryTask
+ /**
+ * Returns all {@link ScheduledRecording}s.
+ */
+ public abstract static class AsyncDvrQueryScheduleTask
extends AsyncDvrDbTask<Void, Void, List<ScheduledRecording>> {
- public AsyncDvrQueryTask(Context context) {
+ public AsyncDvrQueryScheduleTask(Context context) {
super(context);
}
@@ -140,17 +140,84 @@ public abstract class AsyncDvrDbTask<Params, Progress, Result>
if (isCancelled()) {
return null;
}
-
- if (isCancelled()) {
- return null;
+ List<ScheduledRecording> scheduledRecordings = new ArrayList<>();
+ try (Cursor c = sDbHelper.query(Schedules.TABLE_NAME, ScheduledRecording.PROJECTION)) {
+ while (c.moveToNext() && !isCancelled()) {
+ scheduledRecordings.add(ScheduledRecording.fromCursor(c));
+ }
}
+ return scheduledRecordings;
+ }
+ }
+
+ /**
+ * Inserts series recordings.
+ */
+ public static class AsyncAddSeriesRecordingTask
+ extends AsyncDvrDbTask<SeriesRecording, Void, Void> {
+ public AsyncAddSeriesRecordingTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected final Void doInDvrBackground(SeriesRecording... params) {
+ sDbHelper.insertSeriesRecordings(params);
+ return null;
+ }
+ }
+
+ /**
+ * Update series recordings.
+ */
+ public static class AsyncUpdateSeriesRecordingTask
+ extends AsyncDvrDbTask<SeriesRecording, Void, Void> {
+ public AsyncUpdateSeriesRecordingTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected final Void doInDvrBackground(SeriesRecording... params) {
+ sDbHelper.updateSeriesRecordings(params);
+ return null;
+ }
+ }
+
+ /**
+ * Delete series recordings.
+ */
+ public static class AsyncDeleteSeriesRecordingTask
+ extends AsyncDvrDbTask<SeriesRecording, Void, Void> {
+ public AsyncDeleteSeriesRecordingTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected final Void doInDvrBackground(SeriesRecording... params) {
+ sDbHelper.deleteSeriesRecordings(params);
+ return null;
+ }
+ }
+
+ /**
+ * Returns all {@link SeriesRecording}s.
+ */
+ public abstract static class AsyncDvrQuerySeriesRecordingTask
+ extends AsyncDvrDbTask<Void, Void, List<SeriesRecording>> {
+ public AsyncDvrQuerySeriesRecordingTask(Context context) {
+ super(context);
+ }
+
+ @Override
+ @Nullable
+ protected final List<SeriesRecording> doInDvrBackground(Void... params) {
if (isCancelled()) {
return null;
}
- List<ScheduledRecording> scheduledRecordings = new ArrayList<>();
- try (Cursor c = sDbHelper.query(Recordings.TABLE_NAME, ScheduledRecording.PROJECTION)) {
+ List<SeriesRecording> scheduledRecordings = new ArrayList<>();
+ try (Cursor c = sDbHelper.query(SeriesRecordings.TABLE_NAME,
+ SeriesRecording.PROJECTION)) {
while (c.moveToNext() && !isCancelled()) {
- scheduledRecordings.add(ScheduledRecording.fromCursor(c));
+ scheduledRecordings.add(SeriesRecording.fromCursor(c));
}
}
return scheduledRecordings;
diff --git a/src/com/android/tv/dvr/provider/DvrContract.java b/src/com/android/tv/dvr/provider/DvrContract.java
index 192cc17b..f0aca18e 100644
--- a/src/com/android/tv/dvr/provider/DvrContract.java
+++ b/src/com/android/tv/dvr/provider/DvrContract.java
@@ -23,10 +23,10 @@ import android.provider.BaseColumns;
* columns. It's for the internal use in Live TV.
*/
public final class DvrContract {
- /** Column definition for Recording table. */
- public static final class Recordings implements BaseColumns {
+ /** Column definition for Schedules table. */
+ public static final class Schedules implements BaseColumns {
/** The table name. */
- public static final String TABLE_NAME = "recording";
+ public static final String TABLE_NAME = "schedules";
/** The recording type for program recording. */
public static final String TYPE_PROGRAM = "TYPE_PROGRAM";
@@ -34,22 +34,27 @@ public final class DvrContract {
/** The recording type for timed recording. */
public static final String TYPE_TIMED = "TYPE_TIMED";
- /** The recording type for season recording. */
- public static final String TYPE_SEASON_RECORDING = "TYPE_SEASON_RECORDING";
-
/** The recording has not been started yet. */
public static final String STATE_RECORDING_NOT_STARTED = "STATE_RECORDING_NOT_STARTED";
/** The recording is in progress. */
public static final String STATE_RECORDING_IN_PROGRESS = "STATE_RECORDING_IN_PROGRESS";
- /** The recording was unexpectedly stopped. */
- public static final String STATE_RECORDING_UNEXPECTEDLY_STOPPED =
- "STATE_RECORDING_UNEXPECTEDLY_STOPPED";
-
/** The recording is finished. */
public static final String STATE_RECORDING_FINISHED = "STATE_RECORDING_FINISHED";
+ /** The recording failed. */
+ public static final String STATE_RECORDING_FAILED = "STATE_RECORDING_FAILED";
+
+ /** The recording finished and clipping. */
+ public static final String STATE_RECORDING_CLIPPED = "STATE_RECORDING_CLIPPED";
+
+ /** The recording marked as deleted. */
+ public static final String STATE_RECORDING_DELETED = "STATE_RECORDING_DELETED";
+
+ /** The recording marked as canceled. */
+ public static final String STATE_RECORDING_CANCELED = "STATE_RECORDING_CANCELED";
+
/**
* The priority of this recording.
*
@@ -63,16 +68,25 @@ public final class DvrContract {
/**
* The type of this recording.
*
- * <p>This value should be one of the followings: {@link #TYPE_PROGRAM},
- * {@link #TYPE_TIMED}, and {@link #TYPE_SEASON_RECORDING}.
+ * <p>This value should be one of the followings: {@link #TYPE_PROGRAM} and
+ * {@link #TYPE_TIMED}.
*
* <p>This is a required field.
*
- * <p>Type: String
+ * <p>Type: TEXT
*/
public static final String COLUMN_TYPE = "type";
/**
+ * The input id of recording.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INPUT_ID = "input_id";
+
+ /**
* The ID of the channel for recording.
*
* <p>This is a required field.
@@ -81,9 +95,8 @@ public final class DvrContract {
*/
public static final String COLUMN_CHANNEL_ID = "channel_id";
-
/**
- * The ID of the associated program for recording.
+ * The ID of the associated program for recording.
*
* <p>This is an optional field.
*
@@ -92,6 +105,15 @@ public final class DvrContract {
public static final String COLUMN_PROGRAM_ID = "program_id";
/**
+ * The title of the associated program for recording.
+ *
+ * <p>This is an optional field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PROGRAM_TITLE = "program_title";
+
+ /**
* The start time of this recording, in milliseconds since the epoch.
*
* <p>This is a required field.
@@ -110,19 +132,261 @@ public final class DvrContract {
public static final String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
/**
+ * The season number of this program for episodic TV shows.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SEASON_NUMBER = "season_number";
+
+ /**
+ * The episode number of this program for episodic TV shows.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_NUMBER = "episode_number";
+
+ /**
+ * The episode title of this program for episodic TV shows.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_EPISODE_TITLE = "episode_title";
+
+ /**
+ * The description of program.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PROGRAM_DESCRIPTION = "program_description";
+
+ /**
+ * The long description of program.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PROGRAM_LONG_DESCRIPTION = "program_long_description";
+
+ /**
+ * The poster art uri of program.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PROGRAM_POST_ART_URI = "program_poster_art_uri";
+
+ /**
+ * The thumbnail uri of program.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PROGRAM_THUMBNAIL_URI = "program_thumbnail_uri";
+
+ /**
* The state of this recording.
*
* <p>This value should be one of the followings: {@link #STATE_RECORDING_NOT_STARTED},
- * {@link #STATE_RECORDING_IN_PROGRESS}, {@link #STATE_RECORDING_UNEXPECTEDLY_STOPPED},
- * and {@link #STATE_RECORDING_FINISHED}.
+ * {@link #STATE_RECORDING_IN_PROGRESS}, {@link #STATE_RECORDING_FINISHED},
+ * {@link #STATE_RECORDING_FAILED}, {@link #STATE_RECORDING_CLIPPED} and
+ * {@link #STATE_RECORDING_DELETED}.
*
* <p>This is a required field.
*
- * <p>Type: String
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_STATE = "state";
+
+ /**
+ * The ID of the parent series recording.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_SERIES_RECORDING_ID = "series_recording_id";
+
+ private Schedules() { }
+ }
+
+ /** Column definition for Recording table. */
+ public static final class SeriesRecordings implements BaseColumns {
+ /** The table name. */
+ public static final String TABLE_NAME = "series_recording";
+
+ /**
+ * This value is used for {@link #COLUMN_START_FROM_SEASON} and
+ * {@link #COLUMN_START_FROM_EPISODE} to mean record all seasons or episodes.
+ */
+ public static final int THE_BEGINNING = -1;
+
+ /**
+ * The series recording option which indicates that the episodes in one channel are
+ * recorded.
+ */
+ public static final String OPTION_CHANNEL_ONE = "OPTION_CHANNEL_ONE";
+
+ /**
+ * The series recording option which indicates that the episodes in all the channels are
+ * recorded.
+ */
+ public static final String OPTION_CHANNEL_ALL = "OPTION_CHANNEL_ALL";
+
+ /**
+ * The state indicates that it is a normal one.
+ */
+ public static final String STATE_SERIES_NORMAL = "STATE_SERIES_NORMAL";
+
+ /**
+ * The state indicates that it is stopped.
+ */
+ public static final String STATE_SERIES_STOPPED = "STATE_SERIES_STOPPED";
+
+ /**
+ * The priority of this recording.
+ *
+ * <p> The lowest number is recorded first. If there is a tie in priority then the lower id
+ * wins. Defaults to {@value Long#MAX_VALUE}
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_PRIORITY = "priority";
+
+ /**
+ * The input id of recording.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INPUT_ID = "input_id";
+
+ /**
+ * The ID of the channel for recording.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
+ * The ID of the associated series to record.
+ *
+ * <p>The id is an opaque but stable string.
+ *
+ * <p>This is an optional field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SERIES_ID = "series_id";
+
+ /**
+ * The title of the series.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_TITLE = "title";
+
+ /**
+ * The short description of the series.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_SHORT_DESCRIPTION = "short_description";
+
+ /**
+ * The long description of the series.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_LONG_DESCRIPTION = "long_description";
+
+ /**
+ * The number of the earliest season to record. The
+ * value {@link #THE_BEGINNING} means record all seasons.
+ *
+ * <p>Default value is {@value #THE_BEGINNING} {@link #THE_BEGINNING}.
+ *
+ * <p>Type: INTEGER (int)
+ */
+ public static final String COLUMN_START_FROM_SEASON = "start_from_season";
+
+ /**
+ * The number of the earliest episode to record in {@link #COLUMN_START_FROM_SEASON}. The
+ * value {@link #THE_BEGINNING} means record all episodes.
+ *
+ * <p>Default value is {@value #THE_BEGINNING} {@link #THE_BEGINNING}.
+ *
+ * <p>Type: INTEGER (int)
+ */
+ public static final String COLUMN_START_FROM_EPISODE = "start_from_episode";
+
+ /**
+ * The series recording option which indicates the channels to record.
+ *
+ * <p>This value should be one of the followings: {@link #OPTION_CHANNEL_ONE} and
+ * {@link #OPTION_CHANNEL_ALL}. The default value is OPTION_CHANNEL_ONE.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CHANNEL_OPTION = "channel_option";
+
+ /**
+ * The comma-separated canonical genre string of this series.
+ *
+ * <p>Canonical genres are defined in {@link android.media.tv.TvContract.Programs.Genres}.
+ * Use {@link android.media.tv.TvContract.Programs.Genres#encode} to create a text that can
+ * be stored in this column. Use {@link android.media.tv.TvContract.Programs.Genres#decode}
+ * to get the canonical genre strings from the text stored in the column.
+ *
+ * <p>Type: TEXT
+ * @see android.media.tv.TvContract.Programs.Genres
+ * @see android.media.tv.TvContract.Programs.Genres#encode
+ * @see android.media.tv.TvContract.Programs.Genres#decode
+ */
+ public static final String COLUMN_CANONICAL_GENRE = "canonical_genre";
+
+ /**
+ * The URI for the poster of this TV series.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_URI = "poster_uri";
+
+ /**
+ * The URI for the photo of this TV program.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_PHOTO_URI = "photo_uri";
+
+ /**
+ * The state of whether the series recording be canceled or not.
+ *
+ * <p>This value should be one of the followings: {@link #STATE_SERIES_NORMAL} and
+ * {@link #STATE_SERIES_STOPPED}. The default value is STATE_SERIES_NORMAL.
+ *
+ * <p>Type: TEXT
*/
public static final String COLUMN_STATE = "state";
- private Recordings() { }
+ private SeriesRecordings() { }
}
private DvrContract() { }
diff --git a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
index bdba8ac3..2f16ba5d 100644
--- a/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
+++ b/src/com/android/tv/dvr/provider/DvrDatabaseHelper.java
@@ -22,13 +22,15 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
+import android.database.sqlite.SQLiteStatement;
+import android.provider.BaseColumns;
+import android.text.TextUtils;
import android.util.Log;
import com.android.tv.dvr.ScheduledRecording;
-import com.android.tv.dvr.provider.DvrContract.Recordings;
-
-import java.util.ArrayList;
-import java.util.List;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.provider.DvrContract.Schedules;
+import com.android.tv.dvr.provider.DvrContract.SeriesRecordings;
/**
* A data class for one recorded contents.
@@ -37,24 +39,153 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper {
private static final String TAG = "DvrDatabaseHelper";
private static final boolean DEBUG = true;
- private static final int DATABASE_VERSION = 4;
+ private static final int DATABASE_VERSION = 17;
private static final String DB_NAME = "dvr.db";
- private static final String SQL_CREATE_RECORDINGS =
- "CREATE TABLE " + Recordings.TABLE_NAME + "("
- + Recordings._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
- + Recordings.COLUMN_PRIORITY + " INTEGER DEFAULT " + Long.MAX_VALUE + ","
- + Recordings.COLUMN_TYPE + " TEXT NOT NULL,"
- + Recordings.COLUMN_CHANNEL_ID + " INTEGER NOT NULL,"
- + Recordings.COLUMN_PROGRAM_ID + " INTEGER ,"
- + Recordings.COLUMN_START_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
- + Recordings.COLUMN_END_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
- + Recordings.COLUMN_STATE + " TEXT NOT NULL)";
-
- private static final String SQL_DROP_RECORDINGS = "DROP TABLE IF EXISTS "
- + Recordings.TABLE_NAME;
- public static final String WHERE_RECORDING_ID_EQUALS = Recordings._ID + " = ?";
+ private static final String SQL_CREATE_SCHEDULES =
+ "CREATE TABLE " + Schedules.TABLE_NAME + "("
+ + Schedules._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ + Schedules.COLUMN_PRIORITY + " INTEGER DEFAULT "
+ + ScheduledRecording.DEFAULT_PRIORITY + ","
+ + Schedules.COLUMN_TYPE + " TEXT NOT NULL,"
+ + Schedules.COLUMN_INPUT_ID + " TEXT NOT NULL,"
+ + Schedules.COLUMN_CHANNEL_ID + " INTEGER NOT NULL,"
+ + Schedules.COLUMN_PROGRAM_ID + " INTEGER,"
+ + Schedules.COLUMN_PROGRAM_TITLE + " TEXT,"
+ + Schedules.COLUMN_START_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
+ + Schedules.COLUMN_END_TIME_UTC_MILLIS + " INTEGER NOT NULL,"
+ + Schedules.COLUMN_SEASON_NUMBER + " TEXT,"
+ + Schedules.COLUMN_EPISODE_NUMBER + " TEXT,"
+ + Schedules.COLUMN_EPISODE_TITLE + " TEXT,"
+ + Schedules.COLUMN_PROGRAM_DESCRIPTION + " TEXT,"
+ + Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION + " TEXT,"
+ + Schedules.COLUMN_PROGRAM_POST_ART_URI + " TEXT,"
+ + Schedules.COLUMN_PROGRAM_THUMBNAIL_URI + " TEXT,"
+ + Schedules.COLUMN_STATE + " TEXT NOT NULL,"
+ + Schedules.COLUMN_SERIES_RECORDING_ID + " INTEGER,"
+ + "FOREIGN KEY(" + Schedules.COLUMN_SERIES_RECORDING_ID + ") "
+ + "REFERENCES " + SeriesRecordings.TABLE_NAME
+ + "(" + SeriesRecordings._ID + ") "
+ + "ON UPDATE CASCADE ON DELETE SET NULL);";
+
+ private static final String SQL_DROP_SCHEDULES = "DROP TABLE IF EXISTS " + Schedules.TABLE_NAME;
+
+ private static final String SQL_CREATE_SERIES_RECORDINGS =
+ "CREATE TABLE " + SeriesRecordings.TABLE_NAME + "("
+ + SeriesRecordings._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ + SeriesRecordings.COLUMN_PRIORITY + " INTEGER DEFAULT "
+ + SeriesRecording.DEFAULT_PRIORITY + ","
+ + SeriesRecordings.COLUMN_TITLE + " TEXT NOT NULL,"
+ + SeriesRecordings.COLUMN_SHORT_DESCRIPTION + " TEXT,"
+ + SeriesRecordings.COLUMN_LONG_DESCRIPTION + " TEXT,"
+ + SeriesRecordings.COLUMN_INPUT_ID + " TEXT NOT NULL,"
+ + SeriesRecordings.COLUMN_CHANNEL_ID + " INTEGER NOT NULL,"
+ + SeriesRecordings.COLUMN_SERIES_ID + " TEXT NOT NULL,"
+ + SeriesRecordings.COLUMN_START_FROM_SEASON + " INTEGER DEFAULT "
+ + SeriesRecordings.THE_BEGINNING + ","
+ + SeriesRecordings.COLUMN_START_FROM_EPISODE + " INTEGER DEFAULT "
+ + SeriesRecordings.THE_BEGINNING + ","
+ + SeriesRecordings.COLUMN_CHANNEL_OPTION + " TEXT DEFAULT "
+ + SeriesRecordings.OPTION_CHANNEL_ONE + ","
+ + SeriesRecordings.COLUMN_CANONICAL_GENRE + " TEXT,"
+ + SeriesRecordings.COLUMN_POSTER_URI + " TEXT,"
+ + SeriesRecordings.COLUMN_PHOTO_URI + " TEXT,"
+ + SeriesRecordings.COLUMN_STATE + " TEXT)";
+
+ private static final String SQL_DROP_SERIES_RECORDINGS = "DROP TABLE IF EXISTS " +
+ SeriesRecordings.TABLE_NAME;
+
+ private static final int SQL_DATA_TYPE_LONG = 0;
+ private static final int SQL_DATA_TYPE_INT = 1;
+ private static final int SQL_DATA_TYPE_STRING = 2;
+
+ private static final ColumnInfo[] COLUMNS_SCHEDULES = new ColumnInfo[] {
+ new ColumnInfo(Schedules._ID, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_PRIORITY, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_TYPE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_INPUT_ID, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_CHANNEL_ID, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_ID, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_TITLE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_START_TIME_UTC_MILLIS, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_END_TIME_UTC_MILLIS, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(Schedules.COLUMN_SEASON_NUMBER, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_EPISODE_NUMBER, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_EPISODE_TITLE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_DESCRIPTION, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_LONG_DESCRIPTION, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_POST_ART_URI, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_PROGRAM_THUMBNAIL_URI, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_STATE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(Schedules.COLUMN_SERIES_RECORDING_ID, SQL_DATA_TYPE_LONG)};
+ private static final String SQL_INSERT_SCHEDULES =
+ buildInsertSql(Schedules.TABLE_NAME, COLUMNS_SCHEDULES);
+ private static final String SQL_UPDATE_SCHEDULES =
+ buildUpdateSql(Schedules.TABLE_NAME, COLUMNS_SCHEDULES);
+ private static final String SQL_DELETE_SCHEDULES = buildDeleteSql(Schedules.TABLE_NAME);
+
+ private static final ColumnInfo[] COLUMNS_SERIES_RECORDINGS = new ColumnInfo[] {
+ new ColumnInfo(SeriesRecordings._ID, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(SeriesRecordings.COLUMN_PRIORITY, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(SeriesRecordings.COLUMN_INPUT_ID, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_CHANNEL_ID, SQL_DATA_TYPE_LONG),
+ new ColumnInfo(SeriesRecordings.COLUMN_SERIES_ID, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_TITLE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_SHORT_DESCRIPTION, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_LONG_DESCRIPTION, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_START_FROM_SEASON, SQL_DATA_TYPE_INT),
+ new ColumnInfo(SeriesRecordings.COLUMN_START_FROM_EPISODE, SQL_DATA_TYPE_INT),
+ new ColumnInfo(SeriesRecordings.COLUMN_CHANNEL_OPTION, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_CANONICAL_GENRE, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_POSTER_URI, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_PHOTO_URI, SQL_DATA_TYPE_STRING),
+ new ColumnInfo(SeriesRecordings.COLUMN_STATE, SQL_DATA_TYPE_STRING)};
+
+ private static final String SQL_INSERT_SERIES_RECORDINGS =
+ buildInsertSql(SeriesRecordings.TABLE_NAME, COLUMNS_SERIES_RECORDINGS);
+ private static final String SQL_UPDATE_SERIES_RECORDINGS =
+ buildUpdateSql(SeriesRecordings.TABLE_NAME, COLUMNS_SERIES_RECORDINGS);
+ private static final String SQL_DELETE_SERIES_RECORDINGS =
+ buildDeleteSql(SeriesRecordings.TABLE_NAME);
+
+ private static String buildInsertSql(String tableName, ColumnInfo[] columns) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("INSERT INTO ").append(tableName).append(" (");
+ boolean appendComma = false;
+ for (ColumnInfo columnInfo : columns) {
+ if (appendComma) {
+ sb.append(",");
+ }
+ appendComma = true;
+ sb.append(columnInfo.name);
+ }
+ sb.append(") VALUES (?");
+ for (int i = 1; i < columns.length; ++i) {
+ sb.append(",?");
+ }
+ sb.append(")");
+ return sb.toString();
+ }
+
+ private static String buildUpdateSql(String tableName, ColumnInfo[] columns) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("UPDATE ").append(tableName).append(" SET ");
+ boolean appendComma = false;
+ for (ColumnInfo columnInfo : columns) {
+ if (appendComma) {
+ sb.append(",");
+ }
+ appendComma = true;
+ sb.append(columnInfo.name).append("=?");
+ }
+ sb.append(" WHERE ").append(BaseColumns._ID).append("=?");
+ return sb.toString();
+ }
+
+ private static String buildDeleteSql(String tableName) {
+ return "DELETE FROM " + tableName + " WHERE " + BaseColumns._ID + "=?";
+ }
public DvrDatabaseHelper(Context context) {
super(context.getApplicationContext(), DB_NAME, null, DATABASE_VERSION);
}
@@ -66,14 +197,18 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper {
@Override
public void onCreate(SQLiteDatabase db) {
- if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_CREATE_RECORDINGS);
- db.execSQL(SQL_CREATE_RECORDINGS);
+ if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_CREATE_SCHEDULES);
+ db.execSQL(SQL_CREATE_SCHEDULES);
+ if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_CREATE_SERIES_RECORDINGS);
+ db.execSQL(SQL_CREATE_SERIES_RECORDINGS);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_DROP_RECORDINGS);
- db.execSQL(SQL_DROP_RECORDINGS);
+ if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_DROP_SCHEDULES);
+ db.execSQL(SQL_DROP_SCHEDULES);
+ if (DEBUG) Log.d(TAG, "Executing SQL: " + SQL_DROP_SERIES_RECORDINGS);
+ db.execSQL(SQL_DROP_SERIES_RECORDINGS);
onCreate(db);
}
@@ -88,61 +223,164 @@ public class DvrDatabaseHelper extends SQLiteOpenHelper {
}
/**
- * Inserts recordings.
- *
- * @return The list of recordings with id set. The id will be -1 if there was an error.
+ * Inserts schedules.
*/
- public List<ScheduledRecording> insertRecordings(ScheduledRecording... scheduledRecordings) {
- updateChannelsFromRecordings(scheduledRecordings);
+ public void insertSchedules(ScheduledRecording... scheduledRecordings) {
+ SQLiteDatabase db = getWritableDatabase();
+ SQLiteStatement statement = db.compileStatement(SQL_INSERT_SCHEDULES);
+ db.beginTransaction();
+ try {
+ for (ScheduledRecording r : scheduledRecordings) {
+ statement.clearBindings();
+ ContentValues values = ScheduledRecording.toContentValues(r);
+ bindColumns(statement, COLUMNS_SCHEDULES, values);
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
- SQLiteDatabase db = getReadableDatabase();
- List<ScheduledRecording> results = new ArrayList<>();
- for (ScheduledRecording r : scheduledRecordings) {
- ContentValues values = ScheduledRecording.toContentValues(r);
- long id = db.insert(Recordings.TABLE_NAME, null, values);
- results.add(ScheduledRecording.buildFrom(r).setId(id).build());
+ /**
+ * Update schedules.
+ */
+ public void updateSchedules(ScheduledRecording... scheduledRecordings) {
+ SQLiteDatabase db = getWritableDatabase();
+ SQLiteStatement statement = db.compileStatement(SQL_UPDATE_SCHEDULES);
+ db.beginTransaction();
+ try {
+ for (ScheduledRecording r : scheduledRecordings) {
+ statement.clearBindings();
+ ContentValues values = ScheduledRecording.toContentValues(r);
+ bindColumns(statement, COLUMNS_SCHEDULES, values);
+ statement.bindLong(COLUMNS_SCHEDULES.length + 1, r.getId());
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ /**
+ * Delete schedules.
+ */
+ public void deleteSchedules(ScheduledRecording... scheduledRecordings) {
+ SQLiteDatabase db = getWritableDatabase();
+ SQLiteStatement statement = db.compileStatement(SQL_DELETE_SCHEDULES);
+ db.beginTransaction();
+ try {
+ for (ScheduledRecording r : scheduledRecordings) {
+ statement.clearBindings();
+ statement.bindLong(1, r.getId());
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- return results;
}
/**
- * Update recordings.
- *
- * @return The list of row update counts. The count will be -1 if there was an error or 0
- * if no match was found. The count is expected to be exactly 1 for each recording.
+ * Inserts series recordings.
*/
- public List<Integer> updateRecordings(ScheduledRecording[] scheduledRecordings) {
- updateChannelsFromRecordings(scheduledRecordings);
+ public void insertSeriesRecordings(SeriesRecording... seriesRecordings) {
SQLiteDatabase db = getWritableDatabase();
- List<Integer> results = new ArrayList<>();
- for (ScheduledRecording r : scheduledRecordings) {
- ContentValues values = ScheduledRecording.toContentValues(r);
- int updated = db.update(Recordings.TABLE_NAME, values, Recordings._ID + " = ?",
- new String[] {String.valueOf(r.getId())});
- results.add(updated);
+ SQLiteStatement statement = db.compileStatement(SQL_INSERT_SERIES_RECORDINGS);
+ db.beginTransaction();
+ try {
+ for (SeriesRecording r : seriesRecordings) {
+ statement.clearBindings();
+ ContentValues values = SeriesRecording.toContentValues(r);
+ bindColumns(statement, COLUMNS_SERIES_RECORDINGS, values);
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
}
- return results;
}
- private void updateChannelsFromRecordings(ScheduledRecording[] scheduledRecordings) {
- // TODO(DVR) implement/
- // TODO(DVR) consider not deleting channels instead of keeping a separate table.
+ /**
+ * Update series recordings.
+ */
+ public void updateSeriesRecordings(SeriesRecording... seriesRecordings) {
+ SQLiteDatabase db = getWritableDatabase();
+ SQLiteStatement statement = db.compileStatement(SQL_UPDATE_SERIES_RECORDINGS);
+ db.beginTransaction();
+ try {
+ for (SeriesRecording r : seriesRecordings) {
+ statement.clearBindings();
+ ContentValues values = SeriesRecording.toContentValues(r);
+ bindColumns(statement, COLUMNS_SERIES_RECORDINGS, values);
+ statement.bindLong(COLUMNS_SERIES_RECORDINGS.length + 1, r.getId());
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
}
/**
- * Delete recordings.
- *
- * @return The list of row update counts. The count will be -1 if there was an error or 0
- * if no match was found. The count is expected to be exactly 1 for each recording.
+ * Delete series recordings.
*/
- public List<Integer> deleteRecordings(ScheduledRecording[] scheduledRecordings) {
+ public void deleteSeriesRecordings(SeriesRecording... seriesRecordings) {
SQLiteDatabase db = getWritableDatabase();
- List<Integer> results = new ArrayList<>();
- for (ScheduledRecording r : scheduledRecordings) {
- int deleted = db.delete(Recordings.TABLE_NAME, WHERE_RECORDING_ID_EQUALS,
- new String[] {String.valueOf(r.getId())});
- results.add(deleted);
+ SQLiteStatement statement = db.compileStatement(SQL_DELETE_SERIES_RECORDINGS);
+ db.beginTransaction();
+ try {
+ for (SeriesRecording r : seriesRecordings) {
+ statement.clearBindings();
+ statement.bindLong(1, r.getId());
+ statement.execute();
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ private void bindColumns(SQLiteStatement statement, ColumnInfo[] columns,
+ ContentValues values) {
+ for (int i = 0; i < columns.length; ++i) {
+ ColumnInfo columnInfo = columns[i];
+ Object value = values.get(columnInfo.name);
+ switch (columnInfo.type) {
+ case SQL_DATA_TYPE_LONG:
+ if (value == null) {
+ statement.bindNull(i + 1);
+ } else {
+ statement.bindLong(i + 1, (Long) value);
+ }
+ break;
+ case SQL_DATA_TYPE_INT:
+ if (value == null) {
+ statement.bindNull(i + 1);
+ } else {
+ statement.bindLong(i + 1, (Integer) value);
+ }
+ break;
+ case SQL_DATA_TYPE_STRING: {
+ if (TextUtils.isEmpty((String) value)) {
+ statement.bindNull(i + 1);
+ } else {
+ statement.bindString(i + 1, (String) value);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private static class ColumnInfo {
+ final String name;
+ final int type;
+
+ ColumnInfo(String name, int type) {
+ this.name = name;
+ this.type = type;
}
- return results;
}
}
diff --git a/src/com/android/tv/dvr/ui/ActionPresenterSelector.java b/src/com/android/tv/dvr/ui/ActionPresenterSelector.java
new file mode 100644
index 00000000..8b8cd5c5
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/ActionPresenterSelector.java
@@ -0,0 +1,138 @@
+/*
+ * 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.graphics.drawable.Drawable;
+import android.support.v17.leanback.R;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+// This class is adapted from Leanback's library, which does not support action icon with one-line
+// label. This class modified its getPresenter method to support the above situation.
+class ActionPresenterSelector extends PresenterSelector {
+ private final Presenter mOneLineActionPresenter = new OneLineActionPresenter();
+ private final Presenter mTwoLineActionPresenter = new TwoLineActionPresenter();
+ private final Presenter[] mPresenters = new Presenter[] {
+ mOneLineActionPresenter, mTwoLineActionPresenter};
+
+ @Override
+ public Presenter getPresenter(Object item) {
+ Action action = (Action) item;
+ if (TextUtils.isEmpty(action.getLabel2()) && action.getIcon() == null) {
+ return mOneLineActionPresenter;
+ } else {
+ return mTwoLineActionPresenter;
+ }
+ }
+
+ @Override
+ public Presenter[] getPresenters() {
+ return mPresenters;
+ }
+
+ static class ActionViewHolder extends Presenter.ViewHolder {
+ Action mAction;
+ Button mButton;
+ int mLayoutDirection;
+
+ public ActionViewHolder(View view, int layoutDirection) {
+ super(view);
+ mButton = (Button) view.findViewById(R.id.lb_action_button);
+ mLayoutDirection = layoutDirection;
+ }
+ }
+
+ class OneLineActionPresenter extends Presenter {
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.lb_action_1_line, parent, false);
+ return new ActionViewHolder(v, parent.getLayoutDirection());
+ }
+
+ @Override
+ public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+ Action action = (Action) item;
+ ActionViewHolder vh = (ActionViewHolder) viewHolder;
+ vh.mAction = action;
+ vh.mButton.setText(action.getLabel1());
+ }
+
+ @Override
+ public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+ ((ActionViewHolder) viewHolder).mAction = null;
+ }
+ }
+
+ class TwoLineActionPresenter extends Presenter {
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.lb_action_2_lines, parent, false);
+ return new ActionViewHolder(v, parent.getLayoutDirection());
+ }
+
+ @Override
+ public void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+ Action action = (Action) item;
+ ActionViewHolder vh = (ActionViewHolder) viewHolder;
+ Drawable icon = action.getIcon();
+ vh.mAction = action;
+
+ if (icon != null) {
+ final int startPadding = vh.view.getResources()
+ .getDimensionPixelSize(R.dimen.lb_action_with_icon_padding_start);
+ final int endPadding = vh.view.getResources()
+ .getDimensionPixelSize(R.dimen.lb_action_with_icon_padding_end);
+ vh.view.setPaddingRelative(startPadding, 0, endPadding, 0);
+ } else {
+ final int padding = vh.view.getResources()
+ .getDimensionPixelSize(R.dimen.lb_action_padding_horizontal);
+ vh.view.setPaddingRelative(padding, 0, padding, 0);
+ }
+ if (vh.mLayoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ vh.mButton.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null);
+ } else {
+ vh.mButton.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
+ }
+
+ CharSequence line1 = action.getLabel1();
+ CharSequence line2 = action.getLabel2();
+ if (TextUtils.isEmpty(line1)) {
+ vh.mButton.setText(line2);
+ } else if (TextUtils.isEmpty(line2)) {
+ vh.mButton.setText(line1);
+ } else {
+ vh.mButton.setText(line1 + "\n" + line2);
+ }
+ }
+
+ @Override
+ public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) {
+ ActionViewHolder vh = (ActionViewHolder) viewHolder;
+ vh.mButton.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+ vh.view.setPadding(0, 0, 0, 0);
+ vh.mAction = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/CurrentRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/CurrentRecordingDetailsFragment.java
new file mode 100644
index 00000000..5d8e20ff
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/CurrentRecordingDetailsFragment.java
@@ -0,0 +1,59 @@
+/*
+ * 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.content.res.Resources;
+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.TvApplication;
+import com.android.tv.dvr.DvrManager;
+
+/**
+ * {@link RecordingDetailsFragment} for current recording in DVR.
+ */
+public class CurrentRecordingDetailsFragment extends RecordingDetailsFragment {
+ private static final int ACTION_STOP_RECORDING = 1;
+
+ @Override
+ protected SparseArrayObjectAdapter onCreateActionsAdapter() {
+ SparseArrayObjectAdapter adapter =
+ new SparseArrayObjectAdapter(new ActionPresenterSelector());
+ Resources res = getResources();
+ adapter.set(ACTION_STOP_RECORDING, new Action(ACTION_STOP_RECORDING,
+ res.getString(R.string.epg_dvr_dialog_message_stop_recording), null,
+ res.getDrawable(R.drawable.lb_ic_stop)));
+ return adapter;
+ }
+
+ @Override
+ protected OnActionClickedListener onCreateOnActionClickedListener() {
+ return new OnActionClickedListener() {
+ @Override
+ public void onActionClicked(Action action) {
+ if (action.getId() == ACTION_STOP_RECORDING) {
+ DvrManager dvrManager = TvApplication.getSingletons(getActivity())
+ .getDvrManager();
+ dvrManager.stopRecording(getRecording());
+ }
+ getActivity().finish();
+ }
+ };
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DetailsContent.java b/src/com/android/tv/dvr/ui/DetailsContent.java
new file mode 100644
index 00000000..19521fca
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DetailsContent.java
@@ -0,0 +1,207 @@
+/*
+ * 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.media.tv.TvContract;
+import android.support.annotation.Nullable;
+import android.text.TextUtils;
+
+import com.android.tv.data.BaseProgram;
+import com.android.tv.data.Channel;
+
+/**
+ * A class for details content.
+ */
+public class DetailsContent {
+ /** Constant for invalid time. */
+ public static final long INVALID_TIME = -1;
+
+ private CharSequence mTitle;
+ private long mStartTimeUtcMillis;
+ private long mEndTimeUtcMillis;
+ private String mDescription;
+ private String mLogoImageUri;
+ private String mBackgroundImageUri;
+
+ private DetailsContent() { }
+
+ /**
+ * Returns title.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns start time.
+ */
+ public long getStartTimeUtcMillis() {
+ return mStartTimeUtcMillis;
+ }
+
+ /**
+ * Returns end time.
+ */
+ public long getEndTimeUtcMillis() {
+ return mEndTimeUtcMillis;
+ }
+
+ /**
+ * Returns description.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns Logo image URI as a String.
+ */
+ public String getLogoImageUri() {
+ return mLogoImageUri;
+ }
+
+ /**
+ * Returns background image URI as a String.
+ */
+ public String getBackgroundImageUri() {
+ return mBackgroundImageUri;
+ }
+
+ /**
+ * Copies other details content.
+ */
+ public void copyFrom(DetailsContent other) {
+ if (this == other) {
+ return;
+ }
+ mTitle = other.mTitle;
+ mStartTimeUtcMillis = other.mStartTimeUtcMillis;
+ mEndTimeUtcMillis = other.mEndTimeUtcMillis;
+ mDescription = other.mDescription;
+ mLogoImageUri = other.mLogoImageUri;
+ mBackgroundImageUri = other.mBackgroundImageUri;
+ }
+
+ /**
+ * A class for building details content.
+ */
+ public static final class Builder {
+ private final DetailsContent mDetailsContent;
+
+ public Builder() {
+ mDetailsContent = new DetailsContent();
+ mDetailsContent.mStartTimeUtcMillis = INVALID_TIME;
+ mDetailsContent.mEndTimeUtcMillis = INVALID_TIME;
+ }
+
+ /**
+ * Sets title.
+ */
+ public Builder setTitle(CharSequence title) {
+ mDetailsContent.mTitle = title;
+ return this;
+ }
+
+ /**
+ * Sets start time.
+ */
+ public Builder setStartTimeUtcMillis(long startTimeUtcMillis) {
+ mDetailsContent.mStartTimeUtcMillis = startTimeUtcMillis;
+ return this;
+ }
+
+ /**
+ * Sets end time.
+ */
+ public Builder setEndTimeUtcMillis(long endTimeUtcMillis) {
+ mDetailsContent.mEndTimeUtcMillis = endTimeUtcMillis;
+ return this;
+ }
+
+ /**
+ * Sets description.
+ */
+ public Builder setDescription(String description) {
+ mDetailsContent.mDescription = description;
+ return this;
+ }
+
+ /**
+ * Sets logo image URI as a String.
+ */
+ public Builder setLogoImageUri(String logoImageUri) {
+ mDetailsContent.mLogoImageUri = logoImageUri;
+ return this;
+ }
+
+ /**
+ * Sets background image URI as a String.
+ */
+ public Builder setBackgroundImageUri(String backgroundImageUri) {
+ mDetailsContent.mBackgroundImageUri = backgroundImageUri;
+ return this;
+ }
+
+ /**
+ * Sets background image and logo image URI from program and channel.
+ */
+ public Builder setImageUris(@Nullable BaseProgram program, @Nullable Channel channel) {
+ if (program != null) {
+ return setImageUris(program.getPosterArtUri(), program.getThumbnailUri(), channel);
+ } else {
+ return setImageUris(null, null, channel);
+ }
+ }
+
+ /**
+ * Sets background image and logo image URI and channel is used for fallback images.
+ */
+ public Builder setImageUris(@Nullable String posterArtUri,
+ @Nullable String thumbnailUri, @Nullable Channel channel) {
+ mDetailsContent.mLogoImageUri = null;
+ mDetailsContent.mBackgroundImageUri = null;
+ if (!TextUtils.isEmpty(posterArtUri) && !TextUtils.isEmpty(thumbnailUri)) {
+ mDetailsContent.mLogoImageUri = posterArtUri;
+ mDetailsContent.mBackgroundImageUri = thumbnailUri;
+ } else if (!TextUtils.isEmpty(posterArtUri)) {
+ // thumbnailUri is empty
+ mDetailsContent.mLogoImageUri = posterArtUri;
+ mDetailsContent.mBackgroundImageUri = posterArtUri;
+ } else if (!TextUtils.isEmpty(thumbnailUri)) {
+ // posterArtUri is empty
+ mDetailsContent.mLogoImageUri = thumbnailUri;
+ mDetailsContent.mBackgroundImageUri = thumbnailUri;
+ }
+ if (TextUtils.isEmpty(mDetailsContent.mLogoImageUri) && channel != null) {
+ String channelLogoUri = TvContract.buildChannelLogoUri(channel.getId())
+ .toString();
+ mDetailsContent.mLogoImageUri = channelLogoUri;
+ mDetailsContent.mBackgroundImageUri = channelLogoUri;
+ }
+ return this;
+ }
+
+ /**
+ * Builds details content.
+ */
+ public DetailsContent build() {
+ DetailsContent detailsContent = new DetailsContent();
+ detailsContent.copyFrom(mDetailsContent);
+ return detailsContent;
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DetailsContentPresenter.java b/src/com/android/tv/dvr/ui/DetailsContentPresenter.java
new file mode 100644
index 00000000..175f05bc
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DetailsContentPresenter.java
@@ -0,0 +1,300 @@
+/*
+ * 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.app.Activity;
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.graphics.Paint;
+import android.graphics.Paint.FontMetricsInt;
+import android.support.v17.leanback.widget.Presenter;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.tv.R;
+import com.android.tv.ui.ViewUtils;
+import com.android.tv.util.Utils;
+
+/**
+ * An {@link Presenter} for rendering a detailed description of an DVR item.
+ * Typically this Presenter will be used in a {@link DetailsOverviewRowPresenter}.
+ * Most codes of this class is originated from
+ * {@link android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter}.
+ * The latter class are re-used to provide a customized version of
+ * {@link android.support.v17.leanback.widget.DetailsOverviewRow}.
+ */
+public class DetailsContentPresenter extends Presenter {
+ /**
+ * The ViewHolder for the {@link DetailsContentPresenter}.
+ */
+ public static class ViewHolder extends Presenter.ViewHolder {
+ final TextView mTitle;
+ final TextView mSubtitle;
+ final LinearLayout mDescriptionContainer;
+ final TextView mBody;
+ final TextView mReadMoreView;
+ final int mTitleMargin;
+ final int mUnderTitleBaselineMargin;
+ final int mUnderSubtitleBaselineMargin;
+ final int mTitleLineSpacing;
+ final int mBodyLineSpacing;
+ final int mBodyMaxLines;
+ final int mBodyMinLines;
+ final FontMetricsInt mTitleFontMetricsInt;
+ final FontMetricsInt mSubtitleFontMetricsInt;
+ final FontMetricsInt mBodyFontMetricsInt;
+ final int mTitleMaxLines;
+
+ private Activity mActivity;
+ private boolean mFullTextMode;
+ private int mFullTextAnimationDuration;
+ private boolean mIsListeningToPreDraw;
+
+ private ViewTreeObserver.OnPreDrawListener mPreDrawListener =
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ if (mSubtitle.getVisibility() == View.VISIBLE
+ && mSubtitle.getTop() > view.getHeight()
+ && mTitle.getLineCount() > 1) {
+ mTitle.setMaxLines(mTitle.getLineCount() - 1);
+ return false;
+ }
+ final int bodyLines = mBody.getLineCount();
+ final int maxLines = mFullTextMode ? bodyLines :
+ (mTitle.getLineCount() > 1 ? mBodyMinLines : mBodyMaxLines);
+ if (bodyLines > maxLines) {
+ mReadMoreView.setVisibility(View.VISIBLE);
+ mDescriptionContainer.setFocusable(true);
+ mDescriptionContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mFullTextMode = true;
+ mReadMoreView.setVisibility(View.GONE);
+ mDescriptionContainer.setFocusable(false);
+ mDescriptionContainer.setOnClickListener(null);
+ mBody.setMaxLines(bodyLines);
+ // Minus 1 from line difference to eliminate the space
+ // originally occupied by "READ MORE"
+ showFullText((bodyLines - maxLines - 1) * mBodyLineSpacing);
+ }
+ });
+ }
+ if (mBody.getMaxLines() != maxLines) {
+ mBody.setMaxLines(maxLines);
+ return false;
+ } else {
+ removePreDrawListener();
+ return true;
+ }
+ }
+ };
+
+ public ViewHolder(final View view) {
+ super(view);
+ mTitle = (TextView) view.findViewById(R.id.dvr_details_description_title);
+ mSubtitle = (TextView) view.findViewById(R.id.dvr_details_description_subtitle);
+ mBody = (TextView) view.findViewById(R.id.dvr_details_description_body);
+ mDescriptionContainer =
+ (LinearLayout) view.findViewById(R.id.dvr_details_description_container);
+ mReadMoreView = (TextView) view.findViewById(R.id.dvr_details_description_read_more);
+
+ FontMetricsInt titleFontMetricsInt = getFontMetricsInt(mTitle);
+ final int titleAscent = view.getResources().getDimensionPixelSize(
+ R.dimen.lb_details_description_title_baseline);
+ // Ascent is negative
+ mTitleMargin = titleAscent + titleFontMetricsInt.ascent;
+
+ mUnderTitleBaselineMargin = view.getResources().getDimensionPixelSize(
+ R.dimen.lb_details_description_under_title_baseline_margin);
+ mUnderSubtitleBaselineMargin = view.getResources().getDimensionPixelSize(
+ R.dimen.lb_details_description_under_subtitle_baseline_margin);
+
+ mTitleLineSpacing = view.getResources().getDimensionPixelSize(
+ R.dimen.lb_details_description_title_line_spacing);
+ mBodyLineSpacing = view.getResources().getDimensionPixelSize(
+ R.dimen.lb_details_description_body_line_spacing);
+
+ mBodyMaxLines = view.getResources().getInteger(
+ R.integer.lb_details_description_body_max_lines);
+ mBodyMinLines = view.getResources().getInteger(
+ R.integer.lb_details_description_body_min_lines);
+ mTitleMaxLines = mTitle.getMaxLines();
+
+ mTitleFontMetricsInt = getFontMetricsInt(mTitle);
+ mSubtitleFontMetricsInt = getFontMetricsInt(mSubtitle);
+ mBodyFontMetricsInt = getFontMetricsInt(mBody);
+ }
+
+ void addPreDrawListener() {
+ if (!mIsListeningToPreDraw) {
+ mIsListeningToPreDraw = true;
+ view.getViewTreeObserver().addOnPreDrawListener(mPreDrawListener);
+ }
+ }
+
+ void removePreDrawListener() {
+ if (mIsListeningToPreDraw) {
+ view.getViewTreeObserver().removeOnPreDrawListener(mPreDrawListener);
+ mIsListeningToPreDraw = false;
+ }
+ }
+
+ public TextView getTitle() {
+ return mTitle;
+ }
+
+ public TextView getSubtitle() {
+ return mSubtitle;
+ }
+
+ public TextView getBody() {
+ return mBody;
+ }
+
+ private FontMetricsInt getFontMetricsInt(TextView textView) {
+ Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ paint.setTextSize(textView.getTextSize());
+ paint.setTypeface(textView.getTypeface());
+ return paint.getFontMetricsInt();
+ }
+
+ private void showFullText(int heightDiff) {
+ final ViewGroup detailsFrame = (ViewGroup) mActivity.findViewById(R.id.details_frame);
+ int nowHeight = ViewUtils.getLayoutHeight(detailsFrame);
+ Animator expandAnimator = ViewUtils.createHeightAnimator(
+ detailsFrame, nowHeight, nowHeight + heightDiff);
+ expandAnimator.setDuration(mFullTextAnimationDuration);
+ Animator shiftAnimator = ObjectAnimator.ofPropertyValuesHolder(detailsFrame,
+ PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
+ 0f, -(heightDiff / 2)));
+ shiftAnimator.setDuration(mFullTextAnimationDuration);
+ AnimatorSet fullTextAnimator = new AnimatorSet();
+ fullTextAnimator.playTogether(expandAnimator, shiftAnimator);
+ fullTextAnimator.start();
+ }
+ }
+
+ private final Activity mActivity;
+ private final int mFullTextAnimationDuration;
+
+ public DetailsContentPresenter(Activity activity) {
+ super();
+ mActivity = activity;
+ mFullTextAnimationDuration = mActivity.getResources()
+ .getInteger(R.integer.dvr_details_full_text_animation_duration);
+ }
+
+ @Override
+ public final ViewHolder onCreateViewHolder(ViewGroup parent) {
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.dvr_details_description, parent, false);
+ return new ViewHolder(v);
+ }
+
+ @Override
+ public final void onBindViewHolder(Presenter.ViewHolder viewHolder, Object item) {
+ final ViewHolder vh = (ViewHolder) viewHolder;
+ final DetailsContent detailsContent = (DetailsContent) item;
+
+ vh.mActivity = mActivity;
+ vh.mFullTextAnimationDuration = mFullTextAnimationDuration;
+
+ boolean hasTitle = true;
+ if (TextUtils.isEmpty(detailsContent.getTitle())) {
+ vh.mTitle.setVisibility(View.GONE);
+ hasTitle = false;
+ } else {
+ vh.mTitle.setText(detailsContent.getTitle());
+ vh.mTitle.setVisibility(View.VISIBLE);
+ vh.mTitle.setLineSpacing(vh.mTitleLineSpacing - vh.mTitle.getLineHeight()
+ + vh.mTitle.getLineSpacingExtra(), vh.mTitle.getLineSpacingMultiplier());
+ vh.mTitle.setMaxLines(vh.mTitleMaxLines);
+ }
+ setTopMargin(vh.mTitle, vh.mTitleMargin);
+
+ boolean hasSubtitle = true;
+ if (detailsContent.getStartTimeUtcMillis() != DetailsContent.INVALID_TIME
+ && detailsContent.getEndTimeUtcMillis() != DetailsContent.INVALID_TIME) {
+ vh.mSubtitle.setText(Utils.getDurationString(viewHolder.view.getContext(),
+ detailsContent.getStartTimeUtcMillis(),
+ detailsContent.getEndTimeUtcMillis(), false));
+ vh.mSubtitle.setVisibility(View.VISIBLE);
+ if (hasTitle) {
+ setTopMargin(vh.mSubtitle, vh.mUnderTitleBaselineMargin
+ + vh.mSubtitleFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent);
+ } else {
+ setTopMargin(vh.mSubtitle, 0);
+ }
+ } else {
+ vh.mSubtitle.setVisibility(View.GONE);
+ hasSubtitle = false;
+ }
+
+ if (TextUtils.isEmpty(detailsContent.getDescription())) {
+ vh.mBody.setVisibility(View.GONE);
+ } else {
+ vh.mBody.setText(detailsContent.getDescription());
+ vh.mBody.setVisibility(View.VISIBLE);
+ vh.mBody.setLineSpacing(vh.mBodyLineSpacing - vh.mBody.getLineHeight()
+ + vh.mBody.getLineSpacingExtra(), vh.mBody.getLineSpacingMultiplier());
+ if (hasSubtitle) {
+ setTopMargin(vh.mDescriptionContainer, vh.mUnderSubtitleBaselineMargin
+ + vh.mBodyFontMetricsInt.ascent - vh.mSubtitleFontMetricsInt.descent
+ - vh.mBody.getPaddingTop());
+ } else if (hasTitle) {
+ setTopMargin(vh.mDescriptionContainer, vh.mUnderTitleBaselineMargin
+ + vh.mBodyFontMetricsInt.ascent - vh.mTitleFontMetricsInt.descent
+ - vh.mBody.getPaddingTop());
+ } else {
+ setTopMargin(vh.mDescriptionContainer, 0);
+ }
+ }
+ }
+
+ @Override
+ public void onUnbindViewHolder(Presenter.ViewHolder viewHolder) { }
+
+ @Override
+ public void onViewAttachedToWindow(Presenter.ViewHolder holder) {
+ // In case predraw listener was removed in detach, make sure
+ // we have the proper layout.
+ ViewHolder vh = (ViewHolder) holder;
+ vh.addPreDrawListener();
+ super.onViewAttachedToWindow(holder);
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(Presenter.ViewHolder holder) {
+ ViewHolder vh = (ViewHolder) holder;
+ vh.removePreDrawListener();
+ super.onViewDetachedFromWindow(holder);
+ }
+
+ private void setTopMargin(View view, int topMargin) {
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
+ lp.topMargin = topMargin;
+ view.setLayoutParams(lp);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DetailsViewBackgroundHelper.java b/src/com/android/tv/dvr/ui/DetailsViewBackgroundHelper.java
new file mode 100644
index 00000000..6714ecd3
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DetailsViewBackgroundHelper.java
@@ -0,0 +1,92 @@
+/*
+ * 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.app.Activity;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.support.v17.leanback.app.BackgroundManager;
+
+/**
+ * The Background Helper.
+ */
+public class DetailsViewBackgroundHelper {
+ // Background delay serves to avoid kicking off expensive bitmap loading
+ // in case multiple backgrounds are set in quick succession.
+ private static final int SET_BACKGROUND_DELAY_MS = 100;
+
+ private final BackgroundManager mBackgroundManager;
+
+ class LoadBackgroundRunnable implements Runnable {
+ final Drawable mBackGround;
+
+ LoadBackgroundRunnable(Drawable background) {
+ mBackGround = background;
+ }
+
+ @Override
+ public void run() {
+ if (!mBackgroundManager.isAttached()) {
+ return;
+ }
+ if (mBackGround instanceof BitmapDrawable) {
+ mBackgroundManager.setBitmap(((BitmapDrawable) mBackGround).getBitmap());
+ }
+ mRunnable = null;
+ }
+ }
+
+ private LoadBackgroundRunnable mRunnable;
+
+ private final Handler mHandler = new Handler();
+
+ public DetailsViewBackgroundHelper(Activity activity) {
+ mBackgroundManager = BackgroundManager.getInstance(activity);
+ mBackgroundManager.attach(activity.getWindow());
+ }
+
+ /**
+ * Sets the given image to background.
+ */
+ public void setBackground(Drawable background) {
+ if (mRunnable != null) {
+ mHandler.removeCallbacks(mRunnable);
+ }
+ mRunnable = new LoadBackgroundRunnable(background);
+ mHandler.postDelayed(mRunnable, SET_BACKGROUND_DELAY_MS);
+ }
+
+ /**
+ * Sets the background color.
+ */
+ public void setBackgroundColor(int color) {
+ if (mBackgroundManager.isAttached()) {
+ mBackgroundManager.setColor(color);
+ }
+ }
+
+ /**
+ * Sets the background scrim.
+ */
+ public void setScrim(int color) {
+ if (mBackgroundManager.isAttached()) {
+ mBackgroundManager.setDimLayer(new ColorDrawable(color));
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrActivity.java b/src/com/android/tv/dvr/ui/DvrActivity.java
index 01f3fb9c..45fb1cf1 100644
--- a/src/com/android/tv/dvr/ui/DvrActivity.java
+++ b/src/com/android/tv/dvr/ui/DvrActivity.java
@@ -20,6 +20,7 @@ import android.app.Activity;
import android.os.Bundle;
import com.android.tv.R;
+import com.android.tv.TvApplication;
/**
* {@link android.app.Activity} for DVR UI.
@@ -27,6 +28,7 @@ import com.android.tv.R;
public class DvrActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate(savedInstanceState);
setContentView(R.layout.dvr_main);
}
diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java
new file mode 100644
index 00000000..9df228d1
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrAlreadyRecordedFragment.java
@@ -0,0 +1,103 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.util.Utils;
+
+import java.util.List;
+
+/**
+ * A fragment which notifies the user that the same episode has already been scheduled.
+ *
+ * <p>Note that the schedule has not been created yet.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrAlreadyRecordedFragment extends DvrGuidedStepFragment {
+ private static final int ACTION_RECORD_ANYWAY = 1;
+ private static final int ACTION_WATCH = 2;
+ private static final int ACTION_CANCEL = 3;
+
+ private Program mProgram;
+ private RecordedProgram mDuplicate;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mProgram = getArguments().getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
+ DvrManager dvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mDuplicate = dvrManager.getRecordedProgram(mProgram.getTitle(),
+ mProgram.getSeasonNumber(), mProgram.getEpisodeNumber());
+ if (mDuplicate == null) {
+ dvrManager.addSchedule(mProgram);
+ DvrUiHelper.showAddScheduleToast(context, mProgram.getTitle(),
+ mProgram.getStartTimeUtcMillis(), mProgram.getEndTimeUtcMillis());
+ dismissDialog();
+ }
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_already_recorded_dialog_title);
+ String description = getString(R.string.dvr_already_recorded_dialog_description);
+ Drawable image = getResources().getDrawable(R.drawable.ic_warning_white_96dp, null);
+ return new Guidance(title, description, null, image);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Context context = getContext();
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_RECORD_ANYWAY)
+ .title(R.string.dvr_action_record_anyway)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_WATCH)
+ .title(R.string.dvr_action_watch_now)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_CANCEL)
+ .title(R.string.dvr_action_record_cancel)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_RECORD_ANYWAY) {
+ getDvrManager().addSchedule(mProgram);
+ } else if (action.getId() == ACTION_WATCH) {
+ DvrUiHelper.startDetailsActivity(getActivity(), mDuplicate, null, false);
+ }
+ dismissDialog();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java
new file mode 100644
index 00000000..78f21784
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrAlreadyScheduledFragment.java
@@ -0,0 +1,107 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.text.format.DateUtils;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.util.Utils;
+
+import java.util.List;
+
+/**
+ * A fragment which notifies the user that the same episode has already been scheduled.
+ *
+ * <p>Note that the schedule has not been created yet.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrAlreadyScheduledFragment extends DvrGuidedStepFragment {
+ private static final int ACTION_RECORD_ANYWAY = 1;
+ private static final int ACTION_RECORD_INSTEAD = 2;
+ private static final int ACTION_CANCEL = 3;
+
+ private Program mProgram;
+ private ScheduledRecording mDuplicate;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mProgram = getArguments().getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
+ DvrManager dvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mDuplicate = dvrManager.getScheduledRecording(mProgram.getTitle(),
+ mProgram.getSeasonNumber(), mProgram.getEpisodeNumber());
+ if (mDuplicate == null) {
+ dvrManager.addSchedule(mProgram);
+ DvrUiHelper.showAddScheduleToast(context, mProgram.getTitle(),
+ mProgram.getStartTimeUtcMillis(), mProgram.getEndTimeUtcMillis());
+ dismissDialog();
+ }
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_already_scheduled_dialog_title);
+ String description = getString(R.string.dvr_already_scheduled_dialog_description,
+ DateUtils.formatDateTime(getContext(), mDuplicate.getStartTimeMs(),
+ DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE));
+ Drawable image = getResources().getDrawable(R.drawable.ic_warning_white_96dp, null);
+ return new Guidance(title, description, null, image);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Context context = getContext();
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_RECORD_ANYWAY)
+ .title(R.string.dvr_action_record_anyway)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_RECORD_INSTEAD)
+ .title(R.string.dvr_action_record_instead)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_CANCEL)
+ .title(R.string.dvr_action_record_cancel)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_RECORD_ANYWAY) {
+ getDvrManager().addSchedule(mProgram);
+ } else if (action.getId() == ACTION_RECORD_INSTEAD) {
+ getDvrManager().addSchedule(mProgram);
+ getDvrManager().removeScheduledRecording(mDuplicate);
+ }
+ dismissDialog();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/DvrBrowseFragment.java
index 70e71cab..a6dd31d1 100644
--- a/src/com/android/tv/dvr/ui/DvrBrowseFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrBrowseFragment.java
@@ -16,140 +16,586 @@
package com.android.tv.dvr.ui;
+import android.content.Context;
+import android.media.tv.TvInputManager.TvInputCallback;
import android.os.Bundle;
-import android.support.annotation.IntDef;
+import android.os.Handler;
import android.support.v17.leanback.app.BrowseFragment;
import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.ClassPresenterSelector;
import android.support.v17.leanback.widget.HeaderItem;
import android.support.v17.leanback.widget.ListRow;
import android.support.v17.leanback.widget.ListRowPresenter;
-import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.v17.leanback.widget.Presenter;
+import android.support.v17.leanback.widget.TitleViewAdapter;
+import android.text.TextUtils;
import android.util.Log;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
import com.android.tv.TvApplication;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.data.GenreItems;
import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.RecordedProgram;
import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.LinkedHashMap;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
/**
* {@link BrowseFragment} for DVR functions.
*/
-public class DvrBrowseFragment extends BrowseFragment {
+public class DvrBrowseFragment extends BrowseFragment implements
+ RecordedProgramListener, ScheduledRecordingListener, SeriesRecordingListener,
+ OnDvrScheduleLoadFinishedListener, OnRecordedProgramLoadFinishedListener {
private static final String TAG = "DvrBrowseFragment";
private static final boolean DEBUG = false;
- private ScheduledRecordingsAdapter mRecordingsInProgressAdapter;
- private ScheduledRecordingsAdapter mRecordingsNotStatedAdapter;
- private RecordedProgramsAdapter mRecordedProgramsAdapter;
-
- @IntDef({DVR_CURRENT_RECORDINGS, DVR_SCHEDULED_RECORDINGS, DVR_RECORDED_PROGRAMS, DVR_SETTINGS})
- @Retention(RetentionPolicy.SOURCE)
- public @interface DVR_HEADERS_MODE {}
- public static final int DVR_CURRENT_RECORDINGS = 0;
- public static final int DVR_SCHEDULED_RECORDINGS = 1;
- public static final int DVR_RECORDED_PROGRAMS = 2;
- public static final int DVR_SETTINGS = 3;
-
- private static final LinkedHashMap<Integer, Integer> sHeaders =
- new LinkedHashMap<Integer, Integer>() {{
- put(DVR_CURRENT_RECORDINGS, R.string.dvr_main_current_recordings);
- put(DVR_SCHEDULED_RECORDINGS, R.string.dvr_main_scheduled_recordings);
- put(DVR_RECORDED_PROGRAMS, R.string.dvr_main_recorded_programs);
- /* put(DVR_SETTINGS, R.string.dvr_main_settings); */ // TODO: Temporarily remove it for DP.
- }};
+ private static final int MAX_RECENT_ITEM_COUNT = 10;
+ private static final int MAX_SCHEDULED_ITEM_COUNT = 4;
+ private RecordedProgramAdapter mRecentAdapter;
+ private ScheduleAdapter mScheduleAdapter;
+ private SeriesAdapter mSeriesAdapter;
+ private RecordedProgramAdapter[] mGenreAdapters =
+ new RecordedProgramAdapter[GenreItems.getGenreCount() + 1];
+ private ListRow mRecentRow;
+ private ListRow mSeriesRow;
+ private ListRow[] mGenreRows = new ListRow[GenreItems.getGenreCount() + 1];
+ private List<String> mGenreLabels;
private DvrDataManager mDvrDataManager;
+ private DvrScheduleManager mDvrScheudleManager;
private ArrayObjectAdapter mRowsAdapter;
+ private ClassPresenterSelector mPresenterSelector;
+ private final HashMap<String, RecordedProgram> mSeriesId2LatestProgram = new HashMap<>();
+ private final Handler mHandler = new Handler();
+
+ private final Comparator<Object> RECORDED_PROGRAM_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object lhs, Object rhs) {
+ if (lhs instanceof SeriesRecording) {
+ lhs = mSeriesId2LatestProgram.get(((SeriesRecording) lhs).getSeriesId());
+ }
+ if (rhs instanceof SeriesRecording) {
+ rhs = mSeriesId2LatestProgram.get(((SeriesRecording) rhs).getSeriesId());
+ }
+ if (lhs instanceof RecordedProgram) {
+ if (rhs instanceof RecordedProgram) {
+ return RecordedProgram.START_TIME_THEN_ID_COMPARATOR.reversed()
+ .compare((RecordedProgram) lhs, (RecordedProgram) rhs);
+ } else {
+ return -1;
+ }
+ } else if (rhs instanceof RecordedProgram) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ };
+
+ private final Comparator<Object> SCHEDULE_COMPARATOR = new Comparator<Object>() {
+ @Override
+ public int compare(Object lhs, Object rhs) {
+ if (lhs instanceof ScheduledRecording) {
+ if (rhs instanceof ScheduledRecording) {
+ return ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR
+ .compare((ScheduledRecording) lhs, (ScheduledRecording) rhs);
+ } else {
+ return -1;
+ }
+ } else if (rhs instanceof ScheduledRecording) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ };
+
+ private final DvrScheduleManager.OnConflictStateChangeListener mOnConflictStateChangeListener =
+ new DvrScheduleManager.OnConflictStateChangeListener() {
+ @Override
+ public void onConflictStateChange(boolean conflict, ScheduledRecording... schedules) {
+ if (mScheduleAdapter != null) {
+ for (ScheduledRecording schedule : schedules) {
+ onScheduledRecordingStatusChanged(schedule);
+ }
+ }
+ }
+ };
+
+ private final Runnable mUpdateRowsRunnable = new Runnable() {
+ @Override
+ public void run() {
+ updateRows();
+ }
+ };
@Override
public void onCreate(Bundle savedInstanceState) {
if (DEBUG) Log.d(TAG, "onCreate");
super.onCreate(savedInstanceState);
- mDvrDataManager = TvApplication.getSingletons(getContext()).getDvrDataManager();
+ Context context = getContext();
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
+ mDvrDataManager = singletons.getDvrDataManager();
+ mDvrScheudleManager = singletons.getDvrScheduleManager();
+ mPresenterSelector = new ClassPresenterSelector()
+ .addClassPresenter(ScheduledRecording.class,
+ new ScheduledRecordingPresenter(context))
+ .addClassPresenter(RecordedProgram.class, new RecordedProgramPresenter(context))
+ .addClassPresenter(SeriesRecording.class, new SeriesRecordingPresenter(context))
+ .addClassPresenter(FullScheduleCardHolder.class, new FullSchedulesCardPresenter());
+ mGenreLabels = new ArrayList<>(Arrays.asList(GenreItems.getLabels(context)));
+ mGenreLabels.add(getString(R.string.dvr_main_others));
setupUiElements();
setupAdapters();
- mRecordingsInProgressAdapter.start();
- mRecordingsNotStatedAdapter.start();
- mRecordedProgramsAdapter.start();
- initRows();
+ mDvrScheudleManager.addOnConflictStateChangeListener(mOnConflictStateChangeListener);
prepareEntranceTransition();
- startEntranceTransition();
- }
-
- @Override
- public void onStart() {
- if (DEBUG) Log.d(TAG, "onStart");
- super.onStart();
- // TODO: It's a workaround for a bug that a progress bar isn't hidden.
- // We need to remove it later.
- getProgressBarManager().disableProgressBar();
+ if (mDvrDataManager.isInitialized()) {
+ startEntranceTransition();
+ } else {
+ if (!mDvrDataManager.isDvrScheduleLoadFinished()) {
+ mDvrDataManager.addDvrScheduleLoadFinishedListener(this);
+ }
+ if (!mDvrDataManager.isRecordedProgramLoadFinished()) {
+ mDvrDataManager.addRecordedProgramLoadFinishedListener(this);
+ }
+ }
}
@Override
public void onDestroy() {
if (DEBUG) Log.d(TAG, "onDestroy");
- mRecordingsInProgressAdapter.stop();
- mRecordingsNotStatedAdapter.stop();
- mRecordedProgramsAdapter.stop();
+ mHandler.removeCallbacks(mUpdateRowsRunnable);
+ mDvrScheudleManager.removeOnConflictStateChangeListener(mOnConflictStateChangeListener);
+ mDvrDataManager.removeRecordedProgramListener(this);
+ mDvrDataManager.removeScheduledRecordingListener(this);
+ mDvrDataManager.removeSeriesRecordingListener(this);
+ mDvrDataManager.removeDvrScheduleLoadFinishedListener(this);
+ mDvrDataManager.removeRecordedProgramLoadFinishedListener(this);
+ mRowsAdapter.clear();
+ mSeriesId2LatestProgram.clear();
+ for (Presenter presenter : mPresenterSelector.getPresenters()) {
+ if (presenter instanceof DvrItemPresenter) {
+ ((DvrItemPresenter) presenter).unbindAllViewHolders();
+ }
+ }
super.onDestroy();
}
+ @Override
+ public void onDvrScheduleLoadFinished() {
+ List<ScheduledRecording> scheduledRecordings = mDvrDataManager.getAllScheduledRecordings();
+ onScheduledRecordingAdded(ScheduledRecording.toArray(scheduledRecordings));
+ List<SeriesRecording> seriesRecordings = mDvrDataManager.getSeriesRecordings();
+ onSeriesRecordingAdded(SeriesRecording.toArray(seriesRecordings));
+ if (mDvrDataManager.isInitialized()) {
+ startEntranceTransition();
+ }
+ mDvrDataManager.removeDvrScheduleLoadFinishedListener(this);
+ }
+
+ @Override
+ public void onRecordedProgramLoadFinished() {
+ for (RecordedProgram recordedProgram : mDvrDataManager.getRecordedPrograms()) {
+ handleRecordedProgramAdded(recordedProgram, true);
+ }
+ updateRows();
+ if (mDvrDataManager.isInitialized()) {
+ startEntranceTransition();
+ }
+ mDvrDataManager.removeRecordedProgramLoadFinishedListener(this);
+ }
+
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ handleRecordedProgramAdded(recordedProgram, true);
+ }
+ postUpdateRows();
+ }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ handleRecordedProgramChanged(recordedProgram);
+ }
+ postUpdateRows();
+ }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ handleRecordedProgramRemoved(recordedProgram);
+ }
+ postUpdateRows();
+ }
+
+ // No need to call updateRows() during ScheduledRecordings' change because
+ // the row for ScheduledRecordings is always displayed.
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording scheduleRecording : scheduledRecordings) {
+ if (needToShowScheduledRecording(scheduleRecording)) {
+ mScheduleAdapter.add(scheduleRecording);
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording scheduleRecording : scheduledRecordings) {
+ mScheduleAdapter.remove(scheduleRecording);
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording scheduleRecording : scheduledRecordings) {
+ if (needToShowScheduledRecording(scheduleRecording)) {
+ mScheduleAdapter.change(scheduleRecording);
+ } else {
+ mScheduleAdapter.removeWithId(scheduleRecording);
+ }
+ }
+ }
+
+ @Override
+ public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) {
+ handleSeriesRecordingsAdded(Arrays.asList(seriesRecordings));
+ postUpdateRows();
+ }
+
+ @Override
+ public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
+ handleSeriesRecordingsRemoved(Arrays.asList(seriesRecordings));
+ postUpdateRows();
+ }
+
+ @Override
+ public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ handleSeriesRecordingsChanged(Arrays.asList(seriesRecordings));
+ postUpdateRows();
+ }
+
+ // Workaround of b/29108300
+ @Override
+ public void showTitle(int flags) {
+ flags &= ~TitleViewAdapter.SEARCH_VIEW_VISIBLE;
+ super.showTitle(flags);
+ }
+
private void setupUiElements() {
+ setBadgeDrawable(getActivity().getDrawable(R.drawable.ic_dvr_badge));
setHeadersState(HEADERS_ENABLED);
setHeadersTransitionOnBackEnabled(false);
+ setBrandColor(getResources().getColor(R.color.program_guide_side_panel_background, null));
}
private void setupAdapters() {
+ mRecentAdapter = new RecordedProgramAdapter(MAX_RECENT_ITEM_COUNT);
+ mScheduleAdapter = new ScheduleAdapter(MAX_SCHEDULED_ITEM_COUNT);
+ mSeriesAdapter = new SeriesAdapter();
+ for (int i = 0; i < mGenreAdapters.length; i++) {
+ mGenreAdapters[i] = new RecordedProgramAdapter();
+ }
+ // Schedule Recordings.
+ List<ScheduledRecording> schedules = mDvrDataManager.getAllScheduledRecordings();
+ onScheduledRecordingAdded(ScheduledRecording.toArray(schedules));
+ mScheduleAdapter.addExtraItem(FullScheduleCardHolder.FULL_SCHEDULE_CARD_HOLDER);
+ // Recorded Programs.
+ for (RecordedProgram recordedProgram : mDvrDataManager.getRecordedPrograms()) {
+ handleRecordedProgramAdded(recordedProgram, false);
+ }
+ // Series Recordings. Series recordings should be added after recorded programs, because
+ // we build series recordings' latest program information while adding recorded programs.
+ List<SeriesRecording> recordings = mDvrDataManager.getSeriesRecordings();
+ handleSeriesRecordingsAdded(recordings);
mRowsAdapter = new ArrayObjectAdapter(new ListRowPresenter());
+ mRecentRow = new ListRow(new HeaderItem(
+ getString(R.string.dvr_main_recent)), mRecentAdapter);
+ mRowsAdapter.add(new ListRow(new HeaderItem(
+ getString(R.string.dvr_main_scheduled)), mScheduleAdapter));
+ mSeriesRow = new ListRow(new HeaderItem(
+ getString(R.string.dvr_main_series)), mSeriesAdapter);
+ updateRows();
+ mDvrDataManager.addRecordedProgramListener(this);
+ mDvrDataManager.addScheduledRecordingListener(this);
+ mDvrDataManager.addSeriesRecordingListener(this);
setAdapter(mRowsAdapter);
- ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
- EmptyItemPresenter emptyItemPresenter = new EmptyItemPresenter(this);
- ScheduledRecordingPresenter scheduledRecordingPresenter = new ScheduledRecordingPresenter(
- getContext());
- RecordedProgramPresenter recordedProgramPresenter = new RecordedProgramPresenter(
- getContext());
- presenterSelector.addClassPresenter(ScheduledRecording.class, scheduledRecordingPresenter);
- presenterSelector.addClassPresenter(RecordedProgram.class, recordedProgramPresenter);
- presenterSelector.addClassPresenter(EmptyHolder.class, emptyItemPresenter);
- mRecordingsInProgressAdapter = new ScheduledRecordingsAdapter(mDvrDataManager,
- ScheduledRecording.STATE_RECORDING_IN_PROGRESS, presenterSelector);
- mRecordingsNotStatedAdapter = new ScheduledRecordingsAdapter(mDvrDataManager,
- ScheduledRecording.STATE_RECORDING_NOT_STARTED, presenterSelector);
- mRecordedProgramsAdapter = new RecordedProgramsAdapter(mDvrDataManager, presenterSelector);
- }
-
- private void initRows() {
- mRowsAdapter.clear();
- for (@DVR_HEADERS_MODE int i : sHeaders.keySet()) {
- HeaderItem gridHeader = new HeaderItem(i, getContext().getString(sHeaders.get(i)));
- ObjectAdapter gridRowAdapter = null;
- switch (i) {
- case DVR_CURRENT_RECORDINGS: {
- gridRowAdapter = mRecordingsInProgressAdapter;
- break;
+ }
+
+ private void handleRecordedProgramAdded(RecordedProgram recordedProgram,
+ boolean updateSeriesRecording) {
+ mRecentAdapter.add(recordedProgram);
+ String seriesId = recordedProgram.getSeriesId();
+ SeriesRecording seriesRecording = null;
+ if (seriesId != null) {
+ seriesRecording = mDvrDataManager.getSeriesRecording(seriesId);
+ RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId);
+ if (latestProgram == null || RecordedProgram.START_TIME_THEN_ID_COMPARATOR
+ .compare(latestProgram, recordedProgram) < 0) {
+ mSeriesId2LatestProgram.put(seriesId, recordedProgram);
+ if (updateSeriesRecording && seriesRecording != null) {
+ onSeriesRecordingChanged(seriesRecording);
}
- case DVR_SCHEDULED_RECORDINGS: {
- gridRowAdapter = mRecordingsNotStatedAdapter;
+ }
+ }
+ if (seriesRecording == null) {
+ for (RecordedProgramAdapter adapter
+ : getGenreAdapters(recordedProgram.getCanonicalGenres())) {
+ adapter.add(recordedProgram);
+ }
+ }
+ }
+
+ private void handleRecordedProgramRemoved(RecordedProgram recordedProgram) {
+ mRecentAdapter.remove(recordedProgram);
+ String seriesId = recordedProgram.getSeriesId();
+ if (seriesId != null) {
+ SeriesRecording seriesRecording = mDvrDataManager.getSeriesRecording(seriesId);
+ RecordedProgram latestProgram =
+ mSeriesId2LatestProgram.get(recordedProgram.getSeriesId());
+ if (latestProgram != null && latestProgram.getId() == recordedProgram.getId()) {
+ if (seriesRecording != null) {
+ updateLatestRecordedProgram(seriesRecording);
+ onSeriesRecordingChanged(seriesRecording);
+ }
+ }
+ }
+ for (RecordedProgramAdapter adapter
+ : getGenreAdapters(recordedProgram.getCanonicalGenres())) {
+ adapter.remove(recordedProgram);
+ }
+ }
+
+ private void handleRecordedProgramChanged(RecordedProgram recordedProgram) {
+ mRecentAdapter.change(recordedProgram);
+ String seriesId = recordedProgram.getSeriesId();
+ SeriesRecording seriesRecording = null;
+ if (seriesId != null) {
+ seriesRecording = mDvrDataManager.getSeriesRecording(seriesId);
+ RecordedProgram latestProgram = mSeriesId2LatestProgram.get(seriesId);
+ if (latestProgram == null || RecordedProgram.START_TIME_THEN_ID_COMPARATOR
+ .compare(latestProgram, recordedProgram) <= 0) {
+ mSeriesId2LatestProgram.put(seriesId, recordedProgram);
+ if (seriesRecording != null) {
+ onSeriesRecordingChanged(seriesRecording);
+ }
+ } else if (latestProgram.getId() == recordedProgram.getId()) {
+ if (seriesRecording != null) {
+ updateLatestRecordedProgram(seriesRecording);
+ onSeriesRecordingChanged(seriesRecording);
+ }
+ }
+ }
+ if (seriesRecording == null) {
+ updateGenreAdapters(getGenreAdapters(
+ recordedProgram.getCanonicalGenres()), recordedProgram);
+ } else {
+ updateGenreAdapters(new ArrayList<>(), recordedProgram);
+ }
+ }
+
+ private void handleSeriesRecordingsAdded(List<SeriesRecording> seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ mSeriesAdapter.add(seriesRecording);
+ if (mSeriesId2LatestProgram.get(seriesRecording.getSeriesId()) != null) {
+ for (RecordedProgramAdapter adapter
+ : getGenreAdapters(seriesRecording.getCanonicalGenreIds())) {
+ adapter.add(seriesRecording);
}
- break;
- case DVR_RECORDED_PROGRAMS: {
- gridRowAdapter = mRecordedProgramsAdapter;
+ }
+ }
+ }
+
+ private void handleSeriesRecordingsRemoved(List<SeriesRecording> seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ mSeriesAdapter.remove(seriesRecording);
+ for (RecordedProgramAdapter adapter
+ : getGenreAdapters(seriesRecording.getCanonicalGenreIds())) {
+ adapter.remove(seriesRecording);
+ }
+ }
+ }
+
+ private void handleSeriesRecordingsChanged(List<SeriesRecording> seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ mSeriesAdapter.change(seriesRecording);
+ if (mSeriesId2LatestProgram.get(seriesRecording.getSeriesId()) != null) {
+ updateGenreAdapters(getGenreAdapters(
+ seriesRecording.getCanonicalGenreIds()), seriesRecording);
+ } else {
+ // Remove series recording from all genre rows if it has no recorded program
+ updateGenreAdapters(new ArrayList<>(), seriesRecording);
+ }
+ }
+ }
+
+ private List<RecordedProgramAdapter> getGenreAdapters(String[] genres) {
+ List<RecordedProgramAdapter> result = new ArrayList<>();
+ if (genres == null || genres.length == 0) {
+ result.add(mGenreAdapters[mGenreAdapters.length - 1]);
+ } else {
+ for (String genre : genres) {
+ int genreId = GenreItems.getId(genre);
+ if(genreId >= mGenreAdapters.length) {
+ Log.d(TAG, "Wrong Genre ID: " + genreId);
+ } else {
+ result.add(mGenreAdapters[genreId]);
+ }
+ }
+ }
+ return result;
+ }
+
+ private List<RecordedProgramAdapter> getGenreAdapters(int[] genreIds) {
+ List<RecordedProgramAdapter> result = new ArrayList<>();
+ if (genreIds == null || genreIds.length == 0) {
+ result.add(mGenreAdapters[mGenreAdapters.length - 1]);
+ } else {
+ for (int genreId : genreIds) {
+ if(genreId >= mGenreAdapters.length) {
+ Log.d(TAG, "Wrong Genre ID: " + genreId);
+ } else {
+ result.add(mGenreAdapters[genreId]);
+ }
+ }
+ }
+ return result;
+ }
+
+ private void updateGenreAdapters(List<RecordedProgramAdapter> adapters, Object r) {
+ for (RecordedProgramAdapter adapter : mGenreAdapters) {
+ if (adapters.contains(adapter)) {
+ adapter.change(r);
+ } else {
+ adapter.remove(r);
+ }
+ }
+ }
+
+ private void postUpdateRows() {
+ mHandler.removeCallbacks(mUpdateRowsRunnable);
+ mHandler.post(mUpdateRowsRunnable);
+ }
+
+ private void updateRows() {
+ int visibleRowsCount = 1; // Schedule's Row will never be empty
+ if (mRecentAdapter.isEmpty()) {
+ mRowsAdapter.remove(mRecentRow);
+ } else {
+ if (mRowsAdapter.indexOf(mRecentRow) < 0) {
+ mRowsAdapter.add(0, mRecentRow);
+ }
+ visibleRowsCount++;
+ }
+ if (mSeriesAdapter.isEmpty()) {
+ mRowsAdapter.remove(mSeriesRow);
+ } else {
+ if (mRowsAdapter.indexOf(mSeriesRow) < 0) {
+ mRowsAdapter.add(visibleRowsCount, mSeriesRow);
+ }
+ visibleRowsCount++;
+ }
+ for (int i = 0; i < mGenreAdapters.length; i++) {
+ RecordedProgramAdapter adapter = mGenreAdapters[i];
+ if (adapter != null) {
+ if (adapter.isEmpty()) {
+ mRowsAdapter.remove(mGenreRows[i]);
+ } else {
+ if (mGenreRows[i] == null || mRowsAdapter.indexOf(mGenreRows[i]) < 0) {
+ mGenreRows[i] = new ListRow(new HeaderItem(mGenreLabels.get(i)), adapter);
+ mRowsAdapter.add(visibleRowsCount, mGenreRows[i]);
+ }
+ visibleRowsCount++;
}
- break;
- case DVR_SETTINGS:
- gridRowAdapter = new ArrayObjectAdapter(new EmptyItemPresenter(this));
- // TODO: provide setup rows.
- break;
}
- if (gridRowAdapter != null) {
- mRowsAdapter.add(new ListRow(gridHeader, gridRowAdapter));
+ }
+ }
+
+ private boolean needToShowScheduledRecording(ScheduledRecording recording) {
+ int state = recording.getState();
+ return state == ScheduledRecording.STATE_RECORDING_IN_PROGRESS
+ || state == ScheduledRecording.STATE_RECORDING_NOT_STARTED;
+ }
+
+ private void updateLatestRecordedProgram(SeriesRecording seriesRecording) {
+ RecordedProgram latestProgram = null;
+ for (RecordedProgram program :
+ mDvrDataManager.getRecordedPrograms(seriesRecording.getId())) {
+ if (latestProgram == null || RecordedProgram
+ .START_TIME_THEN_ID_COMPARATOR.compare(latestProgram, program) < 0) {
+ latestProgram = program;
+ }
+ }
+ mSeriesId2LatestProgram.put(seriesRecording.getSeriesId(), latestProgram);
+ }
+
+ private class ScheduleAdapter extends SortedArrayAdapter<Object> {
+ ScheduleAdapter(int maxItemCount) {
+ super(mPresenterSelector, SCHEDULE_COMPARATOR, maxItemCount);
+ }
+
+ @Override
+ public long getId(Object item) {
+ if (item instanceof ScheduledRecording) {
+ return ((ScheduledRecording) item).getId();
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ private class SeriesAdapter extends SortedArrayAdapter<SeriesRecording> {
+ SeriesAdapter() {
+ super(mPresenterSelector, new Comparator<SeriesRecording>() {
+ @Override
+ public int compare(SeriesRecording lhs, SeriesRecording rhs) {
+ if (lhs.isStopped() && !rhs.isStopped()) {
+ return 1;
+ } else if (!lhs.isStopped() && rhs.isStopped()) {
+ return -1;
+ }
+ return SeriesRecording.PRIORITY_COMPARATOR.compare(lhs, rhs);
+ }
+ });
+ }
+
+ @Override
+ public long getId(SeriesRecording item) {
+ return item.getId();
+ }
+ }
+
+ private class RecordedProgramAdapter extends SortedArrayAdapter<Object> {
+ RecordedProgramAdapter() {
+ this(Integer.MAX_VALUE);
+ }
+
+ RecordedProgramAdapter(int maxItemCount) {
+ super(mPresenterSelector, RECORDED_PROGRAM_COMPARATOR, maxItemCount);
+ }
+
+ @Override
+ public long getId(Object item) {
+ if (item instanceof SeriesRecording) {
+ return ((SeriesRecording) item).getId();
+ } else if (item instanceof RecordedProgram) {
+ return ((RecordedProgram) item).getId();
+ } else {
+ return -1;
}
}
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
new file mode 100644
index 00000000..837d8ab2
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
@@ -0,0 +1,109 @@
+/*
+ * 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.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.DvrConflictFragment.DvrChannelRecordConflictFragment;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public class DvrChannelRecordDurationOptionFragment extends DvrGuidedStepFragment {
+ private final List<Long> mDurations = new ArrayList<>();
+ private Channel mChannel;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
+ mChannel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(channelId);
+ }
+ SoftPreconditions.checkArgument(mChannel != null);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_channel_record_duration_dialog_title);
+ Drawable icon = getResources().getDrawable(R.drawable.ic_dvr, null);
+ return new Guidance(title, null, null, icon);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ int actionId = -1;
+ mDurations.clear();
+ mDurations.add(TimeUnit.MINUTES.toMillis(10));
+ mDurations.add(TimeUnit.MINUTES.toMillis(30));
+ mDurations.add(TimeUnit.HOURS.toMillis(1));
+ mDurations.add(TimeUnit.HOURS.toMillis(3));
+
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(++actionId)
+ .title(R.string.recording_start_dialog_10_min_duration)
+ .build());
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(++actionId)
+ .title(R.string.recording_start_dialog_30_min_duration)
+ .build());
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(++actionId)
+ .title(R.string.recording_start_dialog_1_hour_duration)
+ .build());
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(++actionId)
+ .title(R.string.recording_start_dialog_3_hours_duration)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ long duration = mDurations.get((int) action.getId());
+ long startTimeMs = System.currentTimeMillis();
+ long endTimeMs = System.currentTimeMillis() + duration;
+ List<ScheduledRecording> conflicts = dvrManager.getConflictingSchedules(
+ mChannel.getId(), startTimeMs, endTimeMs);
+ dvrManager.addSchedule(mChannel, startTimeMs, endTimeMs);
+ if (conflicts.isEmpty()) {
+ dismissDialog();
+ } else {
+ GuidedStepFragment fragment = new DvrChannelRecordConflictFragment();
+ Bundle args = new Bundle();
+ args.putLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID, mChannel.getId());
+ args.putLong(DvrHalfSizedDialogFragment.KEY_START_TIME_MS, startTimeMs);
+ args.putLong(DvrHalfSizedDialogFragment.KEY_END_TIME_MS, endTimeMs);
+ fragment.setArguments(args);
+ GuidedStepFragment.add(getFragmentManager(), fragment,
+ R.id.halfsized_dialog_host);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrConflictFragment.java b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
new file mode 100644
index 00000000..e7be4d0a
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
@@ -0,0 +1,339 @@
+/*
+ * 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.graphics.drawable.Drawable;
+import android.media.tv.TvInputInfo;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.MainActivity;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Channel;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.ConflictChecker;
+import com.android.tv.dvr.ConflictChecker.OnUpcomingConflictChangeListener;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.util.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+
+public abstract class DvrConflictFragment extends DvrGuidedStepFragment {
+ private static final String TAG = "DvrConflictFragment";
+ private static final boolean DEBUG = false;
+
+ private static final int ACTION_DELETE_CONFLICT = 1;
+ private static final int ACTION_CANCEL = 2;
+ private static final int ACTION_VIEW_SCHEDULES = 3;
+
+ // The program count which will be listed in the description. This is the number of the
+ // program strings in R.plurals.dvr_program_conflict_dialog_description_many.
+ private static final int LISTED_PROGRAM_COUNT = 2;
+
+ protected List<ScheduledRecording> mConflicts;
+
+ void setConflicts(List<ScheduledRecording> conflicts) {
+ mConflicts = conflicts;
+ }
+
+ List<ScheduledRecording> getConflicts() {
+ return mConflicts;
+ }
+
+ @Override
+ public int onProvideTheme() {
+ return R.style.Theme_TV_Dvr_Conflict_GuidedStep;
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions,
+ Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getContext())
+ .clickAction(GuidedAction.ACTION_ID_OK)
+ .build());
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(ACTION_VIEW_SCHEDULES)
+ .title(R.string.dvr_action_view_schedules)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_VIEW_SCHEDULES) {
+ DvrUiHelper.startSchedulesActivityForOneTimeRecordingConflict(
+ getContext(), getConflicts());
+ }
+ dismissDialog();
+ }
+
+ String getConflictDescription() {
+ List<String> titles = new ArrayList<>();
+ HashSet<String> titleSet = new HashSet<>();
+ for (ScheduledRecording schedule : getConflicts()) {
+ String scheduleTitle = getScheduleTitle(schedule);
+ if (scheduleTitle != null && !titleSet.contains(scheduleTitle)) {
+ titles.add(scheduleTitle);
+ titleSet.add(scheduleTitle);
+ }
+ }
+ switch (titles.size()) {
+ case 0:
+ Log.i(TAG, "Conflict has been resolved by any reason. Maybe input might have"
+ + " been deleted.");
+ return null;
+ case 1:
+ return getResources().getString(
+ R.string.dvr_program_conflict_dialog_description_1, titles.get(0));
+ case 2:
+ return getResources().getString(
+ R.string.dvr_program_conflict_dialog_description_2, titles.get(0),
+ titles.get(1));
+ case 3:
+ return getResources().getString(
+ R.string.dvr_program_conflict_dialog_description_3, titles.get(0),
+ titles.get(1));
+ default:
+ return getResources().getQuantityString(
+ R.plurals.dvr_program_conflict_dialog_description_many,
+ titles.size() - LISTED_PROGRAM_COUNT, titles.get(0), titles.get(1),
+ titles.size() - LISTED_PROGRAM_COUNT);
+ }
+ }
+
+ @Nullable
+ private String getScheduleTitle(ScheduledRecording schedule) {
+ if (schedule.getType() == ScheduledRecording.TYPE_TIMED) {
+ Channel channel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(schedule.getChannelId());
+ if (channel != null) {
+ return channel.getDisplayName();
+ } else {
+ return null;
+ }
+ } else {
+ return schedule.getProgramTitle();
+ }
+ }
+
+ /**
+ * A fragment to show the program conflict.
+ */
+ public static class DvrProgramConflictFragment extends DvrConflictFragment {
+ private Program mProgram;
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mProgram = args.getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
+ }
+ SoftPreconditions.checkArgument(mProgram != null);
+ TvInputInfo input = Utils.getTvInputInfoForProgram(getContext(), mProgram);
+ SoftPreconditions.checkNotNull(input);
+ List<ScheduledRecording> conflicts = null;
+ if (input != null) {
+ conflicts = TvApplication.getSingletons(getContext()).getDvrManager()
+ .getConflictingSchedules(mProgram);
+ }
+ if (conflicts == null) {
+ conflicts = Collections.emptyList();
+ }
+ if (conflicts.isEmpty()) {
+ dismissDialog();
+ }
+ setConflicts(conflicts);
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_program_conflict_dialog_title);
+ String descriptionPrefix = getString(
+ R.string.dvr_program_conflict_dialog_description_prefix, mProgram.getTitle());
+ String description = getConflictDescription();
+ if (description == null) {
+ dismissDialog();
+ }
+ Drawable icon = getResources().getDrawable(R.drawable.ic_error_white_48dp, null);
+ return new Guidance(title, descriptionPrefix + " " + description, null, icon);
+ }
+ }
+
+ /**
+ * A fragment to show the channel recording conflict.
+ */
+ public static class DvrChannelRecordConflictFragment extends DvrConflictFragment {
+ private Channel mChannel;
+ private long mStartTimeMs;
+ private long mEndTimeMs;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
+ mChannel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(channelId);
+ SoftPreconditions.checkArgument(mChannel != null);
+ TvInputInfo input = Utils.getTvInputInfoForChannelId(getContext(), mChannel.getId());
+ SoftPreconditions.checkNotNull(input);
+ List<ScheduledRecording> conflicts = null;
+ if (input != null) {
+ mStartTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_START_TIME_MS);
+ mEndTimeMs = args.getLong(DvrHalfSizedDialogFragment.KEY_END_TIME_MS);
+ conflicts = TvApplication.getSingletons(getContext()).getDvrManager()
+ .getConflictingSchedules(mChannel.getId(), mStartTimeMs, mEndTimeMs);
+ }
+ if (conflicts == null) {
+ conflicts = Collections.emptyList();
+ }
+ if (conflicts.isEmpty()) {
+ dismissDialog();
+ }
+ setConflicts(conflicts);
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_channel_conflict_dialog_title);
+ String descriptionPrefix = getString(
+ R.string.dvr_channel_conflict_dialog_description_prefix,
+ mChannel.getDisplayName());
+ String description = getConflictDescription();
+ if (description == null) {
+ dismissDialog();
+ }
+ Drawable icon = getResources().getDrawable(R.drawable.ic_error_white_48dp, null);
+ return new Guidance(title, descriptionPrefix + " " + description, null, icon);
+ }
+ }
+
+ /**
+ * A fragment to show the channel watching conflict.
+ * <p>
+ * This fragment is automatically closed when there are no upcoming conflicts.
+ */
+ public static class DvrChannelWatchConflictFragment extends DvrConflictFragment
+ implements OnUpcomingConflictChangeListener {
+ private long mChannelId;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mChannelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
+ }
+ SoftPreconditions.checkArgument(mChannelId != Channel.INVALID_ID);
+ ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker();
+ List<ScheduledRecording> conflicts = null;
+ if (checker != null) {
+ checker.addOnUpcomingConflictChangeListener(this);
+ conflicts = checker.getUpcomingConflicts();
+ if (DEBUG) Log.d(TAG, "onCreateView: upcoming conflicts: " + conflicts);
+ if (conflicts.isEmpty()) {
+ dismissDialog();
+ }
+ }
+ if (conflicts == null) {
+ if (DEBUG) Log.d(TAG, "onCreateView: There's no conflict.");
+ conflicts = Collections.emptyList();
+ }
+ if (conflicts.isEmpty()) {
+ dismissDialog();
+ }
+ setConflicts(conflicts);
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(
+ R.string.dvr_epg_channel_watch_conflict_dialog_title);
+ String description = getResources().getString(
+ R.string.dvr_epg_channel_watch_conflict_dialog_description);
+ return new Guidance(title, description, null, null);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions,
+ Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(ACTION_DELETE_CONFLICT)
+ .title(R.string.dvr_action_delete_schedule)
+ .build());
+ actions.add(new GuidedAction.Builder(getContext())
+ .id(ACTION_CANCEL)
+ .title(R.string.dvr_action_record_program)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_CANCEL) {
+ ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker();
+ if (checker != null) {
+ checker.setCheckedConflictsForChannel(mChannelId, getConflicts());
+ }
+ } else if (action.getId() == ACTION_DELETE_CONFLICT) {
+ for (ScheduledRecording schedule : mConflicts) {
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ getDvrManager().stopRecording(schedule);
+ } else {
+ getDvrManager().removeScheduledRecording(schedule);
+ }
+ }
+ }
+ super.onGuidedActionClicked(action);
+ }
+
+ @Override
+ public void onDetach() {
+ ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker();
+ if (checker != null) {
+ checker.removeOnUpcomingConflictChangeListener(this);
+ }
+ super.onDetach();
+ }
+
+ @Override
+ public void onUpcomingConflictChange() {
+ ConflictChecker checker = ((MainActivity) getContext()).getDvrConflictChecker();
+ if (checker == null || checker.getUpcomingConflicts().isEmpty()) {
+ if (DEBUG) Log.d(TAG, "onUpcomingConflictChange: There's no conflict.");
+ dismissDialog();
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrDetailsActivity.java b/src/com/android/tv/dvr/ui/DvrDetailsActivity.java
new file mode 100644
index 00000000..806c775c
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrDetailsActivity.java
@@ -0,0 +1,98 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.app.DetailsFragment;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+
+/**
+ * Activity to show details view in DVR.
+ */
+public class DvrDetailsActivity extends Activity {
+ /**
+ * Name of record id added to the Intent.
+ */
+ public static final String RECORDING_ID = "record_id";
+
+ /**
+ * Name of flag added to the Intent to determine if details view should hide "View schedule"
+ * button.
+ */
+ public static final String HIDE_VIEW_SCHEDULE = "hide_view_schedule";
+
+ /**
+ * Name of details view's type added to the intent.
+ */
+ public static final String DETAILS_VIEW_TYPE = "details_view_type";
+
+ /**
+ * Name of shared element between activities.
+ */
+ public static final String SHARED_ELEMENT_NAME = "shared_element";
+
+ /**
+ * CURRENT_RECORDING_VIEW refers to Current Recordings in DVR.
+ */
+ public static final int CURRENT_RECORDING_VIEW = 1;
+
+ /**
+ * SCHEDULED_RECORDING_VIEW refers to Scheduled Recordings in DVR.
+ */
+ public static final int SCHEDULED_RECORDING_VIEW = 2;
+
+ /**
+ * RECORDED_PROGRAM_VIEW refers to Recorded programs in DVR.
+ */
+ public static final int RECORDED_PROGRAM_VIEW = 3;
+
+ /**
+ * SERIES_RECORDING_VIEW refers to series recording in DVR.
+ */
+ public static final int SERIES_RECORDING_VIEW = 4;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, true);
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dvr_details);
+ long recordId = getIntent().getLongExtra(RECORDING_ID, -1);
+ int detailsViewType = getIntent().getIntExtra(DETAILS_VIEW_TYPE, -1);
+ boolean hideViewSchedule = getIntent().getBooleanExtra(HIDE_VIEW_SCHEDULE, false);
+ if (recordId != -1 && detailsViewType != -1 && savedInstanceState == null) {
+ Bundle args = new Bundle();
+ args.putLong(RECORDING_ID, recordId);
+ DetailsFragment detailsFragment = null;
+ if (detailsViewType == CURRENT_RECORDING_VIEW) {
+ detailsFragment = new CurrentRecordingDetailsFragment();
+ } else if (detailsViewType == SCHEDULED_RECORDING_VIEW) {
+ args.putBoolean(HIDE_VIEW_SCHEDULE, hideViewSchedule);
+ detailsFragment = new ScheduledRecordingDetailsFragment();
+ } else if (detailsViewType == RECORDED_PROGRAM_VIEW) {
+ detailsFragment = new RecordedProgramDetailsFragment();
+ } else if (detailsViewType == SERIES_RECORDING_VIEW) {
+ detailsFragment = new SeriesRecordingDetailsFragment();
+ }
+ detailsFragment.setArguments(args);
+ getFragmentManager().beginTransaction()
+ .replace(R.id.dvr_details_view_frame, detailsFragment).commit();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/DvrDetailsFragment.java
new file mode 100644
index 00000000..21f9c4b4
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrDetailsFragment.java
@@ -0,0 +1,344 @@
+/*
+ * 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.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvContentRating;
+import android.media.tv.TvInputManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.DetailsOverviewRow;
+import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.support.v17.leanback.widget.VerticalGridView;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.BaseProgram;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dialog.PinDialogFragment;
+import com.android.tv.dvr.DvrPlaybackActivity;
+import com.android.tv.dvr.RecordedProgram;
+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 {
+ private static final int LOAD_LOGO_IMAGE = 1;
+ private static final int LOAD_BACKGROUND_IMAGE = 2;
+
+ protected DetailsViewBackgroundHelper mBackgroundHelper;
+ private ArrayObjectAdapter mRowsAdapter;
+ private DetailsOverviewRow mDetailsOverview;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (!onLoadRecordingDetails(getArguments())) {
+ getActivity().finish();
+ return;
+ }
+ mBackgroundHelper = new DetailsViewBackgroundHelper(getActivity());
+ setupAdapter();
+ onCreateInternal();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ // TODO: remove the workaround of b/30401180.
+ VerticalGridView container = (VerticalGridView) getActivity()
+ .findViewById(R.id.container_list);
+ // Need to manually modify offset. Please refer DetailsFragment.setVerticalGridViewLayout.
+ container.setItemAlignmentOffset(0);
+ container.setWindowAlignmentOffset(
+ getResources().getDimensionPixelSize(R.dimen.lb_details_rows_align_top));
+ }
+
+ private void setupAdapter() {
+ DetailsOverviewRowPresenter rowPresenter = new DetailsOverviewRowPresenter(
+ new DetailsContentPresenter(getActivity()));
+ rowPresenter.setBackgroundColor(getResources().getColor(R.color.common_tv_background,
+ null));
+ rowPresenter.setSharedElementEnterTransition(getActivity(),
+ DvrDetailsActivity.SHARED_ELEMENT_NAME);
+ rowPresenter.setOnActionClickedListener(onCreateOnActionClickedListener());
+ mRowsAdapter = new ArrayObjectAdapter(onCreatePresenterSelector(rowPresenter));
+ setAdapter(mRowsAdapter);
+ }
+
+ /**
+ * Returns details views' rows adapter.
+ */
+ protected ArrayObjectAdapter getRowsAdapter() {
+ return mRowsAdapter;
+ }
+
+ /**
+ * Sets details overview.
+ */
+ protected void setDetailsOverviewRow(DetailsContent detailsContent) {
+ mDetailsOverview = new DetailsOverviewRow(detailsContent);
+ mDetailsOverview.setActionsAdapter(onCreateActionsAdapter());
+ mRowsAdapter.add(mDetailsOverview);
+ onLoadLogoAndBackgroundImages(detailsContent);
+ }
+
+ /**
+ * Creates and returns presenter selector will be used by rows adaptor.
+ */
+ protected PresenterSelector onCreatePresenterSelector(
+ DetailsOverviewRowPresenter rowPresenter) {
+ ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
+ presenterSelector.addClassPresenter(DetailsOverviewRow.class, rowPresenter);
+ return presenterSelector;
+ }
+
+ /**
+ * Does customized initialization of subclasses. Since {@link #onCreate(Bundle)} might finish
+ * activity early when it cannot fetch valid recordings, subclasses' onCreate method should not
+ * do anything after calling {@link #onCreate(Bundle)}. If there's something subclasses have to
+ * do after the super class did onCreate, it should override this method and put the codes here.
+ */
+ protected void onCreateInternal() { }
+
+ /**
+ * Updates actions of details overview.
+ */
+ protected void updateActions() {
+ mDetailsOverview.setActionsAdapter(onCreateActionsAdapter());
+ }
+
+ /**
+ * Loads recording details according to the arguments the fragment got.
+ *
+ * @return false if cannot find valid recordings, else return true. If the return value
+ * is false, the detail activity and fragment will be ended.
+ */
+ abstract boolean onLoadRecordingDetails(Bundle args);
+
+ /**
+ * Creates actions users can interact with and their adaptor for this fragment.
+ */
+ abstract SparseArrayObjectAdapter onCreateActionsAdapter();
+
+ /**
+ * Creates actions listeners to implement the behavior of the fragment after users click some
+ * action buttons.
+ */
+ abstract OnActionClickedListener onCreateOnActionClickedListener();
+
+ /**
+ * Returns program title with episode number. If the program is null, returns channel name.
+ */
+ protected CharSequence getTitleFromProgram(BaseProgram program, Channel channel) {
+ String titleWithEpisodeNumber = program.getTitleWithEpisodeNumber(getContext());
+ SpannableString title = titleWithEpisodeNumber == null ? null
+ : new SpannableString(titleWithEpisodeNumber);
+ if (TextUtils.isEmpty(title)) {
+ title = new SpannableString(channel != null ? channel.getDisplayName()
+ : getContext().getResources().getString(
+ R.string.no_program_information));
+ } else {
+ String programTitle = program.getTitle();
+ title.setSpan(new TextAppearanceSpan(getContext(),
+ R.style.text_appearance_card_view_episode_number), programTitle == null ? 0
+ : programTitle.length(), title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ return title;
+ }
+
+ /**
+ * Loads logo and background images for detail fragments.
+ */
+ protected void onLoadLogoAndBackgroundImages(DetailsContent detailsContent) {
+ Drawable logoDrawable = null;
+ Drawable backgroundDrawable = null;
+ if (TextUtils.isEmpty(detailsContent.getLogoImageUri())) {
+ logoDrawable = getContext().getResources()
+ .getDrawable(R.drawable.dvr_default_poster, null);
+ mDetailsOverview.setImageDrawable(logoDrawable);
+ }
+ if (TextUtils.isEmpty(detailsContent.getBackgroundImageUri())) {
+ backgroundDrawable = getContext().getResources()
+ .getDrawable(R.drawable.dvr_default_poster, null);
+ mBackgroundHelper.setBackground(backgroundDrawable);
+ }
+ if (logoDrawable != null && backgroundDrawable != null) {
+ return;
+ }
+ if (logoDrawable == null && backgroundDrawable == null
+ && detailsContent.getLogoImageUri().equals(
+ detailsContent.getBackgroundImageUri())) {
+ ImageLoader.loadBitmap(getContext(), detailsContent.getLogoImageUri(),
+ new MyImageLoaderCallback(this, LOAD_LOGO_IMAGE | LOAD_BACKGROUND_IMAGE,
+ getContext()));
+ return;
+ }
+ if (logoDrawable == null) {
+ int imageWidth = getResources().getDimensionPixelSize(R.dimen.dvr_details_poster_width);
+ int imageHeight = getResources()
+ .getDimensionPixelSize(R.dimen.dvr_details_poster_height);
+ ImageLoader.loadBitmap(getContext(), detailsContent.getLogoImageUri(),
+ imageWidth, imageHeight,
+ new MyImageLoaderCallback(this, LOAD_LOGO_IMAGE, getContext()));
+ }
+ if (backgroundDrawable == null) {
+ ImageLoader.loadBitmap(getContext(), detailsContent.getBackgroundImageUri(),
+ new MyImageLoaderCallback(this, LOAD_BACKGROUND_IMAGE, getContext()));
+ }
+ }
+
+ protected void startPlayback(RecordedProgram recordedProgram, long seekTimeMs) {
+ if (Utils.isInBundledPackageSet(recordedProgram.getPackageName()) &&
+ !isDataUriAccessible(recordedProgram.getDataUri())) {
+ // Since cleaning RecordedProgram from forgotten storage will take some time,
+ // ignore playback until cleaning is finished.
+ ToastUtils.show(getContext(),
+ getContext().getResources().getString(R.string.dvr_toast_recording_deleted),
+ Toast.LENGTH_SHORT);
+ return;
+ }
+ ParentalControlSettings parental = TvApplication.getSingletons(getActivity())
+ .getTvInputManagerHelper().getParentalControlSettings();
+ if (!parental.isParentalControlsEnabled()) {
+ launchPlaybackActivity(recordedProgram, seekTimeMs, false);
+ return;
+ }
+ ChannelDataManager channelDataManager =
+ TvApplication.getSingletons(getActivity()).getChannelDataManager();
+ Channel channel = channelDataManager.getChannel(recordedProgram.getChannelId());
+ if (channel != null && channel.isLocked()) {
+ checkPinToPlay(recordedProgram, seekTimeMs);
+ return;
+ }
+ String ratingString = recordedProgram.getContentRating();
+ if (TextUtils.isEmpty(ratingString)) {
+ launchPlaybackActivity(recordedProgram, seekTimeMs, false);
+ return;
+ }
+ String[] ratingList = ratingString.split(",");
+ TvContentRating[] programRatings = new TvContentRating[ratingList.length];
+ for (int i = 0; i < ratingList.length; i++) {
+ programRatings[i] = TvContentRating.unflattenFromString(ratingList[i]);
+ }
+ TvContentRating blockRatings = parental.getBlockedRating(programRatings);
+ if (blockRatings != null) {
+ checkPinToPlay(recordedProgram, seekTimeMs);
+ } else {
+ launchPlaybackActivity(recordedProgram, seekTimeMs, false);
+ }
+ }
+
+ private boolean isDataUriAccessible(Uri dataUri) {
+ if (dataUri == null || dataUri.getPath() == null) {
+ return false;
+ }
+ try {
+ File recordedProgramPath = new File(dataUri.getPath());
+ if (recordedProgramPath.exists()) {
+ return true;
+ }
+ } catch (SecurityException e) {
+ }
+ return false;
+ }
+
+ private void checkPinToPlay(RecordedProgram recordedProgram, long seekTimeMs) {
+ new PinDialogFragment(PinDialogFragment.PIN_DIALOG_TYPE_UNLOCK_PROGRAM,
+ new PinDialogFragment.ResultListener() {
+ @Override
+ public void done(boolean success) {
+ if (success) {
+ launchPlaybackActivity(recordedProgram, seekTimeMs, true);
+ }
+ }
+ }).show(getActivity().getFragmentManager(), PinDialogFragment.DIALOG_TAG);
+ }
+
+ private void launchPlaybackActivity(RecordedProgram mRecordedProgram, long seekTimeMs,
+ boolean pinChecked) {
+ Intent intent = new Intent(getActivity(), DvrPlaybackActivity.class);
+ intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, mRecordedProgram.getId());
+ if (seekTimeMs != TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME, seekTimeMs);
+ }
+ intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED, pinChecked);
+ getActivity().startActivity(intent);
+ }
+
+ private static class MyImageLoaderCallback extends
+ ImageLoader.ImageLoaderCallback<DvrDetailsFragment> {
+ private final Context mContext;
+ private final int mLoadType;
+
+ public MyImageLoaderCallback(DvrDetailsFragment fragment,
+ int loadType, Context context) {
+ super(fragment);
+ mLoadType = loadType;
+ mContext = context;
+ }
+
+ @Override
+ public void onBitmapLoaded(DvrDetailsFragment fragment,
+ @Nullable Bitmap bitmap) {
+ Drawable drawable;
+ int loadType = mLoadType;
+ if (bitmap == null) {
+ Resources res = mContext.getResources();
+ drawable = res.getDrawable(R.drawable.dvr_default_poster, null);
+ if ((loadType & LOAD_BACKGROUND_IMAGE) != 0 && !fragment.isDetached()) {
+ loadType &= ~LOAD_BACKGROUND_IMAGE;
+ fragment.mBackgroundHelper.setBackgroundColor(
+ res.getColor(R.color.dvr_detail_default_background));
+ fragment.mBackgroundHelper.setScrim(
+ res.getColor(R.color.dvr_detail_default_background_scrim));
+ }
+ } else {
+ drawable = new BitmapDrawable(mContext.getResources(), bitmap);
+ }
+ if (!fragment.isDetached()) {
+ if ((loadType & LOAD_LOGO_IMAGE) != 0) {
+ fragment.mDetailsOverview.setImageDrawable(drawable);
+ }
+ if ((loadType & LOAD_BACKGROUND_IMAGE) != 0) {
+ fragment.mBackgroundHelper.setBackground(drawable);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrDialogFragment.java b/src/com/android/tv/dvr/ui/DvrDialogFragment.java
deleted file mode 100644
index 38de9d8d..00000000
--- a/src/com/android/tv/dvr/ui/DvrDialogFragment.java
+++ /dev/null
@@ -1,50 +0,0 @@
-package com.android.tv.dvr.ui;
-
-import android.app.FragmentManager;
-import android.content.Context;
-import android.os.Bundle;
-import android.support.v17.leanback.app.GuidedStepFragment;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-
-import com.android.tv.MainActivity;
-import com.android.tv.R;
-import com.android.tv.guide.ProgramGuide;
-
-public class DvrDialogFragment extends HalfSizedDialogFragment {
- private final DvrGuidedStepFragment mDvrGuidedStepFragment;
-
- public DvrDialogFragment(DvrGuidedStepFragment dvrGuidedStepFragment) {
- mDvrGuidedStepFragment = dvrGuidedStepFragment;
- }
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- ProgramGuide programGuide =
- ((MainActivity) getActivity()).getOverlayManager().getProgramGuide();
- if (programGuide != null && programGuide.isActive()) {
- programGuide.cancelHide();
- }
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- View view = super.onCreateView(inflater, container, savedInstanceState);
- FragmentManager fm = getChildFragmentManager();
- GuidedStepFragment.add(fm, mDvrGuidedStepFragment, R.id.halfsized_dialog_host);
- return view;
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- ProgramGuide programGuide =
- ((MainActivity) getActivity()).getOverlayManager().getProgramGuide();
- if (programGuide != null && programGuide.isActive()) {
- programGuide.scheduleHide();
- }
- }
-}
diff --git a/src/com/android/tv/dvr/ui/DvrForgetStorageErrorFragment.java b/src/com/android/tv/dvr/ui/DvrForgetStorageErrorFragment.java
new file mode 100644
index 00000000..73ddcdd0
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrForgetStorageErrorFragment.java
@@ -0,0 +1,87 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+
+import java.util.List;
+
+public class DvrForgetStorageErrorFragment extends DvrGuidedStepFragment {
+ private static final int ACTION_CANCEL = 1;
+ private static final int ACTION_FORGET_STORAGE = 2;
+ private String mInputId;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mInputId = args.getString(DvrHalfSizedDialogFragment.KEY_INPUT_ID);
+ }
+ SoftPreconditions.checkArgument(!TextUtils.isEmpty(mInputId));
+ super.onCreate(savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_error_forget_storage_title);
+ String description = getResources().getString(
+ R.string.dvr_error_forget_storage_description);
+ return new Guidance(title, description, null, null);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Activity activity = getActivity();
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_CANCEL)
+ .title(getResources().getString(R.string.dvr_action_error_cancel))
+ .build());
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_FORGET_STORAGE)
+ .title(getResources().getString(R.string.dvr_action_error_forget_storage))
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() != ACTION_FORGET_STORAGE) {
+ dismissDialog();
+ return;
+ }
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ dvrManager.forgetStorage(mInputId);
+ Activity activity = getActivity();
+ if (activity instanceof DvrDetailsActivity) {
+ // Since we removed everything, just finish the activity.
+ activity.finish();
+ } else {
+ dismissDialog();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java
new file mode 100644
index 00000000..6b0c22ff
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrGuidedActionsStylist.java
@@ -0,0 +1,78 @@
+/*
+ * 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.content.Context;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+
+import com.android.tv.R;
+
+/**
+ * Stylist class used for DVR settings {@link GuidedStepFragment}.
+ */
+public class DvrGuidedActionsStylist extends GuidedActionsStylist {
+ private static boolean sInitialized;
+ private static float sWidthWeight;
+ private static int sItemHeight;
+
+ private final boolean mIsButtonActions;
+
+ public DvrGuidedActionsStylist(boolean isButtonActions) {
+ super();
+ mIsButtonActions = isButtonActions;
+ if (mIsButtonActions) {
+ setAsButtonActions();
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container) {
+ initializeIfNeeded(container.getContext());
+ View v = super.onCreateView(inflater, container);
+ if (mIsButtonActions) {
+ ((LinearLayout.LayoutParams) v.getLayoutParams()).weight = sWidthWeight;
+ }
+ return v;
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ initializeIfNeeded(parent.getContext());
+ ViewHolder viewHolder = super.onCreateViewHolder(parent);
+ viewHolder.itemView.getLayoutParams().height = sItemHeight;
+ return viewHolder;
+ }
+
+ private void initializeIfNeeded(Context context) {
+ if (sInitialized) {
+ return;
+ }
+ sInitialized = true;
+ sItemHeight = context.getResources().getDimensionPixelSize(
+ R.dimen.dvr_settings_one_line_action_container_height);
+ TypedValue outValue = new TypedValue();
+ context.getResources().getValue(R.dimen.dvr_settings_button_actions_list_width_weight,
+ outValue, true);
+ sWidthWeight = outValue.getFloat();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
index 0854b91a..d26e6836 100644
--- a/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrGuidedStepFragment.java
@@ -1,32 +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.dvr.ui;
+import android.app.DialogFragment;
import android.content.Context;
import android.os.Bundle;
import android.support.v17.leanback.app.GuidedStepFragment;
-import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
import android.support.v17.leanback.widget.VerticalGridView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.tv.MainActivity;
+import com.android.tv.R;
import com.android.tv.TvApplication;
import com.android.tv.dialog.SafeDismissDialogFragment;
import com.android.tv.dvr.DvrManager;
-import com.android.tv.guide.ProgramManager.TableEntry;
-import com.android.tv.R;
+import com.android.tv.dvr.ui.HalfSizedDialogFragment.OnActionClickListener;
public class DvrGuidedStepFragment extends GuidedStepFragment {
- private final TableEntry mEntry;
private DvrManager mDvrManager;
-
- public DvrGuidedStepFragment(TableEntry entry) {
- mEntry = entry;
- }
-
- protected TableEntry getEntry() {
- return mEntry;
- }
+ private OnActionClickListener mOnActionClickListener;
protected DvrManager getDvrManager() {
return mDvrManager;
@@ -42,32 +51,39 @@ public class DvrGuidedStepFragment extends GuidedStepFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
- VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView();
- gridView.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+ VerticalGridView actionsList = getGuidedActionsStylist().getActionsGridView();
+ actionsList.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
+ VerticalGridView buttonActionsList = getGuidedButtonActionsStylist().getActionsGridView();
+ buttonActionsList.setWindowAlignment(VerticalGridView.WINDOW_ALIGN_BOTH_EDGE);
return view;
}
@Override
- public GuidanceStylist onCreateGuidanceStylist() {
- // Workaround: b/28448653
- return new GuidanceStylist() {
- @Override
- public int onProvideLayoutId() {
- return R.layout.halfsized_guidance;
- }
- };
+ public int onProvideTheme() {
+ return R.style.Theme_TV_Dvr_GuidedStep;
}
@Override
- public int onProvideTheme() {
- return R.style.Theme_TV_Dvr_GuidedStep;
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (mOnActionClickListener != null) {
+ mOnActionClickListener.onActionClick(action.getId());
+ }
+ dismissDialog();
}
protected void dismissDialog() {
- SafeDismissDialogFragment currentDialog =
- ((MainActivity) getActivity()).getOverlayManager().getCurrentDialog();
- if (currentDialog instanceof DvrDialogFragment) {
- currentDialog.dismiss();
+ if (getActivity() instanceof MainActivity) {
+ SafeDismissDialogFragment currentDialog =
+ ((MainActivity) getActivity()).getOverlayManager().getCurrentDialog();
+ if (currentDialog instanceof DvrHalfSizedDialogFragment) {
+ currentDialog.dismiss();
+ }
+ } else if (getParentFragment() instanceof DialogFragment) {
+ ((DialogFragment) getParentFragment()).dismiss();
}
}
-}
+
+ protected void setOnActionClickListener(OnActionClickListener listener) {
+ mOnActionClickListener = listener;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java
new file mode 100644
index 00000000..2b132db8
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrHalfSizedDialogFragment.java
@@ -0,0 +1,228 @@
+/*
+ * 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.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.MainActivity;
+import com.android.tv.R;
+import com.android.tv.dvr.DvrStorageStatusManager;
+import com.android.tv.dvr.ui.DvrConflictFragment.DvrChannelWatchConflictFragment;
+import com.android.tv.dvr.ui.DvrConflictFragment.DvrProgramConflictFragment;
+import com.android.tv.guide.ProgramGuide;
+
+import java.util.List;
+
+public class DvrHalfSizedDialogFragment extends HalfSizedDialogFragment {
+ /**
+ * Key for input ID.
+ * Type: String.
+ */
+ public static final String KEY_INPUT_ID = "DvrHalfSizedDialogFragment.input_id";
+ /**
+ * Key for the program.
+ * Type: {@link com.android.tv.data.Program}.
+ */
+ public static final String KEY_PROGRAM = "DvrHalfSizedDialogFragment.program";
+ /**
+ * Key for the channel ID.
+ * Type: long.
+ */
+ public static final String KEY_CHANNEL_ID = "DvrHalfSizedDialogFragment.channel_id";
+ /**
+ * Key for the recording start time in millisecond.
+ * Type: long.
+ */
+ public static final String KEY_START_TIME_MS = "DvrHalfSizedDialogFragment.start_time_ms";
+ /**
+ * Key for the recording end time in millisecond.
+ * Type: long.
+ */
+ public static final String KEY_END_TIME_MS = "DvrHalfSizedDialogFragment.end_time_ms";
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ Activity activity = getActivity();
+ if (activity instanceof MainActivity) {
+ ProgramGuide programGuide =
+ ((MainActivity) activity).getOverlayManager().getProgramGuide();
+ if (programGuide != null && programGuide.isActive()) {
+ programGuide.cancelHide();
+ }
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ Activity activity = getActivity();
+ if (activity instanceof MainActivity) {
+ ProgramGuide programGuide =
+ ((MainActivity) activity).getOverlayManager().getProgramGuide();
+ if (programGuide != null && programGuide.isActive()) {
+ programGuide.scheduleHide();
+ }
+ }
+ }
+
+ public abstract static class DvrGuidedStepDialogFragment extends DvrHalfSizedDialogFragment {
+ private DvrGuidedStepFragment mFragment;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ mFragment = onCreateGuidedStepFragment();
+ mFragment.setArguments(getArguments());
+ mFragment.setOnActionClickListener(getOnActionClickListener());
+ GuidedStepFragment.add(getChildFragmentManager(),
+ mFragment, R.id.halfsized_dialog_host);
+ return view;
+ }
+
+ @Override
+ public void setOnActionClickListener(OnActionClickListener listener) {
+ super.setOnActionClickListener(listener);
+ if (mFragment != null) {
+ mFragment.setOnActionClickListener(listener);
+ }
+ }
+
+ protected abstract DvrGuidedStepFragment onCreateGuidedStepFragment();
+ }
+
+ /** A dialog fragment for {@link DvrScheduleFragment}. */
+ public static class DvrScheduleDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrScheduleFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrProgramConflictFragment}. */
+ public static class DvrProgramConflictDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrProgramConflictFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrChannelWatchConflictFragment}. */
+ public static class DvrChannelWatchConflictDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrChannelWatchConflictFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrChannelRecordDurationOptionFragment}. */
+ public static class DvrChannelRecordDurationOptionDialogFragment
+ extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrChannelRecordDurationOptionFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrInsufficientSpaceErrorFragment}. */
+ public static class DvrInsufficientSpaceErrorDialogFragment
+ extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrInsufficientSpaceErrorFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrMissingStorageErrorFragment}. */
+ public static class DvrMissingStorageErrorDialogFragment
+ extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrMissingStorageErrorFragment();
+ }
+ }
+
+ /**
+ * A dialog fragment to show error message when the current storage is too small to
+ * support DVR
+ */
+ public static class DvrSmallSizedStorageErrorDialogFragment
+ extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrGuidedStepFragment() {
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(
+ R.string.dvr_error_small_sized_storage_title);
+ String description = getResources().getString(
+ R.string.dvr_error_small_sized_storage_description,
+ DvrStorageStatusManager.MIN_STORAGE_SIZE_FOR_DVR_IN_BYTES / 1024
+ / 1024 / 1024);
+ return new Guidance(title, description, null, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ Activity activity = getActivity();
+ actions.add(new GuidedAction.Builder(activity)
+ .id(GuidedAction.ACTION_ID_OK)
+ .title(android.R.string.ok)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ dismissDialog();
+ }
+ };
+ }
+ }
+
+ /** A dialog fragment for {@link DvrStopRecordingFragment}. */
+ public static class DvrStopRecordingDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrStopRecordingFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrAlreadyScheduledFragment}. */
+ public static class DvrAlreadyScheduledDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrAlreadyScheduledFragment();
+ }
+ }
+
+ /** A dialog fragment for {@link DvrAlreadyRecordedFragment}. */
+ public static class DvrAlreadyRecordedDialogFragment extends DvrGuidedStepDialogFragment {
+ @Override
+ protected DvrGuidedStepFragment onCreateGuidedStepFragment() {
+ return new DvrAlreadyRecordedFragment();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java
new file mode 100644
index 00000000..3b1dbfa0
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrInsufficientSpaceErrorFragment.java
@@ -0,0 +1,71 @@
+/*
+ * 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.app.Activity;
+import android.content.Intent;
+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.TvApplication;
+import com.android.tv.dvr.DvrDataManager;
+
+import java.util.List;
+
+public class DvrInsufficientSpaceErrorFragment extends DvrGuidedStepFragment {
+ private static final int ACTION_DONE = 1;
+ private static final int ACTION_OPEN_DVR = 2;
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_error_insufficient_space_title);
+ String description = getResources()
+ .getString(R.string.dvr_error_insufficient_space_description);
+ return new Guidance(title, description, null, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ Activity activity = getActivity();
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_DONE)
+ .title(getResources().getString(R.string.dvr_action_error_done))
+ .build());
+ DvrDataManager dvrDataManager = TvApplication.getSingletons(getContext())
+ .getDvrDataManager();
+ if (!(dvrDataManager.getRecordedPrograms().isEmpty()
+ && dvrDataManager.getStartedRecordings().isEmpty()
+ && dvrDataManager.getNonStartedScheduledRecordings().isEmpty()
+ && dvrDataManager.getSeriesRecordings().isEmpty())) {
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_OPEN_DVR)
+ .title(getResources().getString(R.string.dvr_action_error_open_dvr))
+ .build());
+ }
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_OPEN_DVR) {
+ Intent intent = new Intent(getActivity(), DvrActivity.class);
+ getActivity().startActivity(intent);
+ }
+ dismissDialog();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrItemPresenter.java b/src/com/android/tv/dvr/ui/DvrItemPresenter.java
new file mode 100644
index 00000000..339e5d2f
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrItemPresenter.java
@@ -0,0 +1,80 @@
+/*
+ * 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.app.Activity;
+import android.support.annotation.CallSuper;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.View;
+import android.view.View.OnClickListener;
+
+import com.android.tv.dvr.DvrUiHelper;
+
+import java.util.HashSet;
+import java.util.Iterator;
+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 ScheduledRecording},
+ * {@link RecordedProgram}, and {@link SeriesRecording}.
+ */
+public abstract class DvrItemPresenter extends Presenter {
+ private final Set<ViewHolder> mBoundViewHolders = new HashSet<>();
+ private final OnClickListener mOnClickListener = onCreateOnClickListener();
+
+ @Override
+ @CallSuper
+ public void onBindViewHolder(ViewHolder viewHolder, Object o) {
+ viewHolder.view.setTag(o);
+ viewHolder.view.setOnClickListener(mOnClickListener);
+ mBoundViewHolders.add(viewHolder);
+ }
+
+ @Override
+ @CallSuper
+ public void onUnbindViewHolder(ViewHolder viewHolder) {
+ mBoundViewHolders.remove(viewHolder);
+ }
+
+ /**
+ * Unbinds all bound view holders.
+ */
+ public void unbindAllViewHolders() {
+ // When browse fragments are destroyed, RecyclerView would not call presenters'
+ // onUnbindViewHolder(). We should handle it by ourselves to prevent resources leaks.
+ for (ViewHolder viewHolder : new HashSet<>(mBoundViewHolders)) {
+ onUnbindViewHolder(viewHolder);
+ }
+ }
+
+ /**
+ * Creates {@link OnClickListener} for DVR library's card views.
+ */
+ protected OnClickListener onCreateOnClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (view instanceof RecordingCardView) {
+ RecordingCardView v = (RecordingCardView) view;
+ DvrUiHelper.startDetailsActivity((Activity) v.getContext(),
+ v.getTag(), v.getImageView(), false);
+ }
+ }
+ };
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java
new file mode 100644
index 00000000..2e2c2849
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrMissingStorageErrorFragment.java
@@ -0,0 +1,79 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.common.SoftPreconditions;
+
+import java.util.List;
+
+public class DvrMissingStorageErrorFragment extends DvrGuidedStepFragment {
+ private static final int ACTION_CANCEL = 1;
+ private static final int ACTION_FORGET_STORAGE = 2;
+ private String mInputId;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mInputId = args.getString(DvrHalfSizedDialogFragment.KEY_INPUT_ID);
+ }
+ SoftPreconditions.checkArgument(!TextUtils.isEmpty(mInputId));
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getResources().getString(R.string.dvr_error_missing_storage_title);
+ String description = getResources().getString(
+ R.string.dvr_error_missing_storage_description);
+ return new Guidance(title, description, null, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ Activity activity = getActivity();
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_CANCEL)
+ .title(getResources().getString(R.string.dvr_action_error_cancel))
+ .build());
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_FORGET_STORAGE)
+ .title(getResources().getString(R.string.dvr_action_error_forget_storage))
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_FORGET_STORAGE) {
+ DvrForgetStorageErrorFragment fragment = new DvrForgetStorageErrorFragment();
+ Bundle args = new Bundle();
+ args.putString(DvrHalfSizedDialogFragment.KEY_INPUT_ID, mInputId);
+ fragment.setArguments(args);
+ GuidedStepFragment.add(getFragmentManager(), fragment, R.id.halfsized_dialog_host);
+ return;
+ }
+ dismissDialog();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrPlaybackCardPresenter.java b/src/com/android/tv/dvr/ui/DvrPlaybackCardPresenter.java
new file mode 100644
index 00000000..8c4c856c
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrPlaybackCardPresenter.java
@@ -0,0 +1,82 @@
+/*
+ * 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.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+
+import com.android.tv.R;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.dvr.DvrPlaybackActivity;
+import com.android.tv.util.Utils;
+
+/**
+ * This class is used to generate Views and bind Objects for related recordings in DVR playback.
+ */
+public class DvrPlaybackCardPresenter extends RecordedProgramPresenter {
+ private static final String TAG = "DvrPlaybackCardPresenter";
+ private static final boolean DEBUG = false;
+
+ private final int mRelatedRecordingCardWidth;
+ private final int mRelatedRecordingCardHeight;
+
+ DvrPlaybackCardPresenter(Context context) {
+ super(context);
+ mRelatedRecordingCardWidth =
+ context.getResources().getDimensionPixelSize(R.dimen.dvr_related_recordings_width);
+ mRelatedRecordingCardHeight =
+ context.getResources().getDimensionPixelSize(R.dimen.dvr_related_recordings_height);
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ Resources res = parent.getResources();
+ RecordingCardView view = new RecordingCardView(
+ getContext(), mRelatedRecordingCardWidth, mRelatedRecordingCardHeight);
+ return new ViewHolder(view);
+ }
+
+ @Override
+ protected OnClickListener onCreateOnClickListener() {
+ return new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ long programId = ((RecordedProgram) v.getTag()).getId();
+ if (DEBUG) Log.d(TAG, "Play Related Recording:" + programId);
+ Intent intent = new Intent(getContext(), DvrPlaybackActivity.class);
+ intent.putExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, programId);
+ getContext().startActivity(intent);
+ }
+ };
+ }
+
+ @Override
+ protected String getDescription(RecordedProgram program) {
+ String description = program.getDescription();
+ if (TextUtils.isEmpty(description)) {
+ description =
+ getContext().getResources().getString(R.string.dvr_msg_no_program_description);
+ }
+ return description;
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrPlaybackControlHelper.java b/src/com/android/tv/dvr/ui/DvrPlaybackControlHelper.java
new file mode 100644
index 00000000..0bc4ecb1
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrPlaybackControlHelper.java
@@ -0,0 +1,313 @@
+/*
+ * 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.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.MediaController.TransportControls;
+import android.media.session.PlaybackState;
+import android.support.v17.leanback.app.PlaybackControlGlue;
+import android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.tv.R;
+import com.android.tv.util.TimeShiftUtils;
+
+/**
+ * A helper class to assist {@link DvrPlaybackOverlayFragment} to manage its controls row and
+ * send command to the media controller. It also helps to update playback states displayed in the
+ * fragment according to information the media session provides.
+ */
+public class DvrPlaybackControlHelper extends PlaybackControlGlue {
+ private static final String TAG = "DvrPlaybackControlHelper";
+ private static final boolean DEBUG = false;
+
+ /**
+ * Indicates the ID of the media under playback is unknown.
+ */
+ public static int UNKNOWN_MEDIA_ID = -1;
+
+ private int mPlaybackState = PlaybackState.STATE_NONE;
+ private int mPlaybackSpeedLevel;
+ private int mPlaybackSpeedId;
+ private boolean mReadyToControl;
+
+ private final MediaController mMediaController;
+ private final MediaController.Callback mMediaControllerCallback = new MediaControllerCallback();
+ private final TransportControls mTransportControls;
+ private final int mExtraPaddingTopForNoDescription;
+
+ public DvrPlaybackControlHelper(Activity activity, DvrPlaybackOverlayFragment overlayFragment) {
+ super(activity, overlayFragment, new int[TimeShiftUtils.MAX_SPEED_LEVEL + 1]);
+ mMediaController = activity.getMediaController();
+ mMediaController.registerCallback(mMediaControllerCallback);
+ mTransportControls = mMediaController.getTransportControls();
+ mExtraPaddingTopForNoDescription = activity.getResources()
+ .getDimensionPixelOffset(R.dimen.dvr_playback_controls_extra_padding_top);
+ }
+
+ @Override
+ public PlaybackControlsRowPresenter createControlsRowAndPresenter() {
+ PlaybackControlsRow controlsRow = new PlaybackControlsRow(this);
+ setControlsRow(controlsRow);
+ AbstractDetailsDescriptionPresenter detailsPresenter =
+ new AbstractDetailsDescriptionPresenter() {
+ @Override
+ protected void onBindDescription(
+ AbstractDetailsDescriptionPresenter.ViewHolder viewHolder, Object object) {
+ PlaybackControlGlue glue = (PlaybackControlGlue) object;
+ if (glue.hasValidMedia()) {
+ viewHolder.getTitle().setText(glue.getMediaTitle());
+ viewHolder.getSubtitle().setText(glue.getMediaSubtitle());
+ } else {
+ viewHolder.getTitle().setText("");
+ viewHolder.getSubtitle().setText("");
+ }
+ if (TextUtils.isEmpty(viewHolder.getSubtitle().getText())) {
+ viewHolder.view.setPadding(viewHolder.view.getPaddingLeft(),
+ mExtraPaddingTopForNoDescription,
+ viewHolder.view.getPaddingRight(), viewHolder.view.getPaddingBottom());
+ }
+ }
+ };
+ PlaybackControlsRowPresenter presenter =
+ new PlaybackControlsRowPresenter(detailsPresenter) {
+ @Override
+ protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
+ super.onBindRowViewHolder(vh, item);
+ vh.setOnKeyListener(DvrPlaybackControlHelper.this);
+ }
+
+ @Override
+ protected void onUnbindRowViewHolder(RowPresenter.ViewHolder vh) {
+ super.onUnbindRowViewHolder(vh);
+ vh.setOnKeyListener(null);
+ }
+ };
+ presenter.setProgressColor(getContext().getResources()
+ .getColor(R.color.play_controls_progress_bar_watched));
+ presenter.setBackgroundColor(getContext().getResources()
+ .getColor(R.color.play_controls_body_background_enabled));
+ presenter.setOnActionClickedListener(new OnActionClickedListener() {
+ @Override
+ public void onActionClicked(Action action) {
+ if (mReadyToControl) {
+ DvrPlaybackControlHelper.super.onActionClicked(action);
+ }
+ }
+ });
+ return presenter;
+ }
+
+ @Override
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+ if (mReadyToControl) {
+ if (keyCode == KeyEvent.KEYCODE_MEDIA_PAUSE && event.getAction() == KeyEvent.ACTION_DOWN
+ && (mPlaybackState == PlaybackState.STATE_FAST_FORWARDING
+ || mPlaybackState == PlaybackState.STATE_REWINDING)) {
+ // Workaround of b/31489271. Clicks play/pause button first to reset play controls
+ // to "play" state. Then we can pass MEDIA_PAUSE to let playback be paused.
+ onActionClicked(getControlsRow().getActionForKeyCode(keyCode));
+ }
+ return super.onKey(v, keyCode, event);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean hasValidMedia() {
+ PlaybackState playbackState = mMediaController.getPlaybackState();
+ return playbackState != null;
+ }
+
+ @Override
+ public boolean isMediaPlaying() {
+ PlaybackState playbackState = mMediaController.getPlaybackState();
+ if (playbackState == null) {
+ return false;
+ }
+ int state = playbackState.getState();
+ return state != PlaybackState.STATE_NONE && state != PlaybackState.STATE_CONNECTING
+ && state != PlaybackState.STATE_PAUSED;
+ }
+
+ /**
+ * Returns the ID of the media under playback.
+ */
+ public long getMediaId() {
+ MediaMetadata mediaMetadata = mMediaController.getMetadata();
+ return mediaMetadata == null ? UNKNOWN_MEDIA_ID
+ : mediaMetadata.getLong(MediaMetadata.METADATA_KEY_MEDIA_ID);
+ }
+
+ @Override
+ public CharSequence getMediaTitle() {
+ MediaMetadata mediaMetadata = mMediaController.getMetadata();
+ return mediaMetadata == null ? ""
+ : mediaMetadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ }
+
+ @Override
+ public CharSequence getMediaSubtitle() {
+ MediaMetadata mediaMetadata = mMediaController.getMetadata();
+ return mediaMetadata == null ? ""
+ : mediaMetadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE);
+ }
+
+ @Override
+ public int getMediaDuration() {
+ MediaMetadata mediaMetadata = mMediaController.getMetadata();
+ return mediaMetadata == null ? 0
+ : (int) mediaMetadata.getLong(MediaMetadata.METADATA_KEY_DURATION);
+ }
+
+ @Override
+ public Drawable getMediaArt() {
+ // Do not show the poster art on control row.
+ return null;
+ }
+
+ @Override
+ public long getSupportedActions() {
+ return ACTION_PLAY_PAUSE | ACTION_FAST_FORWARD | ACTION_REWIND;
+ }
+
+ @Override
+ public int getCurrentSpeedId() {
+ return mPlaybackSpeedId;
+ }
+
+ @Override
+ public int getCurrentPosition() {
+ PlaybackState playbackState = mMediaController.getPlaybackState();
+ if (playbackState == null) {
+ return 0;
+ }
+ return (int) playbackState.getPosition();
+ }
+
+ /**
+ * Unregister media controller's callback.
+ */
+ public void unregisterCallback() {
+ mMediaController.unregisterCallback(mMediaControllerCallback);
+ }
+
+ @Override
+ protected void startPlayback(int speedId) {
+ if (getCurrentSpeedId() == speedId) {
+ return;
+ }
+ if (speedId == PLAYBACK_SPEED_NORMAL) {
+ mTransportControls.play();
+ } else if (speedId <= -PLAYBACK_SPEED_FAST_L0) {
+ mTransportControls.rewind();
+ } else if (speedId >= PLAYBACK_SPEED_FAST_L0){
+ mTransportControls.fastForward();
+ }
+ }
+
+ @Override
+ protected void pausePlayback() {
+ mTransportControls.pause();
+ }
+
+ @Override
+ protected void skipToNext() {
+ // Do nothing.
+ }
+
+ @Override
+ protected void skipToPrevious() {
+ // Do nothing.
+ }
+
+ @Override
+ protected void onRowChanged(PlaybackControlsRow row) {
+ // Do nothing.
+ }
+
+ private void onStateChanged(int state, long positionMs, int speedLevel) {
+ if (DEBUG) Log.d(TAG, "onStateChanged");
+ getControlsRow().setCurrentTime((int) positionMs);
+ if (state == mPlaybackState && mPlaybackSpeedLevel == speedLevel) {
+ // Only position is changed, no need to update controls row
+ return;
+ }
+ // NOTICE: The below two variables should only be used in this method.
+ // The only usage of them is to confirm if the state is changed or not.
+ mPlaybackState = state;
+ mPlaybackSpeedLevel = speedLevel;
+ switch (state) {
+ case PlaybackState.STATE_PLAYING:
+ mPlaybackSpeedId = PLAYBACK_SPEED_NORMAL;
+ setFadingEnabled(true);
+ mReadyToControl = true;
+ break;
+ case PlaybackState.STATE_PAUSED:
+ mPlaybackSpeedId = PLAYBACK_SPEED_PAUSED;
+ setFadingEnabled(true);
+ mReadyToControl = true;
+ break;
+ case PlaybackState.STATE_FAST_FORWARDING:
+ mPlaybackSpeedId = PLAYBACK_SPEED_FAST_L0 + speedLevel;
+ setFadingEnabled(false);
+ mReadyToControl = true;
+ break;
+ case PlaybackState.STATE_REWINDING:
+ mPlaybackSpeedId = -PLAYBACK_SPEED_FAST_L0 - speedLevel;
+ setFadingEnabled(false);
+ mReadyToControl = true;
+ break;
+ case PlaybackState.STATE_CONNECTING:
+ setFadingEnabled(false);
+ mReadyToControl = false;
+ break;
+ case PlaybackState.STATE_NONE:
+ mReadyToControl = false;
+ break;
+ default:
+ setFadingEnabled(true);
+ break;
+ }
+ onStateChanged();
+ }
+
+ private class MediaControllerCallback extends MediaController.Callback {
+ @Override
+ public void onPlaybackStateChanged(PlaybackState state) {
+ if (DEBUG) Log.d(TAG, "Playback state changed: " + state.getState());
+ onStateChanged(state.getState(), state.getPosition(), (int) state.getPlaybackSpeed());
+ }
+
+ @Override
+ public void onMetadataChanged(MediaMetadata metadata) {
+ DvrPlaybackControlHelper.this.onMetadataChanged();
+ ((DvrPlaybackOverlayFragment) getFragment()).onMediaControllerUpdated();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrPlaybackOverlayFragment.java b/src/com/android/tv/dvr/ui/DvrPlaybackOverlayFragment.java
new file mode 100644
index 00000000..51ec93b8
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrPlaybackOverlayFragment.java
@@ -0,0 +1,304 @@
+/*
+ * 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.content.Context;
+import android.content.Intent;
+import android.graphics.Point;
+import android.hardware.display.DisplayManager;
+import android.media.tv.TvContentRating;
+import android.os.Bundle;
+import android.media.session.PlaybackState;
+import android.media.tv.TvInputManager;
+import android.media.tv.TvView;
+import android.support.v17.leanback.app.PlaybackOverlayFragment;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.PlaybackControlsRow;
+import android.support.v17.leanback.widget.PlaybackControlsRowPresenter;
+import android.support.v17.leanback.widget.SinglePresenterSelector;
+import android.view.Display;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Toast;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.BaseProgram;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.dialog.PinDialogFragment;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrPlayer;
+import com.android.tv.dvr.DvrPlaybackMediaSessionHelper;
+import com.android.tv.parental.ContentRatingsManager;
+import com.android.tv.util.Utils;
+
+public class DvrPlaybackOverlayFragment extends PlaybackOverlayFragment {
+ // TODO: Handles audio focus. Deals with block and ratings.
+ private static final String TAG = "DvrPlaybackOverlayFragment";
+ private static final boolean DEBUG = false;
+
+ private static final String MEDIA_SESSION_TAG = "com.android.tv.dvr.mediasession";
+ private static final float DISPLAY_ASPECT_RATIO_EPSILON = 0.01f;
+
+ // mProgram is only used to store program from intent. Don't use it elsewhere.
+ private RecordedProgram mProgram;
+ private DvrPlaybackMediaSessionHelper mMediaSessionHelper;
+ private DvrPlaybackControlHelper mPlaybackControlHelper;
+ private ArrayObjectAdapter mRowsAdapter;
+ private SortedArrayAdapter<BaseProgram> mRelatedRecordingsRowAdapter;
+ private DvrPlaybackCardPresenter mRelatedRecordingCardPresenter;
+ private DvrDataManager mDvrDataManager;
+ private ContentRatingsManager mContentRatingsManager;
+ private TvView mTvView;
+ private View mBlockScreenView;
+ private ListRow mRelatedRecordingsRow;
+ private int mExtraPaddingNoRelatedRow;
+ private int mWindowWidth;
+ private int mWindowHeight;
+ private float mAppliedAspectRatio;
+ private float mWindowAspectRatio;
+ private boolean mPinChecked;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ if (DEBUG) Log.d(TAG, "onCreate");
+ super.onCreate(savedInstanceState);
+ mExtraPaddingNoRelatedRow = getActivity().getResources()
+ .getDimensionPixelOffset(R.dimen.dvr_playback_fragment_extra_padding_top);
+ mDvrDataManager = TvApplication.getSingletons(getActivity()).getDvrDataManager();
+ mContentRatingsManager = TvApplication.getSingletons(getContext())
+ .getTvInputManagerHelper().getContentRatingsManager();
+ mProgram = getProgramFromIntent(getActivity().getIntent());
+ if (mProgram == null) {
+ Toast.makeText(getActivity(), getString(R.string.dvr_program_not_found),
+ Toast.LENGTH_SHORT).show();
+ getActivity().finish();
+ return;
+ }
+ Point size = new Point();
+ ((DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE))
+ .getDisplay(Display.DEFAULT_DISPLAY).getSize(size);
+ mWindowWidth = size.x;
+ mWindowHeight = size.y;
+ mWindowAspectRatio = mAppliedAspectRatio = (float) mWindowWidth / mWindowHeight;
+ setBackgroundType(PlaybackOverlayFragment.BG_LIGHT);
+ setFadingEnabled(true);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ mTvView = (TvView) getActivity().findViewById(R.id.dvr_tv_view);
+ mBlockScreenView = getActivity().findViewById(R.id.block_screen);
+ mMediaSessionHelper = new DvrPlaybackMediaSessionHelper(
+ getActivity(), MEDIA_SESSION_TAG, new DvrPlayer(mTvView), this);
+ mPlaybackControlHelper = new DvrPlaybackControlHelper(getActivity(), this);
+ setUpRows();
+ preparePlayback(getActivity().getIntent());
+ DvrPlayer dvrPlayer = mMediaSessionHelper.getDvrPlayer();
+ dvrPlayer.setAspectRatioChangedListener(new DvrPlayer.AspectRatioChangedListener() {
+ @Override
+ public void onAspectRatioChanged(float videoAspectRatio) {
+ updateAspectRatio(videoAspectRatio);
+ }
+ });
+ mPinChecked = getActivity().getIntent()
+ .getBooleanExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED, false);
+ dvrPlayer.setContentBlockedListener(new DvrPlayer.ContentBlockedListener() {
+ @Override
+ public void onContentBlocked(TvContentRating rating) {
+ if (mPinChecked) {
+ mTvView.unblockContent(rating);
+ return;
+ }
+ mBlockScreenView.setVisibility(View.VISIBLE);
+ getActivity().getMediaController().getTransportControls().pause();
+ new PinDialogFragment(PinDialogFragment.PIN_DIALOG_TYPE_UNLOCK_DVR,
+ new PinDialogFragment.ResultListener() {
+ @Override
+ public void done(boolean success) {
+ if (success) {
+ mPinChecked = true;
+ mTvView.unblockContent(rating);
+ mBlockScreenView.setVisibility(View.GONE);
+ getActivity().getMediaController()
+ .getTransportControls().play();
+ }
+ }
+ }, mContentRatingsManager.getDisplayNameForRating(rating))
+ .show(getActivity().getFragmentManager(), PinDialogFragment.DIALOG_TAG);
+ }
+ });
+ }
+
+ @Override
+ public void onPause() {
+ if (DEBUG) Log.d(TAG, "onPause");
+ super.onPause();
+ if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_FAST_FORWARDING
+ || mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_REWINDING) {
+ getActivity().getMediaController().getTransportControls().pause();
+ }
+ if (mMediaSessionHelper.getPlaybackState() == PlaybackState.STATE_NONE) {
+ getActivity().requestVisibleBehind(false);
+ } else {
+ getActivity().requestVisibleBehind(true);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Log.d(TAG, "onDestroy");
+ mPlaybackControlHelper.unregisterCallback();
+ mMediaSessionHelper.release();
+ mRelatedRecordingCardPresenter.unbindAllViewHolders();
+ super.onDestroy();
+ }
+
+ /**
+ * Passes the intent to the fragment.
+ */
+ public void onNewIntent(Intent intent) {
+ mProgram = getProgramFromIntent(intent);
+ if (mProgram == null) {
+ Toast.makeText(getActivity(), getString(R.string.dvr_program_not_found),
+ Toast.LENGTH_SHORT).show();
+ // Continue playing the original program
+ return;
+ }
+ preparePlayback(intent);
+ }
+
+ /**
+ * Should be called when windows' size is changed in order to notify DVR player
+ * to update it's view width/height and position.
+ */
+ public void onWindowSizeChanged(final int windowWidth, final int windowHeight) {
+ mWindowWidth = windowWidth;
+ mWindowHeight = windowHeight;
+ mWindowAspectRatio = (float) mWindowWidth / mWindowHeight;
+ updateAspectRatio(mAppliedAspectRatio);
+ }
+
+ public RecordedProgram getNextEpisode(RecordedProgram program) {
+ int position = mRelatedRecordingsRowAdapter.findInsertPosition(program);
+ if (position == mRelatedRecordingsRowAdapter.size()) {
+ return null;
+ } else {
+ return (RecordedProgram) mRelatedRecordingsRowAdapter.get(position);
+ }
+ }
+
+ void onMediaControllerUpdated() {
+ mRowsAdapter.notifyArrayItemRangeChanged(0, 1);
+ }
+
+ private void updateAspectRatio(float videoAspectRatio) {
+ if (Math.abs(mAppliedAspectRatio - videoAspectRatio) < DISPLAY_ASPECT_RATIO_EPSILON) {
+ // No need to change
+ return;
+ }
+ if (videoAspectRatio < mWindowAspectRatio) {
+ int newPadding = (mWindowWidth - Math.round(mWindowHeight * videoAspectRatio)) / 2;
+ ((ViewGroup) mTvView.getParent()).setPadding(newPadding, 0, newPadding, 0);
+ } else {
+ int newPadding = (mWindowHeight - Math.round(mWindowWidth / videoAspectRatio)) / 2;
+ ((ViewGroup) mTvView.getParent()).setPadding(0, newPadding, 0, newPadding);
+ }
+ mAppliedAspectRatio = videoAspectRatio;
+ }
+
+ private void preparePlayback(Intent intent) {
+ mMediaSessionHelper.setupPlayback(mProgram, getSeekTimeFromIntent(intent));
+ getActivity().getMediaController().getTransportControls().prepare();
+ updateRelatedRecordingsRow();
+ }
+
+ private void updateRelatedRecordingsRow() {
+ boolean wasEmpty = (mRelatedRecordingsRowAdapter.size() == 0);
+ mRelatedRecordingsRowAdapter.clear();
+ long programId = mProgram.getId();
+ String seriesId = mProgram.getSeriesId();
+ if (!TextUtils.isEmpty(seriesId)) {
+ if (DEBUG) Log.d(TAG, "Update related recordings with:" + seriesId);
+ for (RecordedProgram program : mDvrDataManager.getRecordedPrograms()) {
+ if (seriesId.equals(program.getSeriesId()) && programId != program.getId()) {
+ mRelatedRecordingsRowAdapter.add(program);
+ }
+ }
+ }
+ View view = getView();
+ if (mRelatedRecordingsRowAdapter.size() == 0) {
+ mRowsAdapter.remove(mRelatedRecordingsRow);
+ view.setPadding(view.getPaddingLeft(), mExtraPaddingNoRelatedRow,
+ view.getPaddingRight(), view.getPaddingBottom());
+ } else if (wasEmpty){
+ mRowsAdapter.add(mRelatedRecordingsRow);
+ view.setPadding(view.getPaddingLeft(), 0,
+ view.getPaddingRight(), view.getPaddingBottom());
+ }
+ }
+
+ private void setUpRows() {
+ PlaybackControlsRowPresenter controlsRowPresenter =
+ mPlaybackControlHelper.createControlsRowAndPresenter();
+
+ ClassPresenterSelector selector = new ClassPresenterSelector();
+ selector.addClassPresenter(PlaybackControlsRow.class, controlsRowPresenter);
+ selector.addClassPresenter(ListRow.class, new ListRowPresenter());
+
+ mRowsAdapter = new ArrayObjectAdapter(selector);
+ mRowsAdapter.add(mPlaybackControlHelper.getControlsRow());
+ mRelatedRecordingsRow = getRelatedRecordingsRow();
+ setAdapter(mRowsAdapter);
+ }
+
+ private ListRow getRelatedRecordingsRow() {
+ mRelatedRecordingCardPresenter = new DvrPlaybackCardPresenter(getActivity());
+ mRelatedRecordingsRowAdapter = new RelatedRecordingsAdapter(mRelatedRecordingCardPresenter);
+ HeaderItem header = new HeaderItem(0,
+ getActivity().getString(R.string.dvr_playback_related_recordings));
+ return new ListRow(header, mRelatedRecordingsRowAdapter);
+ }
+
+ private RecordedProgram getProgramFromIntent(Intent intent) {
+ long programId = intent.getLongExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_ID, -1);
+ return mDvrDataManager.getRecordedProgram(programId);
+ }
+
+ private long getSeekTimeFromIntent(Intent intent) {
+ return intent.getLongExtra(Utils.EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME,
+ TvInputManager.TIME_SHIFT_INVALID_TIME);
+ }
+
+ private class RelatedRecordingsAdapter extends SortedArrayAdapter<BaseProgram> {
+ RelatedRecordingsAdapter(DvrPlaybackCardPresenter presenter) {
+ super(new SinglePresenterSelector(presenter), BaseProgram.EPISODE_COMPARATOR);
+ }
+
+ @Override
+ long getId(BaseProgram item) {
+ return item.getId();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrRecordConflictFragment.java b/src/com/android/tv/dvr/ui/DvrRecordConflictFragment.java
deleted file mode 100644
index 92052b5b..00000000
--- a/src/com/android/tv/dvr/ui/DvrRecordConflictFragment.java
+++ /dev/null
@@ -1,82 +0,0 @@
-package com.android.tv.dvr.ui;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import com.android.tv.MainActivity;
-import com.android.tv.R;
-
-import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
-import android.support.v17.leanback.widget.GuidedAction;
-
-import com.android.tv.data.Channel;
-import com.android.tv.data.ChannelDataManager;
-import com.android.tv.data.Program;
-import com.android.tv.dvr.ScheduledRecording;
-import com.android.tv.guide.ProgramManager.TableEntry;
-
-import java.text.DateFormat;
-import java.util.Date;
-import java.util.List;
-
-public class DvrRecordConflictFragment extends DvrGuidedStepFragment {
- private static final int DVR_EPG_RECORD = 1;
- private static final int DVR_EPG_NOT_RECORD = 2;
-
- private List<ScheduledRecording> mConflicts;
-
- public DvrRecordConflictFragment(TableEntry entry) {
- super(entry);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- mConflicts = getDvrManager().getScheduledRecordingsThatConflict(getEntry().program);
- return super.onCreateView(inflater, container, savedInstanceState);
- }
-
- @Override
- public Guidance onCreateGuidance(Bundle savedInstanceState) {
- final MainActivity tvActivity = (MainActivity) getActivity();
- final ChannelDataManager channelDataManager = tvActivity.getChannelDataManager();
- StringBuilder sb = new StringBuilder();
- for (ScheduledRecording r : mConflicts) {
- Channel channel = channelDataManager.getChannel(r.getChannelId());
- if (channel == null) {
- continue;
- }
- sb.append(channel.getDisplayName())
- .append(" : ")
- .append(DateFormat.getDateTimeInstance().format(new Date(r.getStartTimeMs())))
- .append("\n");
- }
- String title = getResources().getString(R.string.dvr_epg_conflict_dialog_title);
- String description = sb.toString();
- return new Guidance(title, description, null, null);
- }
-
- @Override
- public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
- Activity activity = getActivity();
- actions.add(new GuidedAction.Builder(activity)
- .id(DVR_EPG_RECORD)
- .title(getResources().getString(R.string.dvr_epg_record))
- .build());
- actions.add(new GuidedAction.Builder(activity)
- .id(DVR_EPG_NOT_RECORD)
- .title(getResources().getString(R.string.dvr_epg_do_not_record))
- .build());
- }
-
- @Override
- public void onGuidedActionClicked(GuidedAction action) {
- Program program = getEntry().program;
- if (action.getId() == DVR_EPG_RECORD) {
- getDvrManager().addSchedule(program, mConflicts);
- }
- dismissDialog();
- }
-}
diff --git a/src/com/android/tv/dvr/ui/DvrRecordDeleteFragment.java b/src/com/android/tv/dvr/ui/DvrRecordDeleteFragment.java
deleted file mode 100644
index d4d5cc41..00000000
--- a/src/com/android/tv/dvr/ui/DvrRecordDeleteFragment.java
+++ /dev/null
@@ -1,48 +0,0 @@
-package com.android.tv.dvr.ui;
-
-import android.app.Activity;
-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.guide.ProgramManager.TableEntry;
-
-import java.util.List;
-
-public class DvrRecordDeleteFragment extends DvrGuidedStepFragment {
- private static final int ACTION_DELETE_YES = 1;
- private static final int ACTION_DELETE_NO = 2;
-
- public DvrRecordDeleteFragment(TableEntry entry) {
- super(entry);
- }
-
- @Override
- public Guidance onCreateGuidance(Bundle savedInstanceState) {
- String title = getResources().getString(R.string.epg_dvr_dialog_message_delete_schedule);
- return new Guidance(title, null, null, null);
- }
-
- @Override
- public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
- Activity activity = getActivity();
- actions.add(new GuidedAction.Builder(activity)
- .id(ACTION_DELETE_YES)
- .title(getResources().getString(android.R.string.yes))
- .build());
- actions.add(new GuidedAction.Builder(activity)
- .id(ACTION_DELETE_NO)
- .title(getResources().getString(android.R.string.no))
- .build());
- }
-
- @Override
- public void onGuidedActionClicked(GuidedAction action) {
- if (action.getId() == ACTION_DELETE_YES) {
- getDvrManager().removeScheduledRecording(getEntry().scheduledRecording);
- }
- dismissDialog();
- }
-}
diff --git a/src/com/android/tv/dvr/ui/DvrRecordScheduleFragment.java b/src/com/android/tv/dvr/ui/DvrRecordScheduleFragment.java
deleted file mode 100644
index 77e78ccc..00000000
--- a/src/com/android/tv/dvr/ui/DvrRecordScheduleFragment.java
+++ /dev/null
@@ -1,70 +0,0 @@
-package com.android.tv.dvr.ui;
-
-import android.app.Activity;
-import android.app.FragmentManager;
-import android.os.Bundle;
-
-import android.support.v17.leanback.app.GuidedStepFragment;
-import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
-import android.support.v17.leanback.widget.GuidedAction;
-
-import com.android.tv.data.Program;
-import com.android.tv.dialog.SafeDismissDialogFragment;
-import com.android.tv.dvr.ScheduledRecording;
-import com.android.tv.guide.ProgramManager.TableEntry;
-import com.android.tv.MainActivity;
-import com.android.tv.R;
-
-import java.util.List;
-
-public class DvrRecordScheduleFragment extends DvrGuidedStepFragment {
- private static final int ACTION_RECORD_YES = 1;
- private static final int ACTION_RECORD_NO = 2;
-
- public DvrRecordScheduleFragment(TableEntry entry) {
- super(entry);
- }
-
- @Override
- public Guidance onCreateGuidance(Bundle savedInstanceState) {
- String title = getResources().getString(R.string.epg_dvr_dialog_message_schedule_recording);
- return new Guidance(title, null, null, null);
- }
-
- @Override
- public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
- Activity activity = getActivity();
- actions.add(new GuidedAction.Builder(activity)
- .id(ACTION_RECORD_YES)
- .title(getResources().getString(android.R.string.yes))
- .build());
- actions.add(new GuidedAction.Builder(activity)
- .id(ACTION_RECORD_NO)
- .title(getResources().getString(android.R.string.no))
- .build());
- }
-
- @Override
- public void onGuidedActionClicked(GuidedAction action) {
- TableEntry entry = getEntry();
- Program program = entry.program;
- final List<ScheduledRecording> conflicts =
- getDvrManager().getScheduledRecordingsThatConflict(program);
- if (action.getId() == ACTION_RECORD_YES) {
- if (conflicts.isEmpty()) {
- getDvrManager().addSchedule(program, conflicts);
- dismissDialog();
- } else {
- DvrRecordConflictFragment dvrConflict = new DvrRecordConflictFragment(entry);
- SafeDismissDialogFragment currentDialog =
- ((MainActivity) getActivity()).getOverlayManager().getCurrentDialog();
- if (currentDialog instanceof DvrDialogFragment) {
- FragmentManager fm = currentDialog.getChildFragmentManager();
- GuidedStepFragment.add(fm, dvrConflict, R.id.halfsized_dialog_host);
- }
- }
- } else if (action.getId() == ACTION_RECORD_NO) {
- dismissDialog();
- }
- }
-}
diff --git a/src/com/android/tv/dvr/ui/DvrScheduleFragment.java b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java
new file mode 100644
index 00000000..da6d1637
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrScheduleFragment.java
@@ -0,0 +1,147 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.text.format.DateUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.ui.DvrConflictFragment.DvrProgramConflictFragment;
+import com.android.tv.util.Utils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A fragment which asks the user the type of the recording.
+ * <p>
+ * The program should be episodic and the series recording should not had been created yet.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrScheduleFragment extends DvrGuidedStepFragment {
+ private static final String TAG = "DvrScheduleFragment";
+
+ private static final int ACTION_RECORD_EPISODE = 1;
+ private static final int ACTION_RECORD_SERIES = 2;
+
+ private Program mProgram;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mProgram = args.getParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM);
+ }
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ SoftPreconditions.checkArgument(mProgram != null && mProgram.isEpisodic(), TAG,
+ "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: " + seriesRecording);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public int onProvideTheme() {
+ return R.style.Theme_TV_Dvr_GuidedStep_Twoline_Action;
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_schedule_dialog_title);
+ Drawable icon = getResources().getDrawable(R.drawable.ic_dvr, null);
+ return new Guidance(title, null, null, icon);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Context context = getContext();
+ String description;
+ if (mProgram.getStartTimeUtcMillis() <= System.currentTimeMillis()) {
+ description = getString(R.string.dvr_action_record_episode_from_now_description,
+ DateUtils.formatDateTime(context, mProgram.getEndTimeUtcMillis(),
+ DateUtils.FORMAT_SHOW_TIME));
+ } else {
+ description = Utils.getDurationString(context, mProgram.getStartTimeUtcMillis(),
+ mProgram.getEndTimeUtcMillis(), true);
+ }
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_RECORD_EPISODE)
+ .title(R.string.dvr_action_record_episode)
+ .description(description)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_RECORD_SERIES)
+ .title(R.string.dvr_action_record_series)
+ .description(mProgram.getTitle())
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_RECORD_EPISODE) {
+ getDvrManager().addSchedule(mProgram);
+ List<ScheduledRecording> conflicts = getDvrManager().getConflictingSchedules(mProgram);
+ if (conflicts.isEmpty()) {
+ DvrUiHelper.showAddScheduleToast(getContext(), mProgram.getTitle(),
+ mProgram.getStartTimeUtcMillis(), mProgram.getEndTimeUtcMillis());
+ dismissDialog();
+ } else {
+ GuidedStepFragment fragment = new DvrProgramConflictFragment();
+ Bundle args = new Bundle();
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, mProgram);
+ fragment.setArguments(args);
+ GuidedStepFragment.add(getFragmentManager(), fragment,
+ R.id.halfsized_dialog_host);
+ }
+ } else if (action.getId() == ACTION_RECORD_SERIES) {
+ SeriesRecording seriesRecording = TvApplication.getSingletons(getContext())
+ .getDvrDataManager().getSeriesRecording(mProgram.getSeriesId());
+ if (seriesRecording == null) {
+ seriesRecording = getDvrManager().addSeriesRecording(mProgram,
+ Collections.emptyList(), SeriesRecording.STATE_SERIES_STOPPED);
+ } else {
+ // Reset priority to the highest.
+ seriesRecording = SeriesRecording.buildFrom(seriesRecording)
+ .setPriority(TvApplication.getSingletons(getContext())
+ .getDvrScheduleManager().suggestNewSeriesPriority())
+ .build();
+ getDvrManager().updateSeriesRecording(seriesRecording);
+ }
+ DvrUiHelper.startSeriesSettingsActivity(getContext(),
+ seriesRecording.getId(), null, true, true, true);
+ dismissDialog();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrSchedulesActivity.java b/src/com/android/tv/dvr/ui/DvrSchedulesActivity.java
new file mode 100644
index 00000000..f6e6ac26
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrSchedulesActivity.java
@@ -0,0 +1,104 @@
+/*
+ * 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.app.Activity;
+import android.app.ProgressDialog;
+import android.os.Bundle;
+import android.support.annotation.IntDef;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.EpisodicProgramLoadTask;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.SeriesRecordingScheduler;
+import com.android.tv.dvr.ui.list.DvrSchedulesFragment;
+import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Activity to show the list of recording schedules.
+ */
+public class DvrSchedulesActivity extends Activity {
+ /**
+ * The key for the type of the schedules which will be listed in the list. The type of the value
+ * should be {@link ScheduleListType}.
+ */
+ public static final String KEY_SCHEDULES_TYPE = "schedules_type";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({TYPE_FULL_SCHEDULE, TYPE_SERIES_SCHEDULE})
+ public @interface ScheduleListType {}
+ /**
+ * A type which means the activity will display the full scheduled recordings.
+ */
+ public static final int TYPE_FULL_SCHEDULE = 0;
+ /**
+ * A type which means the activity will display a scheduled recording list of a series
+ * recording.
+ */
+ public static final int TYPE_SERIES_SCHEDULE = 1;
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, true);
+ // Pass null to prevent automatically re-creating fragments
+ super.onCreate(null);
+ setContentView(R.layout.activity_dvr_schedules);
+ int scheduleType = getIntent().getIntExtra(KEY_SCHEDULES_TYPE, TYPE_FULL_SCHEDULE);
+ if (scheduleType == TYPE_FULL_SCHEDULE) {
+ DvrSchedulesFragment schedulesFragment = new DvrSchedulesFragment();
+ schedulesFragment.setArguments(getIntent().getExtras());
+ getFragmentManager().beginTransaction().add(
+ R.id.fragment_container, schedulesFragment).commit();
+ } else if (scheduleType == TYPE_SERIES_SCHEDULE) {
+ final ProgressDialog dialog = ProgressDialog.show(this, null, getString(
+ R.string.dvr_series_schedules_progress_message_reading_programs));
+ SeriesRecording seriesRecording = getIntent().getExtras()
+ .getParcelable(DvrSeriesSchedulesFragment
+ .SERIES_SCHEDULES_KEY_SERIES_RECORDING);
+ // To get programs faster, hold the update of the series schedules.
+ SeriesRecordingScheduler.getInstance(this).pauseUpdate();
+ new EpisodicProgramLoadTask(this, Collections.singletonList(seriesRecording)) {
+ @Override
+ protected void onPostExecute(List<Program> programs) {
+ SeriesRecordingScheduler.getInstance(DvrSchedulesActivity.this).resumeUpdate();
+ dialog.dismiss();
+ Bundle args = getIntent().getExtras();
+ args.putParcelableArrayList(DvrSeriesSchedulesFragment
+ .SERIES_SCHEDULES_KEY_SERIES_PROGRAMS, new ArrayList<>(programs));
+ DvrSeriesSchedulesFragment schedulesFragment = new DvrSeriesSchedulesFragment();
+ schedulesFragment.setArguments(args);
+ getFragmentManager().beginTransaction().add(
+ R.id.fragment_container, schedulesFragment).commit();
+ }
+ }.setLoadCurrentProgram(true)
+ .setLoadDisallowedProgram(true)
+ .setLoadScheduledEpisode(true)
+ .setIgnoreChannelOption(true)
+ .execute();
+ } else {
+ finish();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java
new file mode 100644
index 00000000..f57e4b05
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrSeriesDeletionActivity.java
@@ -0,0 +1,50 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.ui.SeriesDeletionFragment;
+import com.android.tv.ui.sidepanel.SettingsFragment;
+
+/**
+ * Activity to show details view in DVR.
+ */
+public class DvrSeriesDeletionActivity extends Activity {
+ /**
+ * Name of series id added to the Intent.
+ */
+ public static final String SERIES_RECORDING_ID = "series_recording_id";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ 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.
+ if (savedInstanceState == null) {
+ SeriesDeletionFragment deletionFragment = new SeriesDeletionFragment();
+ deletionFragment.setArguments(getIntent().getExtras());
+ GuidedStepFragment.addAsRoot(this, deletionFragment, R.id.dvr_settings_view_frame);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java
new file mode 100644
index 00000000..1a0d13d3
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledDialogActivity.java
@@ -0,0 +1,48 @@
+/*
+ * 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.app.Activity;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+
+import com.android.tv.R;
+
+public class DvrSeriesScheduledDialogActivity extends Activity {
+ /**
+ * Name of series recording id added to the Intent.
+ */
+ public static final String SERIES_RECORDING_ID = "series_recording_id";
+
+ /**
+ * Name of flag to check if the dialog should show view schedule option.
+ */
+ public static final String SHOW_VIEW_SCHEDULE_OPTION = "show_view_schedule_option";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.halfsized_dialog);
+ if (savedInstanceState == null) {
+ DvrSeriesScheduledFragment dvrSeriesScheduledFragment =
+ new DvrSeriesScheduledFragment();
+ dvrSeriesScheduledFragment.setArguments(getIntent().getExtras());
+ GuidedStepFragment.addAsRoot(this, dvrSeriesScheduledFragment,
+ R.id.halfsized_dialog_host);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java
new file mode 100644
index 00000000..1173df46
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrSeriesScheduledFragment.java
@@ -0,0 +1,154 @@
+/*
+ * 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.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+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.TvApplication;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment;
+
+import java.util.List;
+
+public class DvrSeriesScheduledFragment extends DvrGuidedStepFragment {
+ private final static long SERIES_RECORDING_ID_NOT_SET = -1;
+
+ private final static int ACTION_VIEW_SCHEDULES = 1;
+
+ private DvrScheduleManager mDvrScheduleManager;
+ private SeriesRecording mSeriesRecording;
+ private boolean mShowViewScheduleOption;
+
+ private int mSchedulesAddedCount = 0;
+ private boolean mHasConflict = false;
+ private int mInThisSeriesConflictCount = 0;
+ private int mOutThisSeriesConflictCount = 0;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ long seriesRecordingId = getArguments().getLong(
+ DvrSeriesScheduledDialogActivity.SERIES_RECORDING_ID, SERIES_RECORDING_ID_NOT_SET);
+ if (seriesRecordingId == SERIES_RECORDING_ID_NOT_SET) {
+ getActivity().finish();
+ return;
+ }
+ mShowViewScheduleOption = getArguments().getBoolean(
+ DvrSeriesScheduledDialogActivity.SHOW_VIEW_SCHEDULE_OPTION);
+ mDvrScheduleManager = TvApplication.getSingletons(context).getDvrScheduleManager();
+ mSeriesRecording = TvApplication.getSingletons(context).getDvrDataManager()
+ .getSeriesRecording(seriesRecordingId);
+ if (mSeriesRecording == null) {
+ getActivity().finish();
+ return;
+ }
+ mSchedulesAddedCount = TvApplication.getSingletons(getContext()).getDvrManager()
+ .getAvailableScheduledRecording(mSeriesRecording.getId()).size();
+ List<ScheduledRecording> conflictingRecordings =
+ mDvrScheduleManager.getConflictingSchedules(mSeriesRecording);
+ mHasConflict = !conflictingRecordings.isEmpty();
+ for (ScheduledRecording recording : conflictingRecordings) {
+ if (recording.getSeriesRecordingId() == mSeriesRecording.getId()) {
+ ++mInThisSeriesConflictCount;
+ } else {
+ ++mOutThisSeriesConflictCount;
+ }
+ }
+ }
+
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_series_recording_dialog_title);
+ Drawable icon;
+ if (!mHasConflict) {
+ icon = getResources().getDrawable(R.drawable.ic_check_circle_white_48dp, null);
+ } else {
+ icon = getResources().getDrawable(R.drawable.ic_error_white_48dp, null);
+ }
+ return new GuidanceStylist.Guidance(title, getDescription(), null, icon);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ Context context = getContext();
+ actions.add(new GuidedAction.Builder(context)
+ .clickAction(GuidedAction.ACTION_ID_OK)
+ .build());
+ if (mShowViewScheduleOption) {
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_VIEW_SCHEDULES)
+ .title(R.string.dvr_action_view_schedules)
+ .build());
+ }
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_VIEW_SCHEDULES) {
+ Intent intent = new Intent(getActivity(), DvrSchedulesActivity.class);
+ intent.putExtra(DvrSchedulesActivity.KEY_SCHEDULES_TYPE, DvrSchedulesActivity
+ .TYPE_SERIES_SCHEDULE);
+ intent.putExtra(DvrSeriesSchedulesFragment.SERIES_SCHEDULES_KEY_SERIES_RECORDING,
+ mSeriesRecording);
+ startActivity(intent);
+ }
+ getActivity().finish();
+ }
+
+ private String getDescription() {
+ if (!mHasConflict) {
+ return getResources().getQuantityString(
+ R.plurals.dvr_series_recording_scheduled_no_conflict, mSchedulesAddedCount,
+ mSchedulesAddedCount, mSeriesRecording.getTitle());
+ } else {
+ // mInThisSeriesConflictCount equals 0 and mOutThisSeriesConflictCount equals 0 means
+ // mHasConflict is false. So we don't need to check that case.
+ if (mInThisSeriesConflictCount != 0 && mOutThisSeriesConflictCount != 0) {
+ return getResources().getQuantityString(R.plurals
+ .dvr_series_recording_scheduled_this_and_other_series_conflict,
+ mSchedulesAddedCount, mSchedulesAddedCount, mSeriesRecording.getTitle(),
+ mInThisSeriesConflictCount + mOutThisSeriesConflictCount);
+ } else if (mInThisSeriesConflictCount != 0) {
+ return getResources().getQuantityString(R.plurals
+ .dvr_series_recording_scheduled_only_this_series_conflict,
+ mSchedulesAddedCount, mSchedulesAddedCount, mSeriesRecording.getTitle(),
+ mInThisSeriesConflictCount);
+ } else {
+ if (mOutThisSeriesConflictCount == 1) {
+ return getResources().getQuantityString(R.plurals
+ .dvr_series_recording_scheduled_only_other_series_one_conflict,
+ mSchedulesAddedCount, mSchedulesAddedCount,
+ mSeriesRecording.getTitle());
+ } else {
+ return getResources().getQuantityString(R.plurals
+ .dvr_series_recording_scheduled_only_other_series_conflict,
+ mSchedulesAddedCount, mSchedulesAddedCount, mSeriesRecording.getTitle(),
+ mOutThisSeriesConflictCount);
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java
new file mode 100644
index 00000000..3f7671b3
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsActivity.java
@@ -0,0 +1,82 @@
+/*
+ * 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.app.Activity;
+import android.graphics.Color;
+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.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+
+/**
+ * Activity to show details view in DVR.
+ */
+public class DvrSeriesSettingsActivity extends Activity {
+ /**
+ * Name of series id added to the Intent.
+ * Type: Long
+ */
+ public static final String SERIES_RECORDING_ID = "series_recording_id";
+ /**
+ * Name of the boolean flag to decide if the series recording with empty schedule and recording
+ * will be removed.
+ */
+ public static final String REMOVE_EMPTY_SERIES_RECORDING = "remove_empty_series_recording";
+ /**
+ * Name of the boolean flag to decide if the setting fragment should be translucent.
+ */
+ public static final String IS_WINDOW_TRANSLUCENT = "windows_translucent";
+ /**
+ * Name of the channel id list. If the channel list is given, we show the channels
+ * from the values in channel option.
+ * Type: Long array
+ */
+ public static final String CHANNEL_ID_LIST = "channel_id_list";
+
+ /**
+ * Name of the boolean flag to check if the confirm dialog should show view schedule option.
+ */
+ public static final String SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG =
+ "show_view_schedule_option_in_dialog";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, true);
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_dvr_series_settings);
+ long seriesRecordingId = getIntent().getLongExtra(SERIES_RECORDING_ID, -1);
+ SoftPreconditions.checkArgument(seriesRecordingId != -1);
+
+ if (savedInstanceState == null) {
+ SeriesSettingsFragment settingFragment = new SeriesSettingsFragment();
+ settingFragment.setArguments(getIntent().getExtras());
+ GuidedStepFragment.addAsRoot(this, settingFragment, R.id.dvr_settings_view_frame);
+ }
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ if (!getIntent().getExtras().getBoolean(IS_WINDOW_TRANSLUCENT, true)) {
+ getWindow().setBackgroundDrawable(
+ new ColorDrawable(getColor(R.color.common_tv_background)));
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java
new file mode 100644
index 00000000..c3867886
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrStopRecordingFragment.java
@@ -0,0 +1,161 @@
+/*
+ * 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.annotation.TargetApi;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.Bundle;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.dvr.ScheduledRecording;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+
+/**
+ * A fragment which asks the user to make a recording schedule for the program.
+ * <p>
+ * If the program belongs to a series and the series recording is not created yet, we will show the
+ * option to record all the episodes of the series.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrStopRecordingFragment extends DvrGuidedStepFragment {
+ /**
+ * The action ID for the stop action.
+ */
+ public static final int ACTION_STOP = 1;
+ /**
+ * Key for the program.
+ * Type: {@link com.android.tv.data.Program}.
+ */
+ public static final String KEY_REASON = "DvrStopRecordingFragment.type";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({REASON_USER_STOP, REASON_ON_CONFLICT})
+ public @interface ReasonType {}
+ /**
+ * The dialog is shown because users want to stop some currently recording program.
+ */
+ public static final int REASON_USER_STOP = 1;
+ /**
+ * The dialog is shown because users want to record some program that is conflict to the
+ * current recording program.
+ */
+ public static final int REASON_ON_CONFLICT = 2;
+
+ private ScheduledRecording mSchedule;
+ private DvrDataManager mDvrDataManager;
+ private @ReasonType int mStopReason;
+
+ private final ScheduledRecordingListener mScheduledRecordingListener =
+ new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... schedules) { }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.getId() == mSchedule.getId()) {
+ dismissDialog();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ if (schedule.getId() == mSchedule.getId()
+ && schedule.getState()
+ != ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ dismissDialog();
+ return;
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ Bundle args = getArguments();
+ long channelId = args.getLong(DvrHalfSizedDialogFragment.KEY_CHANNEL_ID);
+ mSchedule = getDvrManager().getCurrentRecording(channelId);
+ if (mSchedule == null) {
+ dismissDialog();
+ return;
+ }
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
+ mStopReason = args.getInt(KEY_REASON);
+ }
+
+ @Override
+ public void onDetach() {
+ if (mDvrDataManager != null) {
+ mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener);
+ }
+ super.onDetach();
+ }
+
+ @NonNull
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_stop_recording_dialog_title);
+ String description;
+ if (mStopReason == REASON_ON_CONFLICT) {
+ String programTitle = mSchedule.getProgramTitle();
+ if (TextUtils.isEmpty(programTitle)) {
+ ChannelDataManager channelDataManager =
+ TvApplication.getSingletons(getActivity()).getChannelDataManager();
+ Channel channel = channelDataManager.getChannel(mSchedule.getChannelId());
+ programTitle = channel.getDisplayName();
+ }
+ description = getString(R.string.dvr_stop_recording_dialog_description_on_conflict,
+ mSchedule.getProgramTitle());
+ } else {
+ description = getString(R.string.dvr_stop_recording_dialog_description);
+ }
+ Drawable image = getResources().getDrawable(R.drawable.ic_warning_white_96dp, null);
+ return new Guidance(title, description, null, image);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Context context = getContext();
+ actions.add(new GuidedAction.Builder(context)
+ .id(ACTION_STOP)
+ .title(R.string.dvr_action_stop)
+ .build());
+ actions.add(new GuidedAction.Builder(context)
+ .clickAction(GuidedAction.ACTION_ID_CANCEL)
+ .build());
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java
new file mode 100644
index 00000000..5b880bd6
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingDialogFragment.java
@@ -0,0 +1,48 @@
+/*
+ * 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.app.DialogFragment;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.R;
+
+/**
+ * A dialog fragment which contains {@link DvrStopSeriesRecordingFragment}.
+ */
+public class DvrStopSeriesRecordingDialogFragment extends DialogFragment {
+ public static final String DIALOG_TAG = "dialog_tag";
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = inflater.inflate(R.layout.halfsized_dialog, container, false);
+ GuidedStepFragment fragment = new DvrStopSeriesRecordingFragment();
+ fragment.setArguments(getArguments());
+ GuidedStepFragment.add(getChildFragmentManager(), fragment, R.id.halfsized_dialog_host);
+ return view;
+ }
+
+ @Override
+ public int getTheme() {
+ return R.style.Theme_TV_dialog_HalfSizedDialog;
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java
new file mode 100644
index 00000000..feaa2357
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/DvrStopSeriesRecordingFragment.java
@@ -0,0 +1,104 @@
+/*
+ * 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.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.v17.leanback.widget.GuidanceStylist;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A fragment which asks the user to stop series recording.
+ */
+public class DvrStopSeriesRecordingFragment extends DvrGuidedStepFragment {
+ /**
+ * Key for the series recording to be stopped.
+ */
+ public static final String KEY_SERIES_RECORDING = "key_series_recoridng";
+
+ private static final int ACTION_STOP_SERIES_RECORDING = 1;
+
+ private SeriesRecording mSeriesRecording;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ mSeriesRecording = getArguments().getParcelable(KEY_SERIES_RECORDING);
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ @NonNull
+ @Override
+ public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String title = getString(R.string.dvr_series_schedules_stop_dialog_title);
+ String description = getString(R.string.dvr_series_schedules_stop_dialog_description);
+ Drawable icon = getContext().getDrawable(R.drawable.ic_dvr_delete);
+ return new GuidanceStylist.Guidance(title, description, null, icon);
+ }
+
+ @Override
+ public void onCreateActions(@NonNull List<GuidedAction> actions, Bundle savedInstanceState) {
+ Activity activity = getActivity();
+ actions.add(new GuidedAction.Builder(activity)
+ .id(ACTION_STOP_SERIES_RECORDING)
+ .title(R.string.dvr_series_schedules_stop_dialog_action_stop)
+ .build());
+ actions.add(new GuidedAction.Builder(activity)
+ .clickAction(GuidedAction.ACTION_ID_CANCEL)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ if (action.getId() == ACTION_STOP_SERIES_RECORDING) {
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
+ DvrManager dvrManager = singletons.getDvrManager();
+ DvrDataManager dataManager = singletons.getDvrDataManager();
+ List<ScheduledRecording> toDelete = new ArrayList<>();
+ for (ScheduledRecording r : dataManager.getAvailableScheduledRecordings()) {
+ if (r.getSeriesRecordingId() == mSeriesRecording.getId()) {
+ if (r.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ toDelete.add(r);
+ } else {
+ dvrManager.stopRecording(r);
+ }
+ }
+ }
+ if (!toDelete.isEmpty()) {
+ dvrManager.forceRemoveScheduledRecording(ScheduledRecording.toArray(toDelete));
+ }
+ dvrManager.updateSeriesRecording(SeriesRecording.buildFrom(mSeriesRecording)
+ .setState(SeriesRecording.STATE_SERIES_STOPPED).build());
+ }
+ dismissDialog();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/EmptyItemPresenter.java b/src/com/android/tv/dvr/ui/EmptyItemPresenter.java
deleted file mode 100644
index c0305128..00000000
--- a/src/com/android/tv/dvr/ui/EmptyItemPresenter.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.dvr.ui;
-
-import android.content.res.Resources;
-import android.graphics.Color;
-import android.support.v17.leanback.widget.Presenter;
-import android.view.Gravity;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import com.android.tv.R;
-import com.android.tv.TvApplication;
-import com.android.tv.data.ChannelDataManager;
-import com.android.tv.util.Utils;
-
-/**
- * Shows the item "NONE". Used for rows with now items.
- */
-public class EmptyItemPresenter extends Presenter {
-
- private final DvrBrowseFragment mMainFragment;
-
- public EmptyItemPresenter(DvrBrowseFragment mainFragment) {
- mMainFragment = mainFragment;
- }
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent) {
- TextView view = new TextView(parent.getContext());
- Resources resources = view.getResources();
- view.setLayoutParams(new ViewGroup.LayoutParams(
- resources.getDimensionPixelSize(R.dimen.dvr_card_layout_width),
- resources.getDimensionPixelSize(R.dimen.dvr_card_layout_width)));
- view.setFocusable(true);
- view.setFocusableInTouchMode(true);
- view.setBackgroundColor(
- Utils.getColor(mMainFragment.getResources(), R.color.setup_background));
- view.setTextColor(Color.WHITE);
- view.setGravity(Gravity.CENTER);
- return new ViewHolder(view);
- }
-
- @Override
- public void onBindViewHolder(ViewHolder viewHolder, Object recording) {
- ((TextView) viewHolder.view).setText(
- viewHolder.view.getContext().getString(R.string.dvr_msg_no_recording_on_the_row));
- }
-
- @Override
- public void onUnbindViewHolder(ViewHolder viewHolder) { }
-}
diff --git a/src/com/android/tv/dvr/SeasonRecording.java b/src/com/android/tv/dvr/ui/FullScheduleCardHolder.java
index 7f89e135..d4d4d8ab 100644
--- a/src/com/android/tv/dvr/SeasonRecording.java
+++ b/src/com/android/tv/dvr/ui/FullScheduleCardHolder.java
@@ -1,5 +1,5 @@
/*
- * 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,22 +14,16 @@
* limitations under the License.
*/
-package com.android.tv.dvr;
-
-import java.util.List;
+package com.android.tv.dvr.ui;
/**
- * A data class for one recorded contents.
+ * Special object for schedule preview;
*/
-public class SeasonRecording {
- private static final String TAG = "Recording";
-
+final class FullScheduleCardHolder {
/**
- * Constant for all season.
+ * Full schedule card holder.
*/
- private static final int ALL_SEASON = -1;
+ static final FullScheduleCardHolder FULL_SCHEDULE_CARD_HOLDER = new FullScheduleCardHolder();
- private List<ScheduledRecording> mSchedule;
- private String mTitle;
- private int mSeasonNumber;
+ private FullScheduleCardHolder() { }
}
diff --git a/src/com/android/tv/dvr/ui/FullSchedulesCardPresenter.java b/src/com/android/tv/dvr/ui/FullSchedulesCardPresenter.java
new file mode 100644
index 00000000..7dd85f45
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/FullSchedulesCardPresenter.java
@@ -0,0 +1,84 @@
+/*
+ * 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.content.Context;
+import android.support.v17.leanback.widget.Presenter;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.util.Utils;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Presents a {@link ScheduledRecording} in the {@link DvrBrowseFragment}.
+ */
+public class FullSchedulesCardPresenter extends Presenter {
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ Context context = parent.getContext();
+ RecordingCardView view = new RecordingCardView(context);
+ return new ScheduledRecordingViewHolder(view);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder baseHolder, Object o) {
+ final ScheduledRecordingViewHolder viewHolder = (ScheduledRecordingViewHolder) baseHolder;
+ final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
+ final Context context = viewHolder.view.getContext();
+
+ cardView.setImage(context.getDrawable(R.drawable.dvr_full_schedule));
+ cardView.setTitle(context.getString(R.string.dvr_full_schedule_card_view_title));
+ List<ScheduledRecording> scheduledRecordings = TvApplication.getSingletons(context)
+ .getDvrDataManager().getAvailableScheduledRecordings();
+ int fullDays = 0;
+ if (!scheduledRecordings.isEmpty()) {
+ fullDays = Utils.computeDateDifference(System.currentTimeMillis(),
+ Collections.max(scheduledRecordings, ScheduledRecording.START_TIME_COMPARATOR)
+ .getStartTimeMs()) + 1;
+ }
+ cardView.setContent(context.getResources().getQuantityString(
+ R.plurals.dvr_full_schedule_card_view_content, fullDays, fullDays), null);
+
+ View.OnClickListener clickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ DvrUiHelper.startSchedulesActivity(context, null);
+ }
+ };
+ baseHolder.view.setOnClickListener(clickListener);
+ }
+
+ @Override
+ public void onUnbindViewHolder(ViewHolder baseHolder) {
+ ScheduledRecordingViewHolder viewHolder = (ScheduledRecordingViewHolder) baseHolder;
+ final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
+ cardView.reset();
+ }
+
+ private static final class ScheduledRecordingViewHolder extends ViewHolder {
+ ScheduledRecordingViewHolder(RecordingCardView view) {
+ super(view);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/HalfSizedDialogFragment.java b/src/com/android/tv/dvr/ui/HalfSizedDialogFragment.java
index dc89a8e0..d320816e 100644
--- a/src/com/android/tv/dvr/ui/HalfSizedDialogFragment.java
+++ b/src/com/android/tv/dvr/ui/HalfSizedDialogFragment.java
@@ -1,21 +1,83 @@
+/*
+ * 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.content.DialogInterface;
import android.os.Bundle;
+import android.os.Handler;
+import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import com.android.tv.dialog.SafeDismissDialogFragment;
import com.android.tv.R;
+import com.android.tv.dialog.SafeDismissDialogFragment;
+
+import java.util.concurrent.TimeUnit;
public class HalfSizedDialogFragment extends SafeDismissDialogFragment {
public static final String DIALOG_TAG = HalfSizedDialogFragment.class.getSimpleName();
public static final String TRACKER_LABEL = "Half sized dialog";
+ private static final long AUTO_DISMISS_TIME_THRESHOLD_MS = TimeUnit.SECONDS.toMillis(30);
+
+ private OnActionClickListener mOnActionClickListener;
+
+ private Handler mHandler = new Handler();
+ private Runnable mAutoDismisser = new Runnable() {
+ @Override
+ public void run() {
+ dismiss();
+ }
+ };
+
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- return inflater.inflate(R.layout.halfsized_dialog, null);
+ return inflater.inflate(R.layout.halfsized_dialog, container, false);
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ getDialog().setOnKeyListener(new DialogInterface.OnKeyListener() {
+ public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent keyEvent) {
+ mHandler.removeCallbacks(mAutoDismisser);
+ mHandler.postDelayed(mAutoDismisser, AUTO_DISMISS_TIME_THRESHOLD_MS);
+ return false;
+ }
+ });
+ mHandler.postDelayed(mAutoDismisser, AUTO_DISMISS_TIME_THRESHOLD_MS);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mOnActionClickListener != null) {
+ // Dismisses the dialog to prevent the callback being forgotten during
+ // fragment re-creating.
+ dismiss();
+ }
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ mHandler.removeCallbacks(mAutoDismisser);
}
@Override
@@ -27,4 +89,29 @@ public class HalfSizedDialogFragment extends SafeDismissDialogFragment {
public String getTrackerLabel() {
return TRACKER_LABEL;
}
-}
+
+ /**
+ * Sets {@link OnActionClickListener} for the dialog fragment. If listener is set, the dialog
+ * will be automatically closed when it's paused to prevent the fragment being re-created by
+ * the framework, which will result the listener being forgotten.
+ */
+ public void setOnActionClickListener(OnActionClickListener listener) {
+ mOnActionClickListener = listener;
+ }
+
+ /**
+ * Returns {@link OnActionClickListener} for sub-classes or any inner fragments.
+ */
+ protected OnActionClickListener getOnActionClickListener() {
+ return mOnActionClickListener;
+ }
+
+ /**
+ * An interface to provide callbacks for half-sized dialogs. Subclasses or inner fragments
+ * should invoke {@link OnActionClickListener#onActionClick(long)} and provide the identifier
+ * of the action user clicked.
+ */
+ public interface OnActionClickListener {
+ void onActionClick(long actionId);
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/PrioritySettingsFragment.java b/src/com/android/tv/dvr/ui/PrioritySettingsFragment.java
new file mode 100644
index 00000000..158bd824
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/PrioritySettingsFragment.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.ui;
+
+import android.app.FragmentManager;
+import android.content.Context;
+import android.graphics.Typeface;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.SeriesRecording;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Fragment for DVR series recording settings.
+ */
+public class PrioritySettingsFragment extends GuidedStepFragment {
+ /**
+ * Name of series recording id starting the fragment.
+ * Type: Long
+ */
+ public static final String COME_FROM_SERIES_RECORDING_ID = "series_recording_id";
+
+ private static final int ONE_TIME_RECORDING_ID = 0;
+ // button action's IDs are negative.
+ private static final long ACTION_ID_SAVE = -100L;
+
+ private final List<SeriesRecording> mSeriesRecordings = new ArrayList<>();
+
+ private SeriesRecording mSelectedRecording;
+ private SeriesRecording mComeFromSeriesRecording;
+ private float mSelectedActionElevation;
+ private int mActionColor;
+ private int mSelectedActionColor;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mSeriesRecordings.clear();
+ mSeriesRecordings.add(new SeriesRecording.Builder()
+ .setTitle(getString(R.string.dvr_priority_action_one_time_recording))
+ .setPriority(Long.MAX_VALUE)
+ .setId(ONE_TIME_RECORDING_ID)
+ .build());
+ 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
+ || series.getId() == comeFromSeriesRecordingId) {
+ mSeriesRecordings.add(series);
+ }
+ }
+ mSeriesRecordings.sort(SeriesRecording.PRIORITY_COMPARATOR);
+ mComeFromSeriesRecording = dvrDataManager.getSeriesRecording(comeFromSeriesRecordingId);
+ mSelectedActionElevation = getResources().getDimension(R.dimen.card_elevation_normal);
+ mActionColor = getResources().getColor(R.color.dvr_guided_step_action_text_color, null);
+ mSelectedActionColor =
+ getResources().getColor(R.color.dvr_guided_step_action_text_color_selected, null);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ setSelectedActionPosition(mComeFromSeriesRecording == null ? 1
+ : mSeriesRecordings.indexOf(mComeFromSeriesRecording));
+ }
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String breadcrumb = mComeFromSeriesRecording == null ? null
+ : mComeFromSeriesRecording.getTitle();
+ return new Guidance(getString(R.string.dvr_priority_title),
+ getString(R.string.dvr_priority_description), breadcrumb, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ int position = 0;
+ for (SeriesRecording seriesRecording : mSeriesRecordings) {
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(position++)
+ .title(seriesRecording.getTitle())
+ .build());
+ }
+ }
+
+ @Override
+ public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_SAVE)
+ .title(getString(R.string.dvr_priority_button_action_save))
+ .build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .clickAction(GuidedAction.ACTION_ID_CANCEL)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ long actionId = action.getId();
+ if (actionId == ACTION_ID_SAVE) {
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ int size = mSeriesRecordings.size();
+ for (int i = 1; i < size; ++i) {
+ long priority = DvrScheduleManager.suggestSeriesPriority(size - i);
+ SeriesRecording seriesRecording = mSeriesRecordings.get(i);
+ if (seriesRecording.getPriority() != priority) {
+ dvrManager.updateSeriesRecording(SeriesRecording.buildFrom(seriesRecording)
+ .setPriority(priority).build());
+ }
+ }
+ FragmentManager fragmentManager = getFragmentManager();
+ fragmentManager.popBackStack();
+ } else if (actionId == GuidedAction.ACTION_ID_CANCEL) {
+ FragmentManager fragmentManager = getFragmentManager();
+ fragmentManager.popBackStack();
+ } else if (mSelectedRecording == null) {
+ mSelectedRecording = mSeriesRecordings.get((int) actionId);
+ for (int i = 0; i < mSeriesRecordings.size(); ++i) {
+ updateItem(i);
+ }
+ } else {
+ mSelectedRecording = null;
+ for (int i = 0; i < mSeriesRecordings.size(); ++i) {
+ updateItem(i);
+ }
+ }
+ }
+
+ @Override
+ public void onGuidedActionFocused(GuidedAction action) {
+ super.onGuidedActionFocused(action);
+ if (mSelectedRecording == null) {
+ return;
+ }
+ if (action.getId() < 0) {
+ int selectedPosition = mSeriesRecordings.indexOf(mSelectedRecording);
+ mSelectedRecording = null;
+ for (int i = 0; i < mSeriesRecordings.size(); ++i) {
+ updateItem(i);
+ }
+ return;
+ }
+ int position = (int) action.getId();
+ int previousPosition = mSeriesRecordings.indexOf(mSelectedRecording);
+ mSeriesRecordings.remove(mSelectedRecording);
+ mSeriesRecordings.add(position, mSelectedRecording);
+ updateItem(previousPosition);
+ updateItem(position);
+ notifyActionChanged(previousPosition);
+ notifyActionChanged(position);
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateButtonActionsStylist() {
+ return new DvrGuidedActionsStylist(true);
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateActionsStylist() {
+ return new DvrGuidedActionsStylist(false) {
+ @Override
+ public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
+ super.onBindViewHolder(vh, action);
+ updateItem(vh.itemView, (int) action.getId());
+ }
+
+ @Override
+ public int onProvideItemLayoutId() {
+ return R.layout.priority_settings_action_item;
+ }
+ };
+ }
+
+ private void updateItem(int position) {
+ View itemView = getActionItemView(position);
+ if (itemView == null) {
+ return;
+ }
+ updateItem(itemView, position);
+ }
+
+ private void updateItem(View itemView, int position) {
+ GuidedAction action = getActions().get(position);
+ action.setTitle(mSeriesRecordings.get(position).getTitle());
+ boolean selected = mSelectedRecording != null
+ && mSeriesRecordings.indexOf(mSelectedRecording) == position;
+ TextView titleView = (TextView) itemView.findViewById(R.id.guidedactions_item_title);
+ ImageView imageView = (ImageView) itemView.findViewById(R.id.guidedactions_item_tail_image);
+ if (position == 0) {
+ // one-time recording
+ itemView.setBackgroundResource(R.drawable.setup_selector_background);
+ imageView.setVisibility(View.GONE);
+ itemView.setFocusable(false);
+ itemView.setElevation(0);
+ // strings.xml <i> tag doesn't work.
+ titleView.setTypeface(titleView.getTypeface(), Typeface.ITALIC);
+ } else if (mSelectedRecording == null) {
+ titleView.setTextColor(mActionColor);
+ itemView.setBackgroundResource(R.drawable.setup_selector_background);
+ imageView.setImageResource(R.drawable.ic_draggable_white);
+ imageView.setVisibility(View.VISIBLE);
+ itemView.setFocusable(true);
+ itemView.setElevation(0);
+ titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL);
+ } else if (selected) {
+ titleView.setTextColor(mSelectedActionColor);
+ itemView.setBackgroundResource(R.drawable.priority_settings_action_item_selected);
+ imageView.setImageResource(R.drawable.ic_dragging_grey);
+ imageView.setVisibility(View.VISIBLE);
+ itemView.setFocusable(true);
+ itemView.setElevation(mSelectedActionElevation);
+ titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL);
+ } else {
+ titleView.setTextColor(mActionColor);
+ itemView.setBackgroundResource(R.drawable.setup_selector_background);
+ imageView.setVisibility(View.INVISIBLE);
+ itemView.setFocusable(true);
+ itemView.setElevation(0);
+ titleView.setTypeface(titleView.getTypeface(), Typeface.NORMAL);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/RecordedProgramDetailsFragment.java b/src/com/android/tv/dvr/ui/RecordedProgramDetailsFragment.java
new file mode 100644
index 00000000..e698b8a2
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/RecordedProgramDetailsFragment.java
@@ -0,0 +1,170 @@
+/*
+ * 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.content.res.Resources;
+import android.media.tv.TvInputManager;
+import android.os.Bundle;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.RecordedProgram;
+
+/**
+ * {@link DetailsFragment} for recorded program in DVR.
+ */
+public class RecordedProgramDetailsFragment extends DvrDetailsFragment
+ implements DvrDataManager.RecordedProgramListener {
+ private static final int ACTION_RESUME_PLAYING = 1;
+ private static final int ACTION_PLAY_FROM_BEGINNING = 2;
+ private static final int ACTION_DELETE_RECORDING = 3;
+
+ private DvrWatchedPositionManager mDvrWatchedPositionManager;
+
+ private RecordedProgram mRecordedProgram;
+ private DetailsContent mDetailsContent;
+ private boolean mPaused;
+ private DvrDataManager mDvrDataManager;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ mDvrDataManager = TvApplication.getSingletons(getContext()).getDvrDataManager();
+ mDvrDataManager.addRecordedProgramListener(this);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ public void onCreateInternal() {
+ mDvrWatchedPositionManager = TvApplication.getSingletons(getActivity())
+ .getDvrWatchedPositionManager();
+ setDetailsOverviewRow(mDetailsContent);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mPaused) {
+ updateActions();
+ mPaused = false;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mPaused = true;
+ }
+
+ @Override
+ public void onDestroy() {
+ mDvrDataManager.removeRecordedProgramListener(this);
+ super.onDestroy();
+ }
+
+ @Override
+ protected boolean onLoadRecordingDetails(Bundle args) {
+ long recordedProgramId = args.getLong(DvrDetailsActivity.RECORDING_ID);
+ mRecordedProgram = mDvrDataManager.getRecordedProgram(recordedProgramId);
+ if (mRecordedProgram == null) {
+ // notify super class to end activity before initializing anything
+ return false;
+ }
+ mDetailsContent = createDetailsContent();
+ return true;
+ }
+
+ private DetailsContent createDetailsContent() {
+ Channel channel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(mRecordedProgram.getChannelId());
+ String description = TextUtils.isEmpty(mRecordedProgram.getLongDescription())
+ ? mRecordedProgram.getDescription() : mRecordedProgram.getLongDescription();
+ return new DetailsContent.Builder()
+ .setTitle(getTitleFromProgram(mRecordedProgram, channel))
+ .setStartTimeUtcMillis(mRecordedProgram.getStartTimeUtcMillis())
+ .setEndTimeUtcMillis(mRecordedProgram.getEndTimeUtcMillis())
+ .setDescription(description)
+ .setImageUris(mRecordedProgram, channel)
+ .build();
+ }
+
+ @Override
+ protected SparseArrayObjectAdapter onCreateActionsAdapter() {
+ SparseArrayObjectAdapter adapter =
+ new SparseArrayObjectAdapter(new ActionPresenterSelector());
+ Resources res = getResources();
+ if (mDvrWatchedPositionManager.getWatchedStatus(mRecordedProgram)
+ == DvrWatchedPositionManager.DVR_WATCHED_STATUS_WATCHING) {
+ adapter.set(ACTION_RESUME_PLAYING, new Action(ACTION_RESUME_PLAYING,
+ res.getString(R.string.dvr_detail_resume_play), null,
+ res.getDrawable(R.drawable.lb_ic_play)));
+ adapter.set(ACTION_PLAY_FROM_BEGINNING, new Action(ACTION_PLAY_FROM_BEGINNING,
+ res.getString(R.string.dvr_detail_play_from_beginning), null,
+ res.getDrawable(R.drawable.lb_ic_replay)));
+ } else {
+ adapter.set(ACTION_PLAY_FROM_BEGINNING, new Action(ACTION_PLAY_FROM_BEGINNING,
+ res.getString(R.string.dvr_detail_watch), null,
+ res.getDrawable(R.drawable.lb_ic_play)));
+ }
+ adapter.set(ACTION_DELETE_RECORDING, new Action(ACTION_DELETE_RECORDING,
+ res.getString(R.string.dvr_detail_delete), null,
+ res.getDrawable(R.drawable.ic_delete_32dp)));
+ return adapter;
+ }
+
+ @Override
+ protected OnActionClickedListener onCreateOnActionClickedListener() {
+ return new OnActionClickedListener() {
+ @Override
+ public void onActionClicked(Action action) {
+ if (action.getId() == ACTION_PLAY_FROM_BEGINNING) {
+ startPlayback(mRecordedProgram, TvInputManager.TIME_SHIFT_INVALID_TIME);
+ } else if (action.getId() == ACTION_RESUME_PLAYING) {
+ startPlayback(mRecordedProgram, mDvrWatchedPositionManager
+ .getWatchedPosition(mRecordedProgram.getId()));
+ } else if (action.getId() == ACTION_DELETE_RECORDING) {
+ DvrManager dvrManager = TvApplication
+ .getSingletons(getActivity()).getDvrManager();
+ dvrManager.removeRecordedProgram(mRecordedProgram);
+ getActivity().finish();
+ }
+ }
+ };
+ }
+
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) { }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) { }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (recordedProgram.getId() == mRecordedProgram.getId()) {
+ getActivity().finish();
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/RecordedProgramPresenter.java b/src/com/android/tv/dvr/ui/RecordedProgramPresenter.java
index 0b656bdc..1bf34310 100644
--- a/src/com/android/tv/dvr/ui/RecordedProgramPresenter.java
+++ b/src/com/android/tv/dvr/ui/RecordedProgramPresenter.java
@@ -17,105 +17,166 @@
package com.android.tv.dvr.ui;
import android.app.Activity;
-import android.app.AlertDialog;
import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.res.Resources;
import android.media.tv.TvContract;
-import android.support.v17.leanback.widget.Presenter;
+import android.media.tv.TvInputManager;
+import android.net.Uri;
+import android.text.Spannable;
+import android.text.SpannableString;
import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
import android.view.View;
import android.view.ViewGroup;
-import java.util.List;
-
-import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TvApplication;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.dvr.RecordedProgram;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
-import com.android.tv.dvr.DvrManager;
-import com.android.tv.ui.DialogUtils;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.DvrWatchedPositionManager.WatchedPositionChangedListener;
import com.android.tv.util.Utils;
+import java.util.concurrent.TimeUnit;
+
/**
* Presents a {@link RecordedProgram} in the {@link DvrBrowseFragment}.
*/
-public class RecordedProgramPresenter extends Presenter {
+public class RecordedProgramPresenter extends DvrItemPresenter {
private final ChannelDataManager mChannelDataManager;
+ private final DvrWatchedPositionManager mDvrWatchedPositionManager;
+ private final Context mContext;
+ private String mTodayString;
+ private String mYesterdayString;
+ private final int mProgressBarColor;
+ private final boolean mShowEpisodeTitle;
- public RecordedProgramPresenter(Context context) {
+ private static final class RecordedProgramViewHolder extends ViewHolder
+ implements WatchedPositionChangedListener {
+ private RecordedProgram mProgram;
+
+ RecordedProgramViewHolder(RecordingCardView view, int progressColor) {
+ super(view);
+ view.setProgressBarColor(progressColor);
+ }
+
+ private void setProgram(RecordedProgram program) {
+ mProgram = program;
+ }
+
+ private void setProgressBar(long watchedPositionMs) {
+ ((RecordingCardView) view).setProgressBar(
+ (watchedPositionMs == TvInputManager.TIME_SHIFT_INVALID_TIME) ? null
+ : Math.min(100, (int) (100.0f * watchedPositionMs
+ / mProgram.getDurationMillis())));
+ }
+
+ @Override
+ public void onWatchedPositionChanged(long programId, long positionMs) {
+ if (programId == mProgram.getId()) {
+ setProgressBar(positionMs);
+ }
+ }
+ }
+
+ public RecordedProgramPresenter(Context context, boolean showEpisodeTitle) {
+ mContext = context;
mChannelDataManager = TvApplication.getSingletons(context).getChannelDataManager();
+ mTodayString = context.getString(R.string.dvr_date_today);
+ mYesterdayString = context.getString(R.string.dvr_date_yesterday);
+ mDvrWatchedPositionManager =
+ TvApplication.getSingletons(context).getDvrWatchedPositionManager();
+ mProgressBarColor = context.getResources()
+ .getColor(R.color.play_controls_progress_bar_watched);
+ mShowEpisodeTitle = showEpisodeTitle;
+ }
+
+ public RecordedProgramPresenter(Context context) {
+ this(context, false);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
- Context context = parent.getContext();
- RecordingCardView view = new RecordingCardView(context);
- return new ViewHolder(view);
+ RecordingCardView view = new RecordingCardView(mContext);
+ return new RecordedProgramViewHolder(view, mProgressBarColor);
}
@Override
public void onBindViewHolder(ViewHolder viewHolder, Object o) {
- final RecordedProgram recording = (RecordedProgram) o;
+ final RecordedProgram program = (RecordedProgram) o;
final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
- final Context context = viewHolder.view.getContext();
- final Resources resources = context.getResources();
-
- Channel channel = mChannelDataManager.getChannel(recording.getChannelId());
-
- if (!TextUtils.isEmpty(recording.getTitle())) {
- cardView.setTitle(recording.getTitle());
- } else {
- cardView.setTitle(resources.getString(R.string.dvr_msg_program_title_unknown));
+ Channel channel = mChannelDataManager.getChannel(program.getChannelId());
+ String titleString = mShowEpisodeTitle ? program.getEpisodeDisplayTitle(mContext)
+ : program.getTitleWithEpisodeNumber(mContext);
+ SpannableString title = titleString == null ? null : new SpannableString(titleString);
+ if (TextUtils.isEmpty(title)) {
+ title = new SpannableString(channel != null ? channel.getDisplayName()
+ : mContext.getResources().getString(R.string.no_program_information));
+ } else if (!mShowEpisodeTitle) {
+ // TODO: Some translation may add delimiters in-between program titles, we should use
+ // a more robust way to get the span range.
+ String programTitle = program.getTitle();
+ title.setSpan(new TextAppearanceSpan(mContext,
+ R.style.text_appearance_card_view_episode_number), programTitle == null ? 0
+ : programTitle.length(), title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
- if (recording.getPosterArt() != null) {
- cardView.setImageUri(recording.getPosterArt());
- } else if (recording.getThumbnail() != null) {
- cardView.setImageUri(recording.getThumbnail());
- } else {
- if (channel != null) {
- cardView.setImageUri(TvContract.buildChannelLogoUri(channel.getId()).toString());
- }
+ cardView.setTitle(title);
+ String imageUri = null;
+ boolean isChannelLogo = false;
+ if (program.getPosterArtUri() != null) {
+ imageUri = program.getPosterArtUri();
+ } else if (program.getThumbnailUri() != null) {
+ imageUri = program.getThumbnailUri();
+ } else if (channel != null) {
+ imageUri = TvContract.buildChannelLogoUri(channel.getId()).toString();
+ isChannelLogo = true;
}
- cardView.setContent(Utils.getDurationString(context, recording.getStartTimeUtcMillis(),
- recording.getEndTimeUtcMillis(), true));
- //TODO: replace with a detail card
- viewHolder.view.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- DialogUtils.showListDialog(v.getContext(),
- new int[] { R.string.dvr_detail_play, R.string.dvr_detail_delete },
- new Runnable[] {
- new Runnable() {
- @Override
- public void run() {
- Intent intent = new Intent(context, MainActivity.class);
- intent.putExtra(Utils.EXTRA_KEY_RECORDING_URI,
- recording.getUri());
- context.startActivity(intent);
- ((Activity) context).finish();
- }
- },
- new Runnable() {
- @Override
- public void run() {
- DvrManager dvrManager = TvApplication
- .getSingletons(context).getDvrManager();
- dvrManager.removeRecordedProgram(recording);
- }
- },
- });
- }
- });
-
+ cardView.setImageUri(imageUri, isChannelLogo);
+ int durationMinutes =
+ Math.max(1, (int) TimeUnit.MILLISECONDS.toMinutes(program.getDurationMillis()));
+ String durationString = getContext().getResources().getQuantityString(
+ R.plurals.dvr_program_duration, durationMinutes, durationMinutes);
+ cardView.setContent(getDescription(program), durationString);
+ if (viewHolder instanceof RecordedProgramViewHolder) {
+ RecordedProgramViewHolder cardViewHolder = (RecordedProgramViewHolder) viewHolder;
+ cardViewHolder.setProgram(program);
+ mDvrWatchedPositionManager.addListener(cardViewHolder, program.getId());
+ cardViewHolder
+ .setProgressBar(mDvrWatchedPositionManager.getWatchedPosition(program.getId()));
+ }
+ super.onBindViewHolder(viewHolder, o);
}
@Override
public void onUnbindViewHolder(ViewHolder viewHolder) {
- final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
- cardView.reset();
+ if (viewHolder instanceof RecordedProgramViewHolder) {
+ mDvrWatchedPositionManager.removeListener((RecordedProgramViewHolder) viewHolder,
+ ((RecordedProgramViewHolder) viewHolder).mProgram.getId());
+ }
+ ((RecordingCardView) viewHolder.view).reset();
+ super.onUnbindViewHolder(viewHolder);
+ }
+
+ /**
+ * Returns description would be used in its card view.
+ */
+ protected String getDescription(RecordedProgram recording) {
+ int dateDifference = Utils.computeDateDifference(recording.getStartTimeUtcMillis(),
+ System.currentTimeMillis());
+ if (dateDifference == 0) {
+ return mTodayString;
+ } else if (dateDifference == 1) {
+ return mYesterdayString;
+ } else {
+ return Utils.getDurationString(mContext, recording.getStartTimeUtcMillis(),
+ recording.getStartTimeUtcMillis(), false, true, false, 0);
+ }
+ }
+
+ /**
+ * Returns context.
+ */
+ protected Context getContext() {
+ return mContext;
}
}
diff --git a/src/com/android/tv/dvr/ui/RecordedProgramsAdapter.java b/src/com/android/tv/dvr/ui/RecordedProgramsAdapter.java
deleted file mode 100644
index eeb26041..00000000
--- a/src/com/android/tv/dvr/ui/RecordedProgramsAdapter.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.dvr.ui;
-
-import android.support.v17.leanback.widget.PresenterSelector;
-
-import com.android.tv.common.recording.RecordedProgram;
-import com.android.tv.dvr.DvrDataManager;
-
-/**
- * Adapter for {@link RecordedProgram}.
- */
-final class RecordedProgramsAdapter extends SortedArrayAdapter<RecordedProgram>
- implements DvrDataManager.RecordedProgramListener {
- private final DvrDataManager mDataManager;
-
- RecordedProgramsAdapter(DvrDataManager dataManager, PresenterSelector presenterSelector) {
- super(presenterSelector, RecordedProgram.START_TIME_THEN_ID_COMPARATOR);
- mDataManager = dataManager;
- }
-
- public void start() {
- clear();
- addAll(mDataManager.getRecordedPrograms());
- mDataManager.addRecordedProgramListener(this);
- }
-
- public void stop() {
- mDataManager.removeRecordedProgramListener(this);
- }
-
- @Override
- long getId(RecordedProgram item) {
- return item.getId();
- }
-
- @Override // DvrDataManager.RecordedProgramListener
- public void onRecordedProgramAdded(RecordedProgram recordedProgram) {
- add(recordedProgram);
- }
-
- @Override // DvrDataManager.RecordedProgramListener
- public void onRecordedProgramChanged(RecordedProgram recordedProgram) {
- change(recordedProgram);
- }
-
- @Override // DvrDataManager.RecordedProgramListener
- public void onRecordedProgramRemoved(RecordedProgram recordedProgram) {
- remove(recordedProgram);
- }
-}
diff --git a/src/com/android/tv/dvr/ui/RecordingCardView.java b/src/com/android/tv/dvr/ui/RecordingCardView.java
index def11248..51c3b03b 100644
--- a/src/com/android/tv/dvr/ui/RecordingCardView.java
+++ b/src/com/android/tv/dvr/ui/RecordingCardView.java
@@ -25,15 +25,19 @@ import android.support.annotation.Nullable;
import android.support.v17.leanback.widget.BaseCardView;
import android.text.TextUtils;
import android.view.LayoutInflater;
+import android.view.View;
import android.widget.ImageView;
+import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.tv.R;
+import com.android.tv.dvr.RecordedProgram;
import com.android.tv.util.ImageLoader;
/**
* A CardView for displaying info about a {@link com.android.tv.dvr.ScheduledRecording} or
- * {@link com.android.tv.common.recording.RecordedProgram}
+ * {@link RecordedProgram} or
+ * {@link com.android.tv.dvr.SeriesRecording}.
*/
class RecordingCardView extends BaseCardView {
private final ImageView mImageView;
@@ -41,36 +45,85 @@ class RecordingCardView extends BaseCardView {
private final int mImageHeight;
private String mImageUri;
private final TextView mTitleView;
- private final TextView mContentView;
+ private final TextView mMajorContentView;
+ private final TextView mMinorContentView;
+ private final ProgressBar mProgressBar;
+ private final View mAffiliatedIconContainer;
+ private final ImageView mAffiliatedIcon;
private final Drawable mDefaultImage;
RecordingCardView(Context context) {
+ this(context,
+ context.getResources().getDimensionPixelSize(R.dimen.dvr_card_image_layout_width),
+ context.getResources().getDimensionPixelSize(R.dimen.dvr_card_image_layout_height));
+ }
+
+ RecordingCardView(Context context, int imageWidth, int imageHeight) {
super(context);
//TODO(dvr): move these to the layout XML.
setCardType(BaseCardView.CARD_TYPE_INFO_UNDER_WITH_EXTRA);
+ setInfoVisibility(BaseCardView.CARD_REGION_VISIBLE_ALWAYS);
setFocusable(true);
setFocusableInTouchMode(true);
- mDefaultImage = getResources().getDrawable(R.drawable.default_now_card, null);
+ mDefaultImage = getResources().getDrawable(R.drawable.dvr_default_poster, null);
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.dvr_recording_card_view, this);
-
mImageView = (ImageView) findViewById(R.id.image);
- mImageWidth = getResources().getDimensionPixelSize(R.dimen.dvr_card_image_layout_width);
- mImageHeight = getResources().getDimensionPixelSize(R.dimen.dvr_card_image_layout_width);
+ mImageWidth = imageWidth;
+ mImageHeight = imageHeight;
+ mProgressBar = (ProgressBar) findViewById(R.id.recording_progress);
+ mAffiliatedIconContainer = findViewById(R.id.affiliated_icon_container);
+ mAffiliatedIcon = (ImageView) findViewById(R.id.affiliated_icon);
mTitleView = (TextView) findViewById(R.id.title);
- mContentView = (TextView) findViewById(R.id.content);
+ mMajorContentView = (TextView) findViewById(R.id.content_major);
+ mMinorContentView = (TextView) findViewById(R.id.content_minor);
}
void setTitle(CharSequence title) {
mTitleView.setText(title);
}
- void setContent(CharSequence content) {
- mContentView.setText(content);
+ void setContent(CharSequence majorContent, CharSequence minorContent) {
+ if (!TextUtils.isEmpty(majorContent)) {
+ mMajorContentView.setText(majorContent);
+ mMajorContentView.setVisibility(View.VISIBLE);
+ } else {
+ mMajorContentView.setVisibility(View.GONE);
+ }
+ if (!TextUtils.isEmpty(minorContent)) {
+ mMinorContentView.setText(minorContent);
+ mMinorContentView.setVisibility(View.VISIBLE);
+ } else {
+ mMinorContentView.setVisibility(View.GONE);
+ }
+ }
+
+ /**
+ * Sets progress bar. If progress is {@code null}, hides progress bar.
+ */
+ void setProgressBar(Integer progress) {
+ if (progress == null) {
+ mProgressBar.setVisibility(View.GONE);
+ } else {
+ mProgressBar.setProgress(progress);
+ mProgressBar.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Sets the color of progress bar.
+ */
+ void setProgressBarColor(int color) {
+ mProgressBar.getProgressDrawable().setTint(color);
}
- void setImageUri(String uri) {
+ void setImageUri(String uri, boolean isChannelLogo) {
+ if (isChannelLogo) {
+ mImageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
+ } else {
+ mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
+ }
mImageUri = uri;
if (TextUtils.isEmpty(uri)) {
mImageView.setImageDrawable(mDefaultImage);
@@ -80,14 +133,31 @@ class RecordingCardView extends BaseCardView {
}
}
- public void setImageUri(Uri uri) {
- if (uri != null) {
- setImageUri(uri.toString());
+ /**
+ * Set image to card view.
+ */
+ public void setImage(Drawable image) {
+ if (image != null) {
+ mImageView.setImageDrawable(image);
+ }
+ }
+
+ public void setAffiliatedIcon(int imageResId) {
+ if (imageResId > 0) {
+ mAffiliatedIconContainer.setVisibility(View.VISIBLE);
+ mAffiliatedIcon.setImageResource(imageResId);
} else {
- setImageUri("");
+ mAffiliatedIconContainer.setVisibility(View.INVISIBLE);
}
}
+ /**
+ * Returns image view.
+ */
+ public ImageView getImageView() {
+ return mImageView;
+ }
+
private static class RecordingCardImageLoaderCallback
extends ImageLoader.ImageLoaderCallback<RecordingCardView> {
private final String mUri;
@@ -108,8 +178,8 @@ class RecordingCardView extends BaseCardView {
}
public void reset() {
- mTitleView.setText("");
- mContentView.setText("");
+ mTitleView.setText(null);
+ setContent(null, null);
mImageView.setImageDrawable(mDefaultImage);
}
}
diff --git a/src/com/android/tv/dvr/ui/RecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/RecordingDetailsFragment.java
new file mode 100644
index 00000000..4e19ec3f
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/RecordingDetailsFragment.java
@@ -0,0 +1,87 @@
+/*
+ * 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.os.Bundle;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.ScheduledRecording;
+
+/**
+ * {@link DetailsFragment} for recordings in DVR.
+ */
+abstract class RecordingDetailsFragment extends DvrDetailsFragment {
+ private ScheduledRecording mRecording;
+
+ @Override
+ protected void onCreateInternal() {
+ setDetailsOverviewRow(createDetailsContent());
+ }
+
+ @Override
+ protected boolean onLoadRecordingDetails(Bundle args) {
+ long scheduledRecordingId = args.getLong(DvrDetailsActivity.RECORDING_ID);
+ mRecording = TvApplication.getSingletons(getContext()).getDvrDataManager()
+ .getScheduledRecording(scheduledRecordingId);
+ return mRecording != null;
+ }
+
+ /**
+ * Returns {@link ScheduledRecording} for the current fragment.
+ */
+ public ScheduledRecording getRecording() {
+ return mRecording;
+ }
+
+ private DetailsContent createDetailsContent() {
+ Channel channel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(mRecording.getChannelId());
+ SpannableString title = mRecording.getProgramTitleWithEpisodeNumber(getContext()) == null ?
+ null : new SpannableString(mRecording
+ .getProgramTitleWithEpisodeNumber(getContext()));
+ if (TextUtils.isEmpty(title)) {
+ title = new SpannableString(channel != null ? channel.getDisplayName()
+ : getContext().getResources().getString(
+ R.string.no_program_information));
+ } else {
+ String programTitle = mRecording.getProgramTitle();
+ title.setSpan(new TextAppearanceSpan(getContext(),
+ R.style.text_appearance_card_view_episode_number), programTitle == null ? 0
+ : programTitle.length(), title.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ String description = !TextUtils.isEmpty(mRecording.getProgramDescription()) ?
+ mRecording.getProgramDescription() : mRecording.getProgramLongDescription();
+ if (TextUtils.isEmpty(description)) {
+ description = channel != null ? channel.getDescription() : null;
+ }
+ return new DetailsContent.Builder()
+ .setTitle(title)
+ .setStartTimeUtcMillis(mRecording.getStartTimeMs())
+ .setEndTimeUtcMillis(mRecording.getEndTimeMs())
+ .setDescription(description)
+ .setImageUris(mRecording.getProgramPosterArtUri(),
+ mRecording.getProgramThumbnailUri(), channel)
+ .build();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/ScheduledRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/ScheduledRecordingDetailsFragment.java
new file mode 100644
index 00000000..60816bb5
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/ScheduledRecordingDetailsFragment.java
@@ -0,0 +1,97 @@
+/*
+ * 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.content.res.Resources;
+import android.os.Bundle;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+
+/**
+ * {@link RecordingDetailsFragment} for scheduled recording in DVR.
+ */
+public class ScheduledRecordingDetailsFragment extends RecordingDetailsFragment {
+ private static final int ACTION_VIEW_SCHEDULE = 1;
+ private static final int ACTION_CANCEL = 2;
+
+ private DvrManager mDvrManager;
+ private Action mScheduleAction;
+ private boolean mHideViewSchedule;
+
+ @Override
+ public void onCreate(Bundle savedInstance) {
+ mDvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ mHideViewSchedule = getArguments().getBoolean(DvrDetailsActivity.HIDE_VIEW_SCHEDULE);
+ super.onCreate(savedInstance);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mScheduleAction != null) {
+ mScheduleAction.setIcon(getResources().getDrawable(getScheduleIconId()));
+ }
+ }
+
+ @Override
+ protected SparseArrayObjectAdapter onCreateActionsAdapter() {
+ SparseArrayObjectAdapter adapter =
+ new SparseArrayObjectAdapter(new ActionPresenterSelector());
+ Resources res = getResources();
+ if (!mHideViewSchedule) {
+ mScheduleAction = new Action(ACTION_VIEW_SCHEDULE,
+ res.getString(R.string.dvr_detail_view_schedule), null,
+ res.getDrawable(getScheduleIconId()));
+ adapter.set(ACTION_VIEW_SCHEDULE, mScheduleAction);
+ }
+ adapter.set(ACTION_CANCEL, new Action(ACTION_CANCEL,
+ res.getString(R.string.epg_dvr_dialog_message_remove_recording_schedule), null,
+ res.getDrawable(R.drawable.ic_dvr_cancel_32dp)));
+ return adapter;
+ }
+
+ @Override
+ protected OnActionClickedListener onCreateOnActionClickedListener() {
+ return new OnActionClickedListener() {
+ @Override
+ public void onActionClicked(Action action) {
+ long actionId = action.getId();
+ if (actionId == ACTION_VIEW_SCHEDULE) {
+ DvrUiHelper.startSchedulesActivity(getContext(), getRecording());
+ } else if (actionId == ACTION_CANCEL) {
+ mDvrManager.removeScheduledRecording(getRecording());
+ getActivity().finish();
+ }
+ }
+ };
+ }
+
+ private int getScheduleIconId() {
+ if (mDvrManager.isConflicting(getRecording())) {
+ return R.drawable.ic_warning_white_32dp;
+ } else {
+ return R.drawable.ic_schedule_32dp;
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/ScheduledRecordingPresenter.java b/src/com/android/tv/dvr/ui/ScheduledRecordingPresenter.java
index 533a4882..5f447f13 100644
--- a/src/com/android/tv/dvr/ui/ScheduledRecordingPresenter.java
+++ b/src/com/android/tv/dvr/ui/ScheduledRecordingPresenter.java
@@ -16,156 +16,162 @@
package com.android.tv.dvr.ui;
-import android.app.AlertDialog;
+import android.app.Activity;
import android.content.Context;
-import android.content.DialogInterface;
import android.media.tv.TvContract;
-import android.support.annotation.Nullable;
-import android.support.v17.leanback.widget.Presenter;
-import android.view.View;
+import android.os.Handler;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.TextUtils;
+import android.text.style.TextAppearanceSpan;
import android.view.ViewGroup;
-import android.widget.Toast;
import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
import com.android.tv.TvApplication;
import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
-import com.android.tv.data.Program;
-import com.android.tv.data.ProgramDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.ScheduledRecording;
import com.android.tv.util.Utils;
+import java.util.concurrent.TimeUnit;
+
/**
* Presents a {@link ScheduledRecording} in the {@link DvrBrowseFragment}.
*/
-public class ScheduledRecordingPresenter extends Presenter {
+public class ScheduledRecordingPresenter extends DvrItemPresenter {
+ private static final long PROGRESS_UPDATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(5);
+
private final ChannelDataManager mChannelDataManager;
+ private final DvrManager mDvrManager;
+ private final Context mContext;
+ private final int mProgressBarColor;
private static final class ScheduledRecordingViewHolder extends ViewHolder {
- private ProgramDataManager.QueryProgramTask mQueryProgramTask;
+ private final Handler mHandler = new Handler();
+ private ScheduledRecording mScheduledRecording;
+ private final Runnable mProgressBarUpdater = new Runnable() {
+ @Override
+ public void run() {
+ updateProgressBar();
+ mHandler.postDelayed(this, PROGRESS_UPDATE_INTERVAL_MS);
+ }
+ };
- ScheduledRecordingViewHolder(RecordingCardView view) {
+ ScheduledRecordingViewHolder(RecordingCardView view, int progressBarColor) {
super(view);
+ view.setProgressBarColor(progressBarColor);
+ }
+
+ private void updateProgressBar() {
+ if (mScheduledRecording == null) {
+ return;
+ }
+ int recordingState = mScheduledRecording.getState();
+ RecordingCardView cardView = (RecordingCardView) view;
+ if (recordingState == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
+ cardView.setProgressBar(Math.max(0, Math.min((int) (100 *
+ (System.currentTimeMillis() - mScheduledRecording.getStartTimeMs())
+ / mScheduledRecording.getDuration()), 100)));
+ } else if (recordingState == ScheduledRecording.STATE_RECORDING_FINISHED) {
+ cardView.setProgressBar(100);
+ } else {
+ // Hides progress bar.
+ cardView.setProgressBar(null);
+ }
+ }
+
+ private void startUpdateProgressBar() {
+ mHandler.post(mProgressBarUpdater);
+ }
+
+ private void stopUpdateProgressBar() {
+ mHandler.removeCallbacks(mProgressBarUpdater);
}
}
public ScheduledRecordingPresenter(Context context) {
ApplicationSingletons singletons = TvApplication.getSingletons(context);
mChannelDataManager = singletons.getChannelDataManager();
+ mDvrManager = singletons.getDvrManager();
+ mContext = context;
+ mProgressBarColor = context.getResources()
+ .getColor(R.color.play_controls_recording_icon_color_on_focus);
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent) {
Context context = parent.getContext();
RecordingCardView view = new RecordingCardView(context);
- return new ScheduledRecordingViewHolder(view);
+ return new ScheduledRecordingViewHolder(view, mProgressBarColor);
}
@Override
public void onBindViewHolder(ViewHolder baseHolder, Object o) {
- ScheduledRecordingViewHolder viewHolder = (ScheduledRecordingViewHolder) baseHolder;
+ final ScheduledRecordingViewHolder viewHolder = (ScheduledRecordingViewHolder) baseHolder;
final ScheduledRecording recording = (ScheduledRecording) o;
final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
final Context context = viewHolder.view.getContext();
- long programId = recording.getProgramId();
- if (programId == ScheduledRecording.ID_NOT_SET) {
- setTitleAndImage(cardView, recording, null);
+ setTitleAndImage(cardView, recording);
+ int dateDifference = Utils.computeDateDifference(System.currentTimeMillis(),
+ recording.getStartTimeMs());
+ if (dateDifference <= 0) {
+ cardView.setContent(mContext.getString(R.string.dvr_date_today_time,
+ Utils.getDurationString(context, recording.getStartTimeMs(),
+ recording.getEndTimeMs(), false, false, true, 0)), null);
+ } else if (dateDifference == 1) {
+ cardView.setContent(mContext.getString(R.string.dvr_date_tomorrow_time,
+ Utils.getDurationString(context, recording.getStartTimeMs(),
+ recording.getEndTimeMs(), false, false, true, 0)), null);
} else {
- viewHolder.mQueryProgramTask = new ProgramDataManager.QueryProgramTask(
- context.getContentResolver(), programId) {
- @Override
- protected void onPostExecute(Program program) {
- super.onPostExecute(program);
- setTitleAndImage(cardView, recording, program);
- }
- };
- viewHolder.mQueryProgramTask.executeOnDbThread();
-
+ cardView.setContent(Utils.getDurationString(context, recording.getStartTimeMs(),
+ recording.getStartTimeMs(), false, true, false, 0), null);
}
- cardView.setContent(Utils.getDurationString(context, recording.getStartTimeMs(),
- recording.getEndTimeMs(), true));
- //TODO: replace with a detail card
- View.OnClickListener clickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- switch (recording.getState()) {
- case ScheduledRecording.STATE_RECORDING_NOT_STARTED: {
- showScheduledRecordingDialog(v.getContext(), recording);
- break;
- }
- case ScheduledRecording.STATE_RECORDING_IN_PROGRESS: {
- showCurrentlyRecordingDialog(v.getContext(), recording);
- break;
- }
- }
- }
- };
- baseHolder.view.setOnClickListener(clickListener);
- }
-
- private void setTitleAndImage(RecordingCardView cardView, ScheduledRecording recording,
- @Nullable Program program) {
- if (program != null) {
- cardView.setTitle(program.getTitle());
- cardView.setImageUri(program.getPosterArtUri());
+ if (mDvrManager.isConflicting(recording)) {
+ cardView.setAffiliatedIcon(R.drawable.ic_warning_white_32dp);
} else {
- cardView.setTitle(
- cardView.getResources().getString(R.string.dvr_msg_program_title_unknown));
- Channel channel = mChannelDataManager.getChannel(recording.getChannelId());
- if (channel != null) {
- cardView.setImageUri(TvContract.buildChannelLogoUri(channel.getId()).toString());
- }
+ cardView.setAffiliatedIcon(0);
}
+ viewHolder.updateProgressBar();
+ viewHolder.mScheduledRecording = recording;
+ viewHolder.startUpdateProgressBar();
+ super.onBindViewHolder(viewHolder, o);
}
@Override
public void onUnbindViewHolder(ViewHolder baseHolder) {
ScheduledRecordingViewHolder viewHolder = (ScheduledRecordingViewHolder) baseHolder;
+ viewHolder.stopUpdateProgressBar();
final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
- if (viewHolder.mQueryProgramTask != null) {
- viewHolder.mQueryProgramTask.cancel(true);
- viewHolder.mQueryProgramTask = null;
- }
+ viewHolder.mScheduledRecording = null;
cardView.reset();
+ super.onUnbindViewHolder(viewHolder);
}
- private void showScheduledRecordingDialog(final Context context,
- final ScheduledRecording recording) {
- DialogInterface.OnClickListener removeScheduleListener
- = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- // TODO(DVR) handle success/failure.
- DvrManager dvrManager = TvApplication.getSingletons(context)
- .getDvrManager();
- dvrManager.removeScheduledRecording((ScheduledRecording) recording);
- }
- };
- new AlertDialog.Builder(context)
- .setMessage(R.string.epg_dvr_dialog_message_remove_recording_schedule)
- .setNegativeButton(android.R.string.no, null)
- .setPositiveButton(android.R.string.yes, removeScheduleListener)
- .show();
- }
-
- private void showCurrentlyRecordingDialog(final Context context,
- final ScheduledRecording recording) {
- DialogInterface.OnClickListener stopRecordingListener
- = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- DvrManager dvrManager = TvApplication.getSingletons(context)
- .getDvrManager();
- dvrManager.stopRecording((ScheduledRecording) recording);
- }
- };
- new AlertDialog.Builder(context)
- .setMessage(R.string.epg_dvr_dialog_message_stop_recording)
- .setNegativeButton(android.R.string.no, null)
- .setPositiveButton(android.R.string.yes, stopRecordingListener)
- .show();
+ private void setTitleAndImage(RecordingCardView cardView, ScheduledRecording recording) {
+ Channel channel = mChannelDataManager.getChannel(recording.getChannelId());
+ SpannableString title = recording.getProgramTitleWithEpisodeNumber(mContext) == null ?
+ null : new SpannableString(recording.getProgramTitleWithEpisodeNumber(mContext));
+ if (TextUtils.isEmpty(title)) {
+ title = new SpannableString(channel != null ? channel.getDisplayName()
+ : mContext.getResources().getString(R.string.no_program_information));
+ } else {
+ String programTitle = recording.getProgramTitle();
+ title.setSpan(new TextAppearanceSpan(mContext,
+ R.style.text_appearance_card_view_episode_number),
+ programTitle == null ? 0 : programTitle.length(), title.length(),
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ String imageUri = recording.getProgramPosterArtUri();
+ boolean isChannelLogo = false;
+ if (TextUtils.isEmpty(imageUri)) {
+ imageUri = channel != null ?
+ TvContract.buildChannelLogoUri(channel.getId()).toString() : null;
+ isChannelLogo = true;
+ }
+ cardView.setTitle(title);
+ cardView.setImageUri(imageUri, isChannelLogo);
}
}
diff --git a/src/com/android/tv/dvr/ui/ScheduledRecordingsAdapter.java b/src/com/android/tv/dvr/ui/ScheduledRecordingsAdapter.java
deleted file mode 100644
index 65955276..00000000
--- a/src/com/android/tv/dvr/ui/ScheduledRecordingsAdapter.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.dvr.ui;
-
-import android.support.v17.leanback.widget.PresenterSelector;
-
-import com.android.tv.dvr.DvrDataManager;
-import com.android.tv.dvr.ScheduledRecording;
-
-/**
- * Adapter for {@link ScheduledRecording} filtered by
- * {@link com.android.tv.dvr.ScheduledRecording.RecordingState}.
- */
-final class ScheduledRecordingsAdapter extends SortedArrayAdapter<ScheduledRecording>
- implements DvrDataManager.ScheduledRecordingListener {
- private final int mState;
- private final DvrDataManager mDataManager;
-
- ScheduledRecordingsAdapter(DvrDataManager dataManager, int state,
- PresenterSelector presenterSelector) {
- super(presenterSelector, ScheduledRecording.START_TIME_THEN_PRIORITY_COMPARATOR);
- mDataManager = dataManager;
- mState = state;
- }
-
- public void start() {
- clear();
- switch (mState) {
- case ScheduledRecording.STATE_RECORDING_NOT_STARTED:
- addAll(mDataManager.getNonStartedScheduledRecordings());
- break;
- case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
- addAll(mDataManager.getStartedRecordings());
- break;
- default:
- throw new IllegalStateException("Unknown recording state " + mState);
-
- }
- mDataManager.addScheduledRecordingListener(this);
- }
-
- public void stop() {
- mDataManager.removeScheduledRecordingListener(this);
- }
-
- @Override
- long getId(ScheduledRecording item) {
- return item.getId();
- }
-
- @Override //DvrDataManager.ScheduledRecordingListener
- public void onScheduledRecordingAdded(ScheduledRecording scheduledRecording) {
- if (scheduledRecording.getState() == mState) {
- add(scheduledRecording);
- }
- }
-
- @Override //DvrDataManager.ScheduledRecordingListener
- public void onScheduledRecordingRemoved(ScheduledRecording scheduledRecording) {
- remove(scheduledRecording);
- }
-
- @Override //DvrDataManager.ScheduledRecordingListener
- public void onScheduledRecordingStatusChanged(ScheduledRecording scheduledRecording) {
- if (scheduledRecording.getState() == mState) {
- change(scheduledRecording);
- } else {
- remove(scheduledRecording);
- }
- }
-}
diff --git a/src/com/android/tv/dvr/ui/SeriesDeletionFragment.java b/src/com/android/tv/dvr/ui/SeriesDeletionFragment.java
new file mode 100644
index 00000000..36e3cfc1
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/SeriesDeletionFragment.java
@@ -0,0 +1,252 @@
+/*
+ * 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.content.Context;
+import android.media.tv.TvInputManager;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.text.TextUtils;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.ui.GuidedActionsStylistWithDivider;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Fragment for DVR series recording settings.
+ */
+public class SeriesDeletionFragment extends GuidedStepFragment {
+ private static final long WATCHED_TIME_UNIT_THRESHOLD = TimeUnit.MINUTES.toMillis(2);
+
+ // Since recordings' IDs are used as its check actions' IDs, which are random positive numbers,
+ // negative values are used by other actions to prevent duplicated IDs.
+ private static final long ACTION_ID_SELECT_WATCHED = -110;
+ private static final long ACTION_ID_SELECT_ALL = -111;
+ private static final long ACTION_ID_DELETE = -112;
+
+ private DvrDataManager mDvrDataManager;
+ private DvrWatchedPositionManager mDvrWatchedPositionManager;
+ private List<RecordedProgram> mRecordings;
+ private final Set<Long> mWatchedRecordings = new HashSet<>();
+ private boolean mAllSelected;
+ private long mSeriesRecordingId;
+ private int mOneLineActionHeight;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mSeriesRecordingId = getArguments()
+ .getLong(DvrSeriesDeletionActivity.SERIES_RECORDING_ID, -1);
+ SoftPreconditions.checkArgument(mSeriesRecordingId != -1);
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mDvrWatchedPositionManager =
+ TvApplication.getSingletons(context).getDvrWatchedPositionManager();
+ mRecordings = mDvrDataManager.getRecordedPrograms(mSeriesRecordingId);
+ mOneLineActionHeight = getResources().getDimensionPixelSize(
+ R.dimen.dvr_settings_one_line_action_container_height);
+ if (mRecordings.isEmpty()) {
+ Toast.makeText(getActivity(), getString(R.string.dvr_series_deletion_no_recordings),
+ Toast.LENGTH_LONG).show();
+ finishGuidedStepFragments();
+ return;
+ }
+ Collections.sort(mRecordings, RecordedProgram.EPISODE_COMPARATOR);
+ }
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String breadcrumb = null;
+ SeriesRecording series = mDvrDataManager.getSeriesRecording(mSeriesRecordingId);
+ if (series != null) {
+ breadcrumb = series.getTitle();
+ }
+ return new Guidance(getString(R.string.dvr_series_deletion_title),
+ getString(R.string.dvr_series_deletion_description), breadcrumb, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_SELECT_WATCHED)
+ .title(getString(R.string.dvr_series_select_watched))
+ .build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_SELECT_ALL)
+ .title(getString(R.string.dvr_series_select_all))
+ .build());
+ actions.add(GuidedActionsStylistWithDivider.createDividerAction(getContext()));
+ for (RecordedProgram recording : mRecordings) {
+ long watchedPositionMs =
+ mDvrWatchedPositionManager.getWatchedPosition(recording.getId());
+ String title = recording.getEpisodeDisplayTitle(getContext());
+ if (TextUtils.isEmpty(title)) {
+ title = TextUtils.isEmpty(recording.getTitle()) ?
+ getString(R.string.channel_banner_no_title) : recording.getTitle();
+ }
+ String description;
+ if (watchedPositionMs != TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ description = getWatchedString(watchedPositionMs, recording.getDurationMillis());
+ mWatchedRecordings.add(recording.getId());
+ } else {
+ description = getString(R.string.dvr_series_never_watched);
+ }
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(recording.getId())
+ .title(title)
+ .description(description)
+ .checkSetId(GuidedAction.CHECKBOX_CHECK_SET_ID)
+ .build());
+ }
+ }
+
+ @Override
+ public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_DELETE)
+ .title(getString(R.string.dvr_detail_delete))
+ .build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .clickAction(GuidedAction.ACTION_ID_CANCEL)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ long actionId = action.getId();
+ if (actionId == ACTION_ID_DELETE) {
+ List<Long> idsToDelete = new ArrayList<>();
+ for (GuidedAction guidedAction : getActions()) {
+ if (guidedAction.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID
+ && guidedAction.isChecked()) {
+ idsToDelete.add(guidedAction.getId());
+ }
+ }
+ if (!idsToDelete.isEmpty()) {
+ DvrManager dvrManager = TvApplication.getSingletons(getActivity()).getDvrManager();
+ dvrManager.removeRecordedPrograms(idsToDelete);
+ }
+ Toast.makeText(getContext(), getResources().getQuantityString(
+ R.plurals.dvr_msg_episodes_deleted, idsToDelete.size(), idsToDelete.size(),
+ mRecordings.size()), Toast.LENGTH_LONG).show();
+ finishGuidedStepFragments();
+ } else if (actionId == GuidedAction.ACTION_ID_CANCEL) {
+ finishGuidedStepFragments();
+ } else if (actionId == ACTION_ID_SELECT_WATCHED) {
+ for (GuidedAction guidedAction : getActions()) {
+ if (guidedAction.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ long recordingId = guidedAction.getId();
+ if (mWatchedRecordings.contains(recordingId)) {
+ guidedAction.setChecked(true);
+ } else {
+ guidedAction.setChecked(false);
+ }
+ notifyActionChanged(findActionPositionById(recordingId));
+ }
+ }
+ mAllSelected = updateSelectAllState();
+ } else if (actionId == ACTION_ID_SELECT_ALL) {
+ mAllSelected = !mAllSelected;
+ for (GuidedAction guidedAction : getActions()) {
+ if (guidedAction.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ guidedAction.setChecked(mAllSelected);
+ notifyActionChanged(findActionPositionById(guidedAction.getId()));
+ }
+ }
+ updateSelectAllState(action, mAllSelected);
+ } else {
+ mAllSelected = updateSelectAllState();
+ }
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateButtonActionsStylist() {
+ return new DvrGuidedActionsStylist(true);
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateActionsStylist() {
+ return new GuidedActionsStylistWithDivider() {
+ @Override
+ public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
+ super.onBindViewHolder(vh, action);
+ if (action.getId() == ACTION_DIVIDER) {
+ return;
+ }
+ LayoutParams lp = vh.itemView.getLayoutParams();
+ if (action.getCheckSetId() != GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ lp.height = mOneLineActionHeight;
+ } else {
+ vh.itemView.setLayoutParams(
+ new LayoutParams(lp.width, LayoutParams.WRAP_CONTENT));
+ }
+ }
+ };
+ }
+
+ private String getWatchedString(long watchedPositionMs, long durationMs) {
+ if (durationMs > WATCHED_TIME_UNIT_THRESHOLD) {
+ return getResources().getString(R.string.dvr_series_watched_info_minutes,
+ Math.max(1, TimeUnit.MILLISECONDS.toMinutes(watchedPositionMs)),
+ TimeUnit.MILLISECONDS.toMinutes(durationMs));
+ } else {
+ return getResources().getString(R.string.dvr_series_watched_info_seconds,
+ Math.max(1, TimeUnit.MILLISECONDS.toSeconds(watchedPositionMs)),
+ TimeUnit.MILLISECONDS.toSeconds(durationMs));
+ }
+ }
+
+ private boolean updateSelectAllState() {
+ for (GuidedAction guidedAction : getActions()) {
+ if (guidedAction.getCheckSetId() == GuidedAction.CHECKBOX_CHECK_SET_ID) {
+ if (!guidedAction.isChecked()) {
+ if (mAllSelected) {
+ updateSelectAllState(findActionById(ACTION_ID_SELECT_ALL), false);
+ }
+ return false;
+ }
+ }
+ }
+ if (!mAllSelected) {
+ updateSelectAllState(findActionById(ACTION_ID_SELECT_ALL), true);
+ }
+ return true;
+ }
+
+ private void updateSelectAllState(GuidedAction selectAll, boolean select) {
+ selectAll.setTitle(select ? getString(R.string.dvr_series_deselect_all)
+ : getString(R.string.dvr_series_select_all));
+ notifyActionChanged(findActionPositionById(ACTION_ID_SELECT_ALL));
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/SeriesRecordingDetailsFragment.java b/src/com/android/tv/dvr/ui/SeriesRecordingDetailsFragment.java
new file mode 100644
index 00000000..e9e391d4
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/SeriesRecordingDetailsFragment.java
@@ -0,0 +1,375 @@
+/*
+ * 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.content.res.Resources;
+import android.graphics.drawable.Drawable;
+import android.media.tv.TvInputManager;
+import android.os.Bundle;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.support.v17.leanback.widget.Action;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.support.v17.leanback.widget.DetailsOverviewRow;
+import android.support.v17.leanback.widget.DetailsOverviewRowPresenter;
+import android.support.v17.leanback.widget.HeaderItem;
+import android.support.v17.leanback.widget.ListRow;
+import android.support.v17.leanback.widget.ListRowPresenter;
+import android.support.v17.leanback.widget.OnActionClickedListener;
+import android.support.v17.leanback.widget.PresenterSelector;
+import android.support.v17.leanback.widget.SparseArrayObjectAdapter;
+import android.text.TextUtils;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.BaseProgram;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * {@link DetailsFragment} for series recording in DVR.
+ */
+public class SeriesRecordingDetailsFragment extends DvrDetailsFragment implements
+ DvrDataManager.SeriesRecordingListener, DvrDataManager.RecordedProgramListener {
+ private static final int ACTION_WATCH = 1;
+ private static final int ACTION_SERIES_SCHEDULES = 2;
+ private static final int ACTION_DELETE = 3;
+
+ private DvrWatchedPositionManager mDvrWatchedPositionManager;
+ private DvrDataManager mDvrDataManager;
+
+ private SeriesRecording mSeries;
+ // NOTICE: mRecordedPrograms should only be used in creating details fragments.
+ // After fragments are created, it should be cleared to save resources.
+ private List<RecordedProgram> mRecordedPrograms;
+ private RecordedProgram mRecommendRecordedProgram;
+ private DetailsContent mDetailsContent;
+ private int mSeasonRowCount;
+ private SparseArrayObjectAdapter mActionsAdapter;
+ private Action mDeleteAction;
+
+ private boolean mPaused;
+ private long mInitialPlaybackPositionMs;
+ private String mWatchLabel;
+ private String mResumeLabel;
+ private Drawable mWatchDrawable;
+ private RecordedProgramPresenter mRecordedProgramPresenter;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ 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);
+ mRecordedProgramPresenter = new RecordedProgramPresenter(getContext(), true);
+ super.onCreate(savedInstanceState);
+ }
+
+ @Override
+ protected void onCreateInternal() {
+ mDvrWatchedPositionManager = TvApplication.getSingletons(getActivity())
+ .getDvrWatchedPositionManager();
+ setDetailsOverviewRow(mDetailsContent);
+ setupRecordedProgramsRow();
+ mDvrDataManager.addSeriesRecordingListener(this);
+ mDvrDataManager.addRecordedProgramListener(this);
+ mRecordedPrograms = null;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mPaused) {
+ updateWatchAction();
+ mPaused = false;
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mPaused = true;
+ }
+
+ private void updateWatchAction() {
+ List<RecordedProgram> programs = mDvrDataManager.getRecordedPrograms(mSeries.getId());
+ Collections.sort(programs, RecordedProgram.EPISODE_COMPARATOR);
+ mRecommendRecordedProgram = getRecommendProgram(programs);
+ if (mRecommendRecordedProgram == null) {
+ mActionsAdapter.clear(ACTION_WATCH);
+ } else {
+ String episodeStatus;
+ if(mDvrWatchedPositionManager.getWatchedStatus(mRecommendRecordedProgram)
+ == DvrWatchedPositionManager.DVR_WATCHED_STATUS_WATCHING) {
+ episodeStatus = mResumeLabel;
+ mInitialPlaybackPositionMs = mDvrWatchedPositionManager
+ .getWatchedPosition(mRecommendRecordedProgram.getId());
+ } else {
+ episodeStatus = mWatchLabel;
+ mInitialPlaybackPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+ }
+ String episodeDisplayNumber = mRecommendRecordedProgram.getEpisodeDisplayNumber(
+ getContext());
+ mActionsAdapter.set(ACTION_WATCH, new Action(ACTION_WATCH,
+ episodeStatus, episodeDisplayNumber, mWatchDrawable));
+ }
+ }
+
+ @Override
+ protected boolean onLoadRecordingDetails(Bundle args) {
+ long recordId = args.getLong(DvrDetailsActivity.RECORDING_ID);
+ mSeries = TvApplication.getSingletons(getActivity()).getDvrDataManager()
+ .getSeriesRecording(recordId);
+ if (mSeries == null) {
+ return false;
+ }
+ mRecordedPrograms = mDvrDataManager.getRecordedPrograms(mSeries.getId());
+ Collections.sort(mRecordedPrograms, RecordedProgram.SEASON_REVERSED_EPISODE_COMPARATOR);
+ mDetailsContent = createDetailsContent();
+ return true;
+ }
+
+ @Override
+ protected PresenterSelector onCreatePresenterSelector(
+ DetailsOverviewRowPresenter rowPresenter) {
+ ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
+ presenterSelector.addClassPresenter(DetailsOverviewRow.class, rowPresenter);
+ presenterSelector.addClassPresenter(ListRow.class, new ListRowPresenter());
+ return presenterSelector;
+ }
+
+ private DetailsContent createDetailsContent() {
+ Channel channel = TvApplication.getSingletons(getContext()).getChannelDataManager()
+ .getChannel(mSeries.getChannelId());
+ String description = TextUtils.isEmpty(mSeries.getLongDescription())
+ ? mSeries.getDescription() : mSeries.getLongDescription();
+ return new DetailsContent.Builder()
+ .setTitle(mSeries.getTitle())
+ .setDescription(description)
+ .setImageUris(mSeries.getPosterUri(), mSeries.getPhotoUri(), channel)
+ .build();
+ }
+
+ @Override
+ protected SparseArrayObjectAdapter onCreateActionsAdapter() {
+ mActionsAdapter = new SparseArrayObjectAdapter(new ActionPresenterSelector());
+ Resources res = getResources();
+ updateWatchAction();
+ mActionsAdapter.set(ACTION_SERIES_SCHEDULES, new Action(ACTION_SERIES_SCHEDULES,
+ getString(R.string.dvr_detail_view_schedule), null,
+ res.getDrawable(R.drawable.ic_schedule_32dp, null)));
+ mDeleteAction = new Action(ACTION_DELETE,
+ getString(R.string.dvr_detail_series_delete), null,
+ res.getDrawable(R.drawable.ic_delete_32dp, null));
+ if (!mRecordedPrograms.isEmpty()) {
+ mActionsAdapter.set(ACTION_DELETE, mDeleteAction);
+ }
+ return mActionsAdapter;
+ }
+
+ private void setupRecordedProgramsRow() {
+ for (RecordedProgram program : mRecordedPrograms) {
+ addProgram(program);
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mDvrDataManager.removeSeriesRecordingListener(this);
+ mDvrDataManager.removeRecordedProgramListener(this);
+ if (mSeries != null) {
+ DvrManager dvrManager = TvApplication.getSingletons(getActivity()).getDvrManager();
+ if (dvrManager.canRemoveSeriesRecording(mSeries.getId())) {
+ dvrManager.removeSeriesRecording(mSeries.getId());
+ }
+ }
+ mRecordedProgramPresenter.unbindAllViewHolders();
+ }
+
+ @Override
+ protected OnActionClickedListener onCreateOnActionClickedListener() {
+ return new OnActionClickedListener() {
+ @Override
+ public void onActionClicked(Action action) {
+ if (action.getId() == ACTION_WATCH) {
+ startPlayback(mRecommendRecordedProgram, mInitialPlaybackPositionMs);
+ } else if (action.getId() == ACTION_SERIES_SCHEDULES) {
+ DvrUiHelper.startSchedulesActivityForSeries(getContext(), mSeries);
+ } else if (action.getId() == ACTION_DELETE) {
+ DvrUiHelper.startSeriesDeletionActivity(getContext(), mSeries.getId());
+ }
+ }
+ };
+ }
+
+ /**
+ * The programs are sorted by season number and episode number.
+ */
+ private RecordedProgram getRecommendProgram(List<RecordedProgram> programs) {
+ for (int i = programs.size() - 1 ; i >= 0 ; i--) {
+ RecordedProgram program = programs.get(i);
+ int watchedStatus = mDvrWatchedPositionManager.getWatchedStatus(program);
+ if (watchedStatus == DvrWatchedPositionManager.DVR_WATCHED_STATUS_NEW) {
+ continue;
+ }
+ if (watchedStatus == DvrWatchedPositionManager.DVR_WATCHED_STATUS_WATCHING) {
+ return program;
+ }
+ if (i == programs.size() - 1) {
+ return program;
+ } else {
+ return programs.get(i + 1);
+ }
+ }
+ return programs.isEmpty() ? null : programs.get(0);
+ }
+
+ @Override
+ public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) { }
+
+ @Override
+ public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording series : seriesRecordings) {
+ if (mSeries.getId() == series.getId()) {
+ mSeries = series;
+ }
+ }
+ }
+
+ @Override
+ public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording series : seriesRecordings) {
+ if (series.getId() == mSeries.getId()) {
+ mSeries = null;
+ getActivity().finish();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (TextUtils.equals(recordedProgram.getSeriesId(), mSeries.getSeriesId())) {
+ addProgram(recordedProgram);
+ if (mActionsAdapter.lookup(ACTION_DELETE) == null) {
+ mActionsAdapter.set(ACTION_DELETE, mDeleteAction);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
+ // Do nothing
+ }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (TextUtils.equals(recordedProgram.getSeriesId(), mSeries.getSeriesId())) {
+ ListRow row = getSeasonRow(recordedProgram.getSeasonNumber(), false);
+ if (row != null) {
+ SeasonRowAdapter adapter = (SeasonRowAdapter) row.getAdapter();
+ adapter.remove(recordedProgram);
+ if (adapter.isEmpty()) {
+ getRowsAdapter().remove(row);
+ if (getRowsAdapter().size() == 1) {
+ // No season rows left. Only DetailsOverviewRow
+ mActionsAdapter.clear(ACTION_DELETE);
+ }
+ }
+ }
+ if (recordedProgram.getId() == mRecommendRecordedProgram.getId()) {
+ updateWatchAction();
+ }
+ }
+ }
+ }
+
+ private void addProgram(RecordedProgram program) {
+ String programSeasonNumber =
+ TextUtils.isEmpty(program.getSeasonNumber()) ? "" : program.getSeasonNumber();
+ getOrCreateSeasonRowAdapter(programSeasonNumber).add(program);
+ }
+
+ private SeasonRowAdapter getOrCreateSeasonRowAdapter(String seasonNumber) {
+ ListRow row = getSeasonRow(seasonNumber, true);
+ return (SeasonRowAdapter) row.getAdapter();
+ }
+
+ private ListRow getSeasonRow(String seasonNumber, boolean createNewRow) {
+ seasonNumber = TextUtils.isEmpty(seasonNumber) ? "" : seasonNumber;
+ ArrayObjectAdapter rowsAdaptor = getRowsAdapter();
+ for (int i = rowsAdaptor.size() - 1; i >= 0; i--) {
+ Object row = rowsAdaptor.get(i);
+ if (row instanceof ListRow) {
+ int compareResult = BaseProgram.numberCompare(seasonNumber,
+ ((SeasonRowAdapter) ((ListRow) row).getAdapter()).mSeasonNumber);
+ if (compareResult == 0) {
+ return (ListRow) row;
+ } else if (compareResult < 0) {
+ return createNewRow ? createNewSeasonRow(seasonNumber, i + 1) : null;
+ }
+ }
+ }
+ return createNewRow ? createNewSeasonRow(seasonNumber, rowsAdaptor.size()) : null;
+ }
+
+ private ListRow createNewSeasonRow(String seasonNumber, int position) {
+ String seasonTitle = seasonNumber.isEmpty() ? mSeries.getTitle()
+ : getString(R.string.dvr_detail_series_season_title, seasonNumber);
+ HeaderItem header = new HeaderItem(mSeasonRowCount++, seasonTitle);
+ ClassPresenterSelector selector = new ClassPresenterSelector();
+ selector.addClassPresenter(RecordedProgram.class, mRecordedProgramPresenter);
+ ListRow row = new ListRow(header, new SeasonRowAdapter(selector,
+ new Comparator<RecordedProgram>() {
+ @Override
+ public int compare(RecordedProgram lhs, RecordedProgram rhs) {
+ return BaseProgram.EPISODE_COMPARATOR.compare(lhs, rhs);
+ }
+ }, seasonNumber));
+ getRowsAdapter().add(position, row);
+ return row;
+ }
+
+ private class SeasonRowAdapter extends SortedArrayAdapter<RecordedProgram> {
+ private String mSeasonNumber;
+
+ SeasonRowAdapter(PresenterSelector selector, Comparator<RecordedProgram> comparator,
+ String seasonNumber) {
+ super(selector, comparator);
+ mSeasonNumber = seasonNumber;
+ }
+
+ @Override
+ public long getId(RecordedProgram program) {
+ return program.getId();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/SeriesRecordingPresenter.java b/src/com/android/tv/dvr/ui/SeriesRecordingPresenter.java
new file mode 100644
index 00000000..c2c0f596
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/SeriesRecordingPresenter.java
@@ -0,0 +1,234 @@
+/*
+ * 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.app.Activity;
+import android.content.Context;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputManager;
+import android.text.TextUtils;
+import android.view.ViewGroup;
+
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrWatchedPositionManager;
+import com.android.tv.dvr.DvrWatchedPositionManager.WatchedPositionChangedListener;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+
+import java.util.List;
+
+/**
+ * Presents a {@link SeriesRecording} in {@link DvrBrowseFragment}.
+ */
+public class SeriesRecordingPresenter extends DvrItemPresenter {
+ private final ChannelDataManager mChannelDataManager;
+ private final DvrDataManager mDvrDataManager;
+ private final DvrManager mDvrManager;
+ private final DvrWatchedPositionManager mWatchedPositionManager;
+
+ private static final class SeriesRecordingViewHolder extends ViewHolder implements
+ WatchedPositionChangedListener, ScheduledRecordingListener, RecordedProgramListener {
+ private SeriesRecording mSeriesRecording;
+ private RecordingCardView mCardView;
+ private DvrDataManager mDvrDataManager;
+ private DvrManager mDvrManager;
+ private DvrWatchedPositionManager mWatchedPositionManager;
+
+ SeriesRecordingViewHolder(RecordingCardView view, DvrDataManager dvrDataManager,
+ DvrManager dvrManager, DvrWatchedPositionManager watchedPositionManager) {
+ super(view);
+ mCardView = view;
+ mDvrDataManager = dvrDataManager;
+ mDvrManager = dvrManager;
+ mWatchedPositionManager = watchedPositionManager;
+ }
+
+ @Override
+ public void onWatchedPositionChanged(long recordedProgramId, long positionMs) {
+ if (positionMs != TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ mWatchedPositionManager.removeListener(this, recordedProgramId);
+ updateCardViewContent();
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording scheduledRecording : scheduledRecordings) {
+ if (scheduledRecording.getSeriesRecordingId() == mSeriesRecording.getId()) {
+ updateCardViewContent();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording scheduledRecording : scheduledRecordings) {
+ if (scheduledRecording.getSeriesRecordingId() == mSeriesRecording.getId()) {
+ updateCardViewContent();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsAdded(RecordedProgram... recordedPrograms) {
+ boolean needToUpdateCardView = false;
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (TextUtils.equals(recordedProgram.getSeriesId(),
+ mSeriesRecording.getSeriesId())) {
+ mDvrDataManager.removeScheduledRecordingListener(this);
+ mWatchedPositionManager.addListener(this, recordedProgram.getId());
+ needToUpdateCardView = true;
+ }
+ }
+ if (needToUpdateCardView) {
+ updateCardViewContent();
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsRemoved(RecordedProgram... recordedPrograms) {
+ boolean needToUpdateCardView = false;
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (TextUtils.equals(recordedProgram.getSeriesId(),
+ mSeriesRecording.getSeriesId())) {
+ if (mWatchedPositionManager.getWatchedPosition(recordedProgram.getId())
+ == TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ mWatchedPositionManager.removeListener(this, recordedProgram.getId());
+ }
+ needToUpdateCardView = true;
+ }
+ }
+ if (needToUpdateCardView) {
+ updateCardViewContent();
+ }
+ }
+
+ @Override
+ public void onRecordedProgramsChanged(RecordedProgram... recordedPrograms) {
+ // Do nothing
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ // Do nothing
+ }
+
+ public void onBound(SeriesRecording seriesRecording) {
+ mSeriesRecording = seriesRecording;
+ mDvrDataManager.addScheduledRecordingListener(this);
+ mDvrDataManager.addRecordedProgramListener(this);
+ for (RecordedProgram recordedProgram :
+ mDvrDataManager.getRecordedPrograms(mSeriesRecording.getId())) {
+ if (mWatchedPositionManager.getWatchedPosition(recordedProgram.getId())
+ == TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ mWatchedPositionManager.addListener(this, recordedProgram.getId());
+ }
+ }
+ updateCardViewContent();
+ }
+
+ public void onUnbound() {
+ mDvrDataManager.removeScheduledRecordingListener(this);
+ mDvrDataManager.removeRecordedProgramListener(this);
+ mWatchedPositionManager.removeListener(this);
+ }
+
+ private void updateCardViewContent() {
+ int count = 0;
+ int quantityStringID;
+ List<RecordedProgram> recordedPrograms =
+ mDvrDataManager.getRecordedPrograms(mSeriesRecording.getId());
+ if (recordedPrograms.size() == 0) {
+ count = mDvrManager.getAvailableScheduledRecording(mSeriesRecording.getId()).size();
+ quantityStringID = R.plurals.dvr_count_scheduled_recordings;
+ } else {
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (mWatchedPositionManager.getWatchedPosition(recordedProgram.getId())
+ == TvInputManager.TIME_SHIFT_INVALID_TIME) {
+ count++;
+ }
+ }
+ if (count == 0) {
+ count = recordedPrograms.size();
+ quantityStringID = R.plurals.dvr_count_recordings;
+ } else {
+ quantityStringID = R.plurals.dvr_count_new_recordings;
+ }
+ }
+ mCardView.setContent(mCardView.getResources()
+ .getQuantityString(quantityStringID, count, count), null);
+ }
+ }
+
+ public SeriesRecordingPresenter(Context context) {
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
+ mChannelDataManager = singletons.getChannelDataManager();
+ mDvrDataManager = singletons.getDvrDataManager();
+ mDvrManager = singletons.getDvrManager();
+ mWatchedPositionManager = singletons.getDvrWatchedPositionManager();
+ }
+
+ @Override
+ public ViewHolder onCreateViewHolder(ViewGroup parent) {
+ Context context = parent.getContext();
+ RecordingCardView view = new RecordingCardView(context);
+ return new SeriesRecordingViewHolder(view, mDvrDataManager, mDvrManager,
+ mWatchedPositionManager);
+ }
+
+ @Override
+ public void onBindViewHolder(ViewHolder baseHolder, Object o) {
+ final SeriesRecordingViewHolder viewHolder = (SeriesRecordingViewHolder) baseHolder;
+ final SeriesRecording seriesRecording = (SeriesRecording) o;
+ final RecordingCardView cardView = (RecordingCardView) viewHolder.view;
+ viewHolder.onBound(seriesRecording);
+ setTitleAndImage(cardView, seriesRecording);
+ super.onBindViewHolder(baseHolder, o);
+ }
+
+ @Override
+ public void onUnbindViewHolder(ViewHolder viewHolder) {
+ ((RecordingCardView) viewHolder.view).reset();
+ ((SeriesRecordingViewHolder) viewHolder).onUnbound();
+ super.onUnbindViewHolder(viewHolder);
+ }
+
+ private void setTitleAndImage(RecordingCardView cardView, SeriesRecording recording) {
+ cardView.setTitle(recording.getTitle());
+ if (recording.getPosterUri() != null) {
+ cardView.setImageUri(recording.getPosterUri(), false);
+ } else {
+ Channel channel = mChannelDataManager.getChannel(recording.getChannelId());
+ String imageUri = null;
+ if (channel != null) {
+ imageUri = TvContract.buildChannelLogoUri(channel.getId()).toString();
+ }
+ cardView.setImageUri(imageUri, true);
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/SeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/SeriesSettingsFragment.java
new file mode 100644
index 00000000..6c05c9c6
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/SeriesSettingsFragment.java
@@ -0,0 +1,397 @@
+/*
+ * 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.app.FragmentManager;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.ProgressBar;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.EpisodicProgramLoadTask;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.SeriesRecording.ChannelOption;
+import com.android.tv.dvr.SeriesRecordingScheduler;
+import com.android.tv.dvr.SeriesRecordingScheduler.OnSeriesRecordingUpdatedListener;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Fragment for DVR series recording settings.
+ */
+public class SeriesSettingsFragment extends GuidedStepFragment
+ implements DvrDataManager.SeriesRecordingListener {
+ private static final String TAG = "SeriesSettingsFragment";
+ private static final boolean DEBUG = false;
+
+ private static final long ACTION_ID_PRIORITY = 10;
+ private static final long ACTION_ID_CHANNEL = 11;
+
+ private static final long SUB_ACTION_ID_CHANNEL_ALL = 102;
+ // Each channel's action id = SUB_ACTION_ID_CHANNEL_ONE_BASE + channel id
+ private static final long SUB_ACTION_ID_CHANNEL_ONE_BASE = 500;
+
+ private DvrDataManager mDvrDataManager;
+ private ChannelDataManager mChannelDataManager;
+ private DvrManager mDvrManager;
+ private SeriesRecording mSeriesRecording;
+ private long mSeriesRecordingId;
+ @ChannelOption int mChannelOption;
+ private Comparator<Channel> mChannelComparator;
+ private long mSelectedChannelId;
+ private int mBackStackCount;
+ private boolean mShowViewScheduleOptionInDialog;
+
+ private String mFragmentTitle;
+ private String mProrityActionTitle;
+ private String mProrityActionHighestText;
+ private String mProrityActionLowestText;
+ private String mChannelsActionTitle;
+ private String mChannelsActionAllText;
+ private LongSparseArray<Channel> mId2Channel = new LongSparseArray<>();
+ private List<Channel> mChannels = new ArrayList<>();
+ private EpisodicProgramLoadTask mEpisodicProgramLoadTask;
+
+ private GuidedAction mPriorityGuidedAction;
+ private GuidedAction mChannelsGuidedAction;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ mBackStackCount = getFragmentManager().getBackStackEntryCount();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mSeriesRecordingId = getArguments().getLong(DvrSeriesSettingsActivity.SERIES_RECORDING_ID);
+ mSeriesRecording = mDvrDataManager.getSeriesRecording(mSeriesRecordingId);
+ if (mSeriesRecording == null) {
+ getActivity().finish();
+ return;
+ }
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mShowViewScheduleOptionInDialog = getArguments().getBoolean(
+ DvrSeriesSettingsActivity.SHOW_VIEW_SCHEDULE_OPTION_IN_DIALOG);
+ mDvrDataManager.addSeriesRecordingListener(this);
+ long[] channelIds = getArguments().getLongArray(DvrSeriesSettingsActivity.CHANNEL_ID_LIST);
+ mChannelDataManager = TvApplication.getSingletons(context).getChannelDataManager();
+ if (channelIds == null) {
+ Channel channel = mChannelDataManager.getChannel(mSeriesRecording.getChannelId());
+ if (channel != null) {
+ mId2Channel.put(channel.getId(), channel);
+ mChannels.add(channel);
+ }
+ collectChannelsInBackground();
+ } else {
+ for (long channelId : channelIds) {
+ Channel channel = mChannelDataManager.getChannel(channelId);
+ if (channel != null) {
+ mId2Channel.put(channel.getId(), channel);
+ mChannels.add(channel);
+ }
+ }
+ }
+ mChannelOption = mSeriesRecording.getChannelOption();
+ mSelectedChannelId = Channel.INVALID_ID;
+ if (mChannelOption == SeriesRecording.OPTION_CHANNEL_ONE) {
+ Channel channel = mChannelDataManager.getChannel(mSeriesRecording.getChannelId());
+ if (channel != null) {
+ mSelectedChannelId = channel.getId();
+ } else {
+ mChannelOption = SeriesRecording.OPTION_CHANNEL_ALL;
+ }
+ }
+ mChannelComparator = new Channel.DefaultComparator(context,
+ TvApplication.getSingletons(context).getTvInputManagerHelper());
+ mChannels.sort(mChannelComparator);
+ mFragmentTitle = getString(R.string.dvr_series_settings_title);
+ mProrityActionTitle = getString(R.string.dvr_series_settings_priority);
+ mProrityActionHighestText = getString(R.string.dvr_series_settings_priority_highest);
+ mProrityActionLowestText = getString(R.string.dvr_series_settings_priority_lowest);
+ mChannelsActionTitle = getString(R.string.dvr_series_settings_channels);
+ mChannelsActionAllText = getString(R.string.dvr_series_settings_channels_all);
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mDvrDataManager.removeSeriesRecordingListener(this);
+ if (mEpisodicProgramLoadTask != null) {
+ mEpisodicProgramLoadTask.cancel(true);
+ mEpisodicProgramLoadTask = null;
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ DvrManager dvrManager = TvApplication.getSingletons(getActivity()).getDvrManager();
+ if (getFragmentManager().getBackStackEntryCount() == mBackStackCount
+ && getArguments()
+ .getBoolean(DvrSeriesSettingsActivity.REMOVE_EMPTY_SERIES_RECORDING)
+ && dvrManager.canRemoveSeriesRecording(mSeriesRecordingId)) {
+ dvrManager.removeSeriesRecording(mSeriesRecordingId);
+ }
+ super.onDestroy();
+ }
+
+ @Override
+ public Guidance onCreateGuidance(Bundle savedInstanceState) {
+ String breadcrumb = mSeriesRecording.getTitle();
+ String title = mFragmentTitle;
+ return new Guidance(title, null, breadcrumb, null);
+ }
+
+ @Override
+ public void onCreateActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ mPriorityGuidedAction = new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_PRIORITY)
+ .title(mProrityActionTitle)
+ .build();
+ updatePriorityGuidedAction(false);
+ actions.add(mPriorityGuidedAction);
+
+ mChannelsGuidedAction = new GuidedAction.Builder(getActivity())
+ .id(ACTION_ID_CHANNEL)
+ .title(mChannelsActionTitle)
+ .subActions(buildChannelSubAction())
+ .build();
+ actions.add(mChannelsGuidedAction);
+ updateChannelsGuidedAction(false);
+ }
+
+ @Override
+ public void onCreateButtonActions(List<GuidedAction> actions, Bundle savedInstanceState) {
+ actions.add(new GuidedAction.Builder(getActivity())
+ .clickAction(GuidedAction.ACTION_ID_OK)
+ .build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .clickAction(GuidedAction.ACTION_ID_CANCEL)
+ .build());
+ }
+
+ @Override
+ public void onGuidedActionClicked(GuidedAction action) {
+ long actionId = action.getId();
+ if (actionId == GuidedAction.ACTION_ID_OK) {
+ if (mEpisodicProgramLoadTask != null) {
+ mEpisodicProgramLoadTask.cancel(true);
+ mEpisodicProgramLoadTask = null;
+ }
+ if (mChannelOption != mSeriesRecording.getChannelOption()
+ || mSeriesRecording.isStopped()
+ || (mChannelOption == SeriesRecording.OPTION_CHANNEL_ONE
+ && mSeriesRecording.getChannelId() != mSelectedChannelId)) {
+ SeriesRecording.Builder builder = SeriesRecording.buildFrom(mSeriesRecording)
+ .setChannelOption(mChannelOption)
+ .setState(SeriesRecording.STATE_SERIES_NORMAL);
+ if (mSelectedChannelId != Channel.INVALID_ID) {
+ builder.setChannelId(mSelectedChannelId);
+ }
+ TvApplication.getSingletons(getContext()).getDvrManager()
+ .updateSeriesRecording(builder.build());
+ SeriesRecordingScheduler scheduler =
+ SeriesRecordingScheduler.getInstance(getContext());
+ // Since dialog is used even after the fragment is closed, we should
+ // use application context.
+ ProgressDialog dialog = ProgressDialog.show(getContext(), null, getString(
+ R.string.dvr_series_schedules_progress_message_updating_programs));
+ scheduler.addOnSeriesRecordingUpdatedListener(
+ new OnSeriesRecordingUpdatedListener() {
+ @Override
+ public void onSeriesRecordingUpdated(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ if (seriesRecording.getId() == mSeriesRecordingId) {
+ dialog.dismiss();
+ scheduler.removeOnSeriesRecordingUpdatedListener(this);
+ showConfirmDialog();
+ return;
+ }
+ }
+ }
+ });
+ } else {
+ showConfirmDialog();
+ }
+ } else if (actionId == GuidedAction.ACTION_ID_CANCEL) {
+ finishGuidedStepFragments();
+ } else if (actionId == ACTION_ID_PRIORITY) {
+ FragmentManager fragmentManager = getFragmentManager();
+ PrioritySettingsFragment fragment = new PrioritySettingsFragment();
+ Bundle args = new Bundle();
+ args.putLong(PrioritySettingsFragment.COME_FROM_SERIES_RECORDING_ID,
+ mSeriesRecording.getId());
+ fragment.setArguments(args);
+ GuidedStepFragment.add(fragmentManager, fragment, R.id.dvr_settings_view_frame);
+ }
+ }
+
+ @Override
+ public boolean onSubGuidedActionClicked(GuidedAction action) {
+ long actionId = action.getId();
+ if (actionId == SUB_ACTION_ID_CHANNEL_ALL) {
+ mChannelOption = SeriesRecording.OPTION_CHANNEL_ALL;
+ mSelectedChannelId = Channel.INVALID_ID;
+ updateChannelsGuidedAction(true);
+ return true;
+ } else if (actionId > SUB_ACTION_ID_CHANNEL_ONE_BASE) {
+ mChannelOption = SeriesRecording.OPTION_CHANNEL_ONE;
+ mSelectedChannelId = actionId - SUB_ACTION_ID_CHANNEL_ONE_BASE;
+ updateChannelsGuidedAction(true);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public GuidedActionsStylist onCreateButtonActionsStylist() {
+ return new DvrGuidedActionsStylist(true);
+ }
+
+ private void updateChannelsGuidedAction(boolean notifyActionChanged) {
+ if (mChannelOption == SeriesRecording.OPTION_CHANNEL_ALL) {
+ mChannelsGuidedAction.setDescription(mChannelsActionAllText);
+ } else {
+ mChannelsGuidedAction.setDescription(mId2Channel.get(mSelectedChannelId)
+ .getDisplayText());
+ }
+ if (notifyActionChanged) {
+ notifyActionChanged(findActionPositionById(ACTION_ID_CHANNEL));
+ }
+ }
+
+ private void updatePriorityGuidedAction(boolean notifyActionChanged) {
+ int totalSeriesCount = 0;
+ int priorityOrder = 0;
+ for (SeriesRecording seriesRecording : mDvrDataManager.getSeriesRecordings()) {
+ if (seriesRecording.getState() == SeriesRecording.STATE_SERIES_NORMAL
+ || seriesRecording.getId() == mSeriesRecording.getId()) {
+ ++totalSeriesCount;
+ }
+ if (seriesRecording.getState() == SeriesRecording.STATE_SERIES_NORMAL
+ && seriesRecording.getId() != mSeriesRecording.getId()
+ && seriesRecording.getPriority() > mSeriesRecording.getPriority()) {
+ ++priorityOrder;
+ }
+ }
+ if (priorityOrder == 0) {
+ mPriorityGuidedAction.setDescription(mProrityActionHighestText);
+ } else if (priorityOrder >= totalSeriesCount - 1) {
+ mPriorityGuidedAction.setDescription(mProrityActionLowestText);
+ } else {
+ mPriorityGuidedAction.setDescription(getString(
+ R.string.dvr_series_settings_priority_rank, priorityOrder + 1));
+ }
+ if (notifyActionChanged) {
+ notifyActionChanged(findActionPositionById(ACTION_ID_PRIORITY));
+ }
+ }
+
+ private void collectChannelsInBackground() {
+ if (mEpisodicProgramLoadTask != null) {
+ mEpisodicProgramLoadTask.cancel(true);
+ }
+ mEpisodicProgramLoadTask = new EpisodicProgramLoadTask(getContext(), mSeriesRecording) {
+ @Override
+ protected void onPostExecute(List<Program> programs) {
+ mEpisodicProgramLoadTask = null;
+ Set<Long> channelIds = new HashSet<>();
+ for (Program program : programs) {
+ channelIds.add(program.getChannelId());
+ }
+ boolean channelAdded = false;
+ for (Long channelId : channelIds) {
+ if (mId2Channel.get(channelId) != null) {
+ continue;
+ }
+ Channel channel = mChannelDataManager.getChannel(channelId);
+ if (channel != null) {
+ channelAdded = true;
+ mId2Channel.put(channelId, channel);
+ mChannels.add(channel);
+ if (DEBUG) Log.d(TAG, "Added channel: " + channel);
+ }
+ }
+ if (!channelAdded) {
+ return;
+ }
+ mChannels.sort(mChannelComparator);
+ mChannelsGuidedAction.setSubActions(buildChannelSubAction());
+ notifyActionChanged(findActionPositionById(ACTION_ID_CHANNEL));
+ if (DEBUG) Log.d(TAG, "Complete EpisodicProgramLoadTask");
+ }
+ }.setLoadCurrentProgram(true)
+ .setLoadDisallowedProgram(true)
+ .setLoadScheduledEpisode(true)
+ .setIgnoreChannelOption(true);
+ mEpisodicProgramLoadTask.execute();
+ }
+
+ private List<GuidedAction> buildChannelSubAction() {
+ List<GuidedAction> channelSubActions = new ArrayList<>();
+ channelSubActions.add(new GuidedAction.Builder(getActivity())
+ .id(SUB_ACTION_ID_CHANNEL_ALL)
+ .title(mChannelsActionAllText)
+ .build());
+ for (Channel channel : mChannels) {
+ channelSubActions.add(new GuidedAction.Builder(getActivity())
+ .id(SUB_ACTION_ID_CHANNEL_ONE_BASE + channel.getId())
+ .title(channel.getDisplayText())
+ .build());
+ }
+ return channelSubActions;
+ }
+
+ private void showConfirmDialog() {
+ DvrUiHelper.StartSeriesScheduledDialogActivity(
+ getContext(), mSeriesRecording, mShowViewScheduleOptionInDialog);
+ finishGuidedStepFragments();
+ }
+
+ @Override
+ public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) { }
+
+ @Override
+ public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) { }
+
+ @Override
+ public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording seriesRecording : seriesRecordings) {
+ if (seriesRecording.getId() == mSeriesRecordingId) {
+ mSeriesRecording = seriesRecording;
+ updatePriorityGuidedAction(true);
+ return;
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java
index 8a8bcdeb..393a5ff3 100644
--- a/src/com/android/tv/dvr/ui/SortedArrayAdapter.java
+++ b/src/com/android/tv/dvr/ui/SortedArrayAdapter.java
@@ -16,7 +16,8 @@
package com.android.tv.dvr.ui;
-import android.support.v17.leanback.widget.ObjectAdapter;
+import android.support.annotation.VisibleForTesting;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
import android.support.v17.leanback.widget.PresenterSelector;
import java.util.ArrayList;
@@ -26,168 +27,155 @@ import java.util.Comparator;
import java.util.List;
/**
- * Keeps a set of {@code T} items sorted, but leaving a {@link EmptyHolder}
- * if there is no items.
+ * Keeps a set of items sorted
*
* <p>{@code T} must have stable IDs.
*/
-abstract class SortedArrayAdapter<T> extends ObjectAdapter {
- private final List<T> mItems = new ArrayList<>();
+public abstract class SortedArrayAdapter<T> extends ArrayObjectAdapter {
private final Comparator<T> mComparator;
+ private final int mMaxItemCount;
+ private int mExtraItemCount;
SortedArrayAdapter(PresenterSelector presenterSelector, Comparator<T> comparator) {
- super(presenterSelector);
- mComparator = comparator;
- setHasStableIds(true);
- }
-
- @Override
- public final int size() {
- return mItems.isEmpty() ? 1 : mItems.size();
- }
-
- @Override
- public final Object get(int position) {
- return isEmpty() ? EmptyHolder.EMPTY_HOLDER : getItem(position);
+ this(presenterSelector, comparator, Integer.MAX_VALUE);
}
- @Override
- public final long getId(int position) {
- if (isEmpty()) {
- return NO_ID;
- }
- T item = mItems.get(position);
- return item == null ? NO_ID : getId(item);
- }
-
- /**
- * Returns the id of the the given {@code item}.
- *
- * The id must be stable.
- */
- abstract long getId(T item);
-
- /**
- * Returns the item at the given {@code position}.
- *
- * @throws IndexOutOfBoundsException if the position is out of range
- * (<tt>position &lt; 0 || position &gt;= size()</tt>)
- */
- final T getItem(int position) {
- return mItems.get(position);
+ SortedArrayAdapter(PresenterSelector presenterSelector, Comparator<T> comparator,
+ int maxItemCount) {
+ super(presenterSelector);
+ mComparator = comparator;
+ mMaxItemCount = maxItemCount;
}
/**
- * Returns {@code true} if the list of items is empty.
+ * Sets the objects in the given collection to the adapter keeping the elements sorted.
*
- * <p><b>NOTE</b> when the item list is empty the adapter has a size of 1 and
- * {@link EmptyHolder#EMPTY_HOLDER} at position 0;
+ * @param items A {@link Collection} of items to be set.
*/
- final boolean isEmpty() {
- return mItems.isEmpty();
+ @VisibleForTesting
+ final void setInitialItems(List<T> items) {
+ List<T> itemsCopy = new ArrayList<>(items);
+ Collections.sort(itemsCopy, mComparator);
+ addAll(0, itemsCopy.subList(0, Math.min(mMaxItemCount, itemsCopy.size())));
}
/**
- * Removes all elements from the list.
+ * Adds an item in sorted order to the adapter.
*
- * <p><b>NOTE</b> when the item list is empty the adapter has a size of 1 and
- * {@link EmptyHolder#EMPTY_HOLDER} at position 0;
+ * @param item The item to add in sorted order to the adapter.
*/
- final void clear() {
- mItems.clear();
- notifyChanged();
+ @Override
+ public final void add(Object item) {
+ add((T) item, false);
}
- /**
- * Adds the objects in the given collection to the adapter keeping the elements sorted.
- * If the index is >= {@link #size} an exception will be thrown.
- *
- * @param items A {@link Collection} of items to insert.
- */
- final void addAll(Collection<T> items) {
- mItems.addAll(items);
- Collections.sort(mItems, mComparator);
- notifyChanged();
+ public boolean isEmpty() {
+ return size() == 0;
}
/**
* Adds an item in sorted order to the adapter.
*
* @param item The item to add in sorted order to the adapter.
+ * @param insertToEnd If items are inserted in a more or less sorted fashion,
+ * sets this parameter to {@code true} to search insertion position from
+ * the end to save search time.
*/
- final void add(T item) {
- int i = findWhereToInsert(item);
- mItems.add(i, item);
- if (mItems.size() == 1) {
- notifyItemRangeChanged(0, 1);
+ public final void add(T item, boolean insertToEnd) {
+ int i;
+ if (insertToEnd) {
+ i = findInsertPosition(item);
} else {
- notifyItemRangeInserted(i, 1);
+ i = findInsertPositionBinary(item);
+ }
+ super.add(i, item);
+ if (size() > mMaxItemCount + mExtraItemCount) {
+ removeItems(mMaxItemCount, size() - mMaxItemCount - mExtraItemCount);
}
}
/**
- * Remove an item from the list
- *
- * @param item The item to remove from the adapter.
+ * Adds an extra item to the end of the adapter. The items will not be subjected to the sorted
+ * order or the maximum number of items. One or more extra items can be added to the adapter.
+ * They will be presented in their insertion order.
*/
- final void remove(T item) {
- int index = indexOf(item);
- if (index != -1) {
- mItems.remove(index);
- if (mItems.isEmpty()) {
- notifyItemRangeChanged(0, 1);
- } else {
- notifyItemRangeRemoved(index, 1);
- }
- }
+ public int addExtraItem(T item) {
+ super.add(item);
+ return ++mExtraItemCount;
+ }
+
+ /**
+ * Removes an item which has the same ID as {@code item}.
+ */
+ public boolean removeWithId(T item) {
+ int index = indexWithTypeAndId(item);
+ return index >= 0 && index < size() && remove(get(index));
}
/**
* Change an item in the list.
* @param item The item to change.
*/
- final void change(T item) {
- int oldIndex = indexOf(item);
+ public final void change(T item) {
+ int oldIndex = indexWithTypeAndId(item);
if (oldIndex != -1) {
- T old = mItems.get(oldIndex);
+ T old = (T) get(oldIndex);
if (mComparator.compare(old, item) == 0) {
- mItems.set(oldIndex, item);
- notifyItemRangeChanged(oldIndex, 1);
+ replace(oldIndex, item);
return;
}
- mItems.remove(oldIndex);
- }
- int newIndex = findWhereToInsert(item);
- mItems.add(newIndex, item);
-
- if (oldIndex != -1) {
- notifyItemRangeRemoved(oldIndex, 1);
- }
- if (newIndex != -1) {
- notifyItemRangeInserted(newIndex, 1);
+ removeItems(oldIndex, 1);
}
+ add(item);
}
- private int indexOf(T item) {
+ /**
+ * Returns the id of the the given {@code item}, which will be used in {@link #change} to
+ * decide if the given item is already existed in the adapter.
+ *
+ * The id must be stable.
+ */
+ abstract long getId(T item);
+
+ private int indexWithTypeAndId(T item) {
long id = getId(item);
- for (int i = 0; i < mItems.size(); i++) {
- T r = mItems.get(i);
- if (getId(r) == id) {
+ for (int i = 0; i < size() - mExtraItemCount; i++) {
+ T r = (T) get(i);
+ if (r.getClass() == item.getClass() && getId(r) == id) {
return i;
}
}
return -1;
}
- private int findWhereToInsert(T item) {
- int i;
- int size = mItems.size();
- for (i = 0; i < size; i++) {
- T r = mItems.get(i);
- if (mComparator.compare(r, item) > 0) {
- return i;
+ /**
+ * Finds the position that the given item should be inserted to keep the sorted order.
+ */
+ public int findInsertPosition(T item) {
+ for (int i = size() - mExtraItemCount - 1; i >=0; i--) {
+ T r = (T) get(i);
+ if (mComparator.compare(r, item) <= 0) {
+ return i + 1;
+ }
+ }
+ return 0;
+ }
+
+ private int findInsertPositionBinary(T item) {
+ int lb = 0;
+ int ub = size() - mExtraItemCount - 1;
+ while (lb <= ub) {
+ int mid = (lb + ub) / 2;
+ T r = (T) get(mid);
+ int compareResult = mComparator.compare(item, r);
+ if (compareResult == 0) {
+ return mid;
+ } else if (compareResult > 0) {
+ lb = mid + 1;
+ } else {
+ ub = mid - 1;
}
}
- return size;
+ return lb;
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
new file mode 100644
index 00000000..d28f026c
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
@@ -0,0 +1,178 @@
+/*
+* 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.list;
+
+import android.os.Bundle;
+import android.support.v17.leanback.app.DetailsFragment;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.ScheduledRecording;
+
+/**
+ * A base fragment to show the list of schedule recordings.
+ */
+public abstract class BaseDvrSchedulesFragment extends DetailsFragment
+ implements DvrDataManager.ScheduledRecordingListener,
+ DvrScheduleManager.OnConflictStateChangeListener {
+ /**
+ * The key for scheduled recording which has be selected in the list.
+ */
+ public static String SCHEDULES_KEY_SCHEDULED_RECORDING = "schedules_key_scheduled_recording";
+
+ private ScheduleRowAdapter mRowsAdapter;
+ private TextView mEmptyInfoScreenView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
+ presenterSelector.addClassPresenter(SchedulesHeaderRow.class, onCreateHeaderRowPresenter());
+ presenterSelector.addClassPresenter(ScheduleRow.class, onCreateRowPresenter());
+ mRowsAdapter = onCreateRowsAdapter(presenterSelector);
+ setAdapter(mRowsAdapter);
+ mRowsAdapter.start();
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
+ singletons.getDvrDataManager().addScheduledRecordingListener(this);
+ singletons.getDvrScheduleManager().addOnConflictStateChangeListener(this);
+ mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View view = super.onCreateView(inflater, container, savedInstanceState);
+ int firstItemPosition = getFirstItemPosition();
+ if (firstItemPosition != -1) {
+ getRowsFragment().setSelectedPosition(firstItemPosition, false);
+ }
+ return view;
+ }
+
+ /**
+ * Returns rows adapter.
+ */
+ protected ScheduleRowAdapter getRowsAdapter() {
+ return mRowsAdapter;
+ }
+
+ /**
+ * Shows the empty message.
+ */
+ void showEmptyMessage(int messageId) {
+ mEmptyInfoScreenView.setText(messageId);
+ if (mEmptyInfoScreenView.getVisibility() != View.VISIBLE) {
+ mEmptyInfoScreenView.setVisibility(View.VISIBLE);
+ }
+ }
+
+ /**
+ * Hides the empty message.
+ */
+ void hideEmptyMessage() {
+ if (mEmptyInfoScreenView.getVisibility() == View.VISIBLE) {
+ mEmptyInfoScreenView.setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public View onInflateTitleView(LayoutInflater inflater, ViewGroup parent,
+ Bundle savedInstanceState) {
+ // Workaround of b/31046014
+ return null;
+ }
+
+ @Override
+ public void onDestroy() {
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
+ singletons.getDvrScheduleManager().removeOnConflictStateChangeListener(this);
+ singletons.getDvrDataManager().removeScheduledRecordingListener(this);
+ mRowsAdapter.stop();
+ super.onDestroy();
+ }
+
+ /**
+ * Creates header row presenter.
+ */
+ public abstract SchedulesHeaderRowPresenter onCreateHeaderRowPresenter();
+
+ /**
+ * Creates rows presenter.
+ */
+ public abstract ScheduleRowPresenter onCreateRowPresenter();
+
+ /**
+ * Creates rows adapter.
+ */
+ public abstract ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelecor);
+
+ /**
+ * Gets the first focus position in schedules list.
+ */
+ protected int getFirstItemPosition() {
+ for (int i = 0; i < mRowsAdapter.size(); i++) {
+ if (mRowsAdapter.get(i) instanceof ScheduleRow) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingAdded(recording);
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingRemoved(recording);
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : scheduledRecordings) {
+ mRowsAdapter.onScheduledRecordingUpdated(recording, false);
+ }
+ }
+ }
+
+ @Override
+ public void onConflictStateChange(boolean conflict, ScheduledRecording... schedules) {
+ if (mRowsAdapter != null) {
+ for (ScheduledRecording recording : schedules) {
+ mRowsAdapter.onScheduledRecordingUpdated(recording, true);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFocusView.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFocusView.java
new file mode 100644
index 00000000..c906c62a
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesFocusView.java
@@ -0,0 +1,88 @@
+/*
+ * 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.list;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+
+import com.android.tv.R;
+
+/**
+ * A view used for focus in schedules list.
+ */
+public class DvrSchedulesFocusView extends View {
+ private final Paint mPaint;
+ private final RectF mRoundRectF = new RectF();
+ private final int mRoundRectRadius;
+
+ private final String mViewTag;
+ private final String mHeaderFocusViewTag;
+ private final String mItemFocusViewTag;
+
+ public DvrSchedulesFocusView(Context context) {
+ this(context, null, 0);
+ }
+
+ public DvrSchedulesFocusView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public DvrSchedulesFocusView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mHeaderFocusViewTag = getContext().getString(R.string.dvr_schedules_header_focus_view);
+ mItemFocusViewTag = getContext().getString(R.string.dvr_schedules_item_focus_view);
+ mViewTag = (String) getTag();
+ mPaint = createPaint(context);
+ mRoundRectRadius = getRoundRectRadius();
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (TextUtils.equals(mViewTag, mHeaderFocusViewTag)) {
+ mRoundRectF.set(0, 0, getWidth(), getHeight());
+ } else if (TextUtils.equals(mViewTag, mItemFocusViewTag)) {
+ int drawHeight = 2 * mRoundRectRadius;
+ int drawOffset = (drawHeight - getHeight()) / 2;
+ mRoundRectF.set(0, -drawOffset, getWidth(), getHeight() + drawOffset);
+ }
+ canvas.drawRoundRect(mRoundRectF, mRoundRectRadius, mRoundRectRadius, mPaint);
+ }
+
+ private Paint createPaint(Context context) {
+ Paint paint = new Paint();
+ paint.setColor(context.getColor(R.color.dvr_schedules_list_item_selector));
+ return paint;
+ }
+
+ private int getRoundRectRadius() {
+ if (TextUtils.equals(mViewTag, mHeaderFocusViewTag)) {
+ return getResources().getDimensionPixelSize(
+ R.dimen.dvr_schedules_header_selector_radius);
+ } else if (TextUtils.equals(mViewTag, mItemFocusViewTag)) {
+ return getResources().getDimensionPixelSize(R.dimen.dvr_schedules_selector_radius);
+ }
+ return 0;
+ }
+}
+
+
diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java
new file mode 100644
index 00000000..722c9b6e
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java
@@ -0,0 +1,86 @@
+/*
+ * 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.list;
+
+import android.os.Bundle;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.R;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter;
+
+/**
+ * A fragment to show the list of schedule recordings.
+ */
+public class DvrSchedulesFragment extends BaseDvrSchedulesFragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getRowsAdapter().size() == 0) {
+ showEmptyMessage(R.string.dvr_schedules_empty_state);
+ }
+ }
+
+ @Override
+ public SchedulesHeaderRowPresenter onCreateHeaderRowPresenter() {
+ return new DateHeaderRowPresenter(getContext());
+ }
+
+ @Override
+ public ScheduleRowPresenter onCreateRowPresenter() {
+ return new ScheduleRowPresenter(getContext());
+ }
+
+ @Override
+ public ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelecor) {
+ return new ScheduleRowAdapter(getContext(), presenterSelecor);
+ }
+
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ super.onScheduledRecordingAdded(scheduledRecordings);
+ if (getRowsAdapter().size() > 0) {
+ hideEmptyMessage();
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ super.onScheduledRecordingRemoved(scheduledRecordings);
+ if (getRowsAdapter().size() == 0) {
+ showEmptyMessage(R.string.dvr_schedules_empty_state);
+ }
+ }
+
+ @Override
+ protected int getFirstItemPosition() {
+ Bundle args = getArguments();
+ ScheduledRecording recording = null;
+ if (args != null) {
+ recording = args.getParcelable(SCHEDULES_KEY_SCHEDULED_RECORDING);
+ }
+ final int selectedPostion = getRowsAdapter().indexOf(
+ getRowsAdapter().findRowByScheduledRecording(recording));
+ if (selectedPostion != -1) {
+ return selectedPostion;
+ }
+ return super.getFirstItemPosition();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java
new file mode 100644
index 00000000..42a1e72b
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrSeriesSchedulesFragment.java
@@ -0,0 +1,208 @@
+/*
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License
+*/
+
+package com.android.tv.dvr.ui.list;
+
+import android.annotation.TargetApi;
+import android.database.ContentObserver;
+import android.media.tv.TvContract.Programs;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.transition.Fade;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager.SeriesRecordingListener;
+import com.android.tv.dvr.EpisodicProgramLoadTask;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.SeriesRecordingHeaderRowPresenter;
+
+import java.util.List;
+
+/**
+ * A fragment to show the list of series schedule recordings.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class DvrSeriesSchedulesFragment extends BaseDvrSchedulesFragment {
+ private static final String TAG = "DvrSeriesSchedulesFragment";
+ /**
+ * The key for series recording whose scheduled recording list will be displayed.
+ */
+ public static final String SERIES_SCHEDULES_KEY_SERIES_RECORDING =
+ "series_schedules_key_series_recording";
+ /**
+ * The key for programs belong to the series recording whose scheduled recording
+ * list will be displayed.
+ */
+ public static final String SERIES_SCHEDULES_KEY_SERIES_PROGRAMS =
+ "series_schedules_key_series_programs";
+
+ private ChannelDataManager mChannelDataManager;
+ private SeriesRecording mSeriesRecording;
+ private List<Program> mPrograms;
+ private EpisodicProgramLoadTask mProgramLoadTask;
+
+ private final SeriesRecordingListener mSeriesRecordingListener =
+ new SeriesRecordingListener() {
+ @Override
+ public void onSeriesRecordingAdded(SeriesRecording... seriesRecordings) { }
+
+ @Override
+ public void onSeriesRecordingRemoved(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ if (r.getId() == mSeriesRecording.getId()) {
+ getActivity().finish();
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void onSeriesRecordingChanged(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ if (r.getId() == mSeriesRecording.getId()
+ && getRowsAdapter() instanceof SeriesScheduleRowAdapter) {
+ ((SeriesScheduleRowAdapter) getRowsAdapter())
+ .onSeriesRecordingUpdated(r);
+ return;
+ }
+ }
+ }
+ };
+
+ private final ContentObserver mContentObserver =
+ new ContentObserver(new Handler(Looper.getMainLooper())) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ executeProgramLoadingTask();
+ }
+ };
+
+ private final ChannelDataManager.Listener mChannelListener = new ChannelDataManager.Listener() {
+ @Override
+ public void onLoadFinished() { }
+
+ @Override
+ public void onChannelListUpdated() {
+ executeProgramLoadingTask();
+ }
+
+ @Override
+ public void onChannelBrowsableChanged() { }
+ };
+
+ public DvrSeriesSchedulesFragment() {
+ setEnterTransition(new Fade(Fade.IN));
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Bundle args = getArguments();
+ if (args != null) {
+ mSeriesRecording = args.getParcelable(SERIES_SCHEDULES_KEY_SERIES_RECORDING);
+ mPrograms = args.getParcelableArrayList(SERIES_SCHEDULES_KEY_SERIES_PROGRAMS);
+ }
+ super.onCreate(savedInstanceState);
+ ApplicationSingletons singletons = TvApplication.getSingletons(getContext());
+ singletons.getDvrDataManager().addSeriesRecordingListener(mSeriesRecordingListener);
+ mChannelDataManager = singletons.getChannelDataManager();
+ mChannelDataManager.addListener(mChannelListener);
+ getContext().getContentResolver().registerContentObserver(Programs.CONTENT_URI, true,
+ mContentObserver);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ onProgramsUpdated();
+ return super.onCreateView(inflater, container, savedInstanceState);
+ }
+
+ private void onProgramsUpdated() {
+ ((SeriesScheduleRowAdapter) getRowsAdapter()).setPrograms(mPrograms);
+ if (mPrograms == null || mPrograms.isEmpty()) {
+ showEmptyMessage(R.string.dvr_series_schedules_empty_state);
+ } else {
+ hideEmptyMessage();
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (mProgramLoadTask != null) {
+ mProgramLoadTask.cancel(true);
+ mProgramLoadTask = null;
+ }
+ getContext().getContentResolver().unregisterContentObserver(mContentObserver);
+ mChannelDataManager.removeListener(mChannelListener);
+ TvApplication.getSingletons(getContext()).getDvrDataManager()
+ .removeSeriesRecordingListener(mSeriesRecordingListener);
+ super.onDestroy();
+ }
+
+ @Override
+ public SchedulesHeaderRowPresenter onCreateHeaderRowPresenter() {
+ return new SeriesRecordingHeaderRowPresenter(getContext());
+ }
+
+ @Override
+ public ScheduleRowPresenter onCreateRowPresenter() {
+ return new SeriesScheduleRowPresenter(getContext());
+ }
+
+ @Override
+ public ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelector) {
+ return new SeriesScheduleRowAdapter(getContext(), presenterSelector, mSeriesRecording);
+ }
+
+ @Override
+ protected int getFirstItemPosition() {
+ if (mSeriesRecording != null
+ && mSeriesRecording.getState() == SeriesRecording.STATE_SERIES_STOPPED) {
+ return 0;
+ }
+ return super.getFirstItemPosition();
+ }
+
+ private void executeProgramLoadingTask() {
+ if (mProgramLoadTask != null) {
+ mProgramLoadTask.cancel(true);
+ }
+ mProgramLoadTask = new EpisodicProgramLoadTask(getContext(), mSeriesRecording) {
+ @Override
+ protected void onPostExecute(List<Program> programs) {
+ mPrograms = programs;
+ onProgramsUpdated();
+ }
+ };
+ mProgramLoadTask.setLoadCurrentProgram(true)
+ .setLoadDisallowedProgram(true)
+ .setLoadScheduledEpisode(true)
+ .setIgnoreChannelOption(true)
+ .execute();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.java
new file mode 100644
index 00000000..23aebf59
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/EpisodicProgramRow.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.ui.list;
+
+import android.content.Context;
+
+import com.android.tv.data.Program;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ScheduledRecording.Builder;
+
+/**
+ * A class for the episodic program.
+ */
+public class EpisodicProgramRow extends ScheduleRow {
+ private final String mInputId;
+ private final Program mProgram;
+
+ public EpisodicProgramRow(String inputId, Program program, ScheduledRecording recording,
+ SchedulesHeaderRow headerRow) {
+ super(recording, headerRow);
+ mInputId = inputId;
+ mProgram = program;
+ }
+
+ /**
+ * Returns the program.
+ */
+ public Program getProgram() {
+ return mProgram;
+ }
+
+ @Override
+ public long getChannelId() {
+ return mProgram.getChannelId();
+ }
+
+ @Override
+ public long getStartTimeMs() {
+ return mProgram.getStartTimeUtcMillis();
+ }
+
+ @Override
+ public long getEndTimeMs() {
+ return mProgram.getEndTimeUtcMillis();
+ }
+
+ @Override
+ public Builder createNewScheduleBuilder() {
+ return ScheduledRecording.builder(mInputId, mProgram);
+ }
+
+ @Override
+ public String getProgramTitleWithEpisodeNumber(Context context) {
+ return mProgram.getTitleWithEpisodeNumber(context);
+ }
+
+ @Override
+ public String getEpisodeDisplayTitle(Context context) {
+ return mProgram.getEpisodeDisplayTitle(context);
+ }
+
+ @Override
+ public boolean matchSchedule(ScheduledRecording schedule) {
+ return schedule.getType() == ScheduledRecording.TYPE_PROGRAM
+ && mProgram.getId() == schedule.getProgramId();
+ }
+
+ @Override
+ public String toString() {
+ return super.toString()
+ + "(inputId=" + mInputId
+ + ",program=" + mProgram
+ + ")";
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRow.java b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
new file mode 100644
index 00000000..3fc92e8a
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
@@ -0,0 +1,203 @@
+/*
+ * 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.list;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.ScheduledRecording;
+
+/**
+ * A class for schedule recording row.
+ */
+public class ScheduleRow {
+ private final SchedulesHeaderRow mHeaderRow;
+ @Nullable private ScheduledRecording mSchedule;
+ private boolean mStopRecordingRequested;
+ private boolean mStartRecordingRequested;
+
+ public ScheduleRow(@Nullable ScheduledRecording recording, SchedulesHeaderRow headerRow) {
+ mSchedule = recording;
+ mHeaderRow = headerRow;
+ }
+
+ /**
+ * Gets which {@link SchedulesHeaderRow} this schedule row belongs to.
+ */
+ public SchedulesHeaderRow getHeaderRow() {
+ return mHeaderRow;
+ }
+
+ /**
+ * Returns the recording schedule.
+ */
+ @Nullable
+ public ScheduledRecording getSchedule() {
+ return mSchedule;
+ }
+
+ /**
+ * Checks if the stop recording has been requested or not.
+ */
+ public boolean isStopRecordingRequested() {
+ return mStopRecordingRequested;
+ }
+
+ /**
+ * Sets the flag of stop recording request.
+ */
+ public void setStopRecordingRequested(boolean stopRecordingRequested) {
+ SoftPreconditions.checkState(!mStartRecordingRequested);
+ mStopRecordingRequested = stopRecordingRequested;
+ }
+
+ /**
+ * Checks if the start recording has been requested or not.
+ */
+ public boolean isStartRecordingRequested() {
+ return mStartRecordingRequested;
+ }
+
+ /**
+ * Sets the flag of start recording request.
+ */
+ public void setStartRecordingRequested(boolean startRecordingRequested) {
+ SoftPreconditions.checkState(!mStopRecordingRequested);
+ mStartRecordingRequested = startRecordingRequested;
+ }
+
+ /**
+ * Sets the recording schedule.
+ */
+ public void setSchedule(@Nullable ScheduledRecording schedule) {
+ mSchedule = schedule;
+ }
+
+ /**
+ * Returns the channel ID.
+ */
+ public long getChannelId() {
+ return mSchedule != null ? mSchedule.getChannelId() : -1;
+ }
+
+ /**
+ * Returns the start time.
+ */
+ public long getStartTimeMs() {
+ return mSchedule != null ? mSchedule.getStartTimeMs() : -1;
+ }
+
+ /**
+ * Returns the end time.
+ */
+ public long getEndTimeMs() {
+ return mSchedule != null ? mSchedule.getEndTimeMs() : -1;
+ }
+
+ /**
+ * Returns the duration.
+ */
+ public final long getDuration() {
+ return getEndTimeMs() - getStartTimeMs();
+ }
+
+ /**
+ * Checks if the program is on air.
+ */
+ public final boolean isOnAir() {
+ long currentTimeMs = System.currentTimeMillis();
+ return getStartTimeMs() <= currentTimeMs && getEndTimeMs() > currentTimeMs;
+ }
+
+ /**
+ * Checks if the schedule is not started.
+ */
+ public final boolean isRecordingNotStarted() {
+ return mSchedule != null
+ && mSchedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED;
+ }
+
+ /**
+ * Checks if the schedule is in progress.
+ */
+ public final boolean isRecordingInProgress() {
+ return mSchedule != null
+ && mSchedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS;
+ }
+
+ /**
+ * Checks if the schedule has been canceled or not.
+ */
+ public final boolean isScheduleCanceled() {
+ return mSchedule != null
+ && mSchedule.getState() == ScheduledRecording.STATE_RECORDING_CANCELED;
+ }
+
+ public boolean isRecordingFinished() {
+ return mSchedule != null
+ && (mSchedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED
+ || mSchedule.getState() == ScheduledRecording.STATE_RECORDING_CLIPPED
+ || mSchedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED);
+ }
+
+ /**
+ * Creates and returns the new schedule with the existing information.
+ */
+ public ScheduledRecording.Builder createNewScheduleBuilder() {
+ return mSchedule != null ? ScheduledRecording.buildFrom(mSchedule) : null;
+ }
+
+ /**
+ * Returns the program title with episode number.
+ */
+ public String getProgramTitleWithEpisodeNumber(Context context) {
+ return mSchedule != null ? mSchedule.getProgramTitleWithEpisodeNumber(context) : null;
+ }
+
+ /**
+ * Returns the program title including the season/episode number.
+ */
+ public String getEpisodeDisplayTitle(Context context) {
+ return mSchedule != null ? mSchedule.getEpisodeDisplayTitle(context) : null;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName()
+ + "(schedule=" + mSchedule
+ + ",stopRecordingRequested=" + mStopRecordingRequested
+ + ",startRecordingRequested=" + mStartRecordingRequested
+ + ")";
+ }
+
+ /**
+ * Checks if the {@code schedule} is for the program or channel.
+ */
+ public boolean matchSchedule(ScheduledRecording schedule) {
+ if (mSchedule == null) {
+ return false;
+ }
+ if (mSchedule.getType() == ScheduledRecording.TYPE_TIMED) {
+ return mSchedule.getChannelId() == schedule.getChannelId()
+ && mSchedule.getStartTimeMs() == schedule.getStartTimeMs()
+ && mSchedule.getEndTimeMs() == schedule.getEndTimeMs();
+ } else {
+ return mSchedule.getProgramId() == schedule.getProgramId();
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
new file mode 100644
index 00000000..9cc82653
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
@@ -0,0 +1,425 @@
+/*
+ * 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.list;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.text.format.DateUtils;
+import android.util.ArraySet;
+import android.util.Log;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow;
+import com.android.tv.util.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * An adapter for {@link ScheduleRow}.
+ */
+public class ScheduleRowAdapter extends ArrayObjectAdapter {
+ private static final String TAG = "ScheduleRowAdapter";
+ private static final boolean DEBUG = false;
+
+ private final static long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
+
+ private static final int MSG_UPDATE_ROW = 1;
+
+ private Context mContext;
+ private final List<String> mTitles = new ArrayList<>();
+ private final Set<ScheduleRow> mPendingUpdate = new ArraySet<>();
+
+ private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_UPDATE_ROW) {
+ long currentTimeMs = System.currentTimeMillis();
+ handleUpdateRow(currentTimeMs);
+ sendNextUpdateMessage(currentTimeMs);
+ }
+ }
+ };
+
+ public ScheduleRowAdapter(Context context, ClassPresenterSelector classPresenterSelector) {
+ super(classPresenterSelector);
+ mContext = context;
+ mTitles.add(mContext.getString(R.string.dvr_date_today));
+ mTitles.add(mContext.getString(R.string.dvr_date_tomorrow));
+ }
+
+ /**
+ * Returns context.
+ */
+ protected Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Starts schedule row adapter.
+ */
+ public void start() {
+ clear();
+ List<ScheduledRecording> recordingList = TvApplication.getSingletons(mContext)
+ .getDvrDataManager().getNonStartedScheduledRecordings();
+ recordingList.addAll(TvApplication.getSingletons(mContext).getDvrDataManager()
+ .getStartedRecordings());
+ Collections.sort(recordingList,
+ ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR);
+ long deadLine = Utils.getLastMillisecondOfDay(System.currentTimeMillis());
+ for (int i = 0; i < recordingList.size();) {
+ ArrayList<ScheduledRecording> section = new ArrayList<>();
+ while (i < recordingList.size() && recordingList.get(i).getStartTimeMs() < deadLine) {
+ section.add(recordingList.get(i++));
+ }
+ if (!section.isEmpty()) {
+ SchedulesHeaderRow headerRow = new DateHeaderRow(calculateHeaderDate(deadLine),
+ mContext.getResources().getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle, section.size(), section.size()),
+ section.size(), deadLine);
+ add(headerRow);
+ for(ScheduledRecording recording : section){
+ add(new ScheduleRow(recording, headerRow));
+ }
+ }
+ deadLine += ONE_DAY_MS;
+ }
+ sendNextUpdateMessage(System.currentTimeMillis());
+ }
+
+ private String calculateHeaderDate(long deadLine) {
+ int titleIndex = (int) ((deadLine -
+ Utils.getLastMillisecondOfDay(System.currentTimeMillis())) / ONE_DAY_MS);
+ String headerDate;
+ if (titleIndex < mTitles.size()) {
+ headerDate = mTitles.get(titleIndex);
+ } else {
+ headerDate = DateUtils.formatDateTime(getContext(), deadLine,
+ DateUtils.FORMAT_SHOW_WEEKDAY | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_ABBREV_MONTH);
+ }
+ return headerDate;
+ }
+
+ /**
+ * Stops schedules row adapter.
+ */
+ public void stop() {
+ mHandler.removeCallbacksAndMessages(null);
+ DvrManager dvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
+ for (int i = 0; i < size(); i++) {
+ if (get(i) instanceof ScheduleRow) {
+ ScheduleRow row = (ScheduleRow) get(i);
+ if (row.isScheduleCanceled()) {
+ dvrManager.removeScheduledRecording(row.getSchedule());
+ }
+ }
+ }
+ }
+
+ /**
+ * Gets which {@link ScheduleRow} the {@link ScheduledRecording} belongs to.
+ */
+ public ScheduleRow findRowByScheduledRecording(ScheduledRecording recording) {
+ if (recording == null) {
+ return null;
+ }
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow && ((ScheduleRow) item).getSchedule() != null) {
+ if (((ScheduleRow) item).getSchedule().getId() == recording.getId()) {
+ return (ScheduleRow) item;
+ }
+ }
+ }
+ return null;
+ }
+
+ private ScheduleRow findRowWithStartRequest(ScheduledRecording schedule) {
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (!(item instanceof ScheduleRow)) {
+ continue;
+ }
+ ScheduleRow row = (ScheduleRow) item;
+ if (row.getSchedule() != null && row.isStartRecordingRequested()
+ && row.matchSchedule(schedule)) {
+ return row;
+ }
+ }
+ return null;
+ }
+
+ private void addScheduleRow(ScheduledRecording recording) {
+ // This method must not be called from inherited class.
+ SoftPreconditions.checkState(getClass().equals(ScheduleRowAdapter.class));
+ if (recording != null) {
+ int pre = -1;
+ int index = 0;
+ for (; index < size(); index++) {
+ if (get(index) instanceof ScheduleRow) {
+ ScheduleRow scheduleRow = (ScheduleRow) get(index);
+ if (ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.compare(
+ scheduleRow.getSchedule(), recording) > 0) {
+ break;
+ }
+ pre = index;
+ }
+ }
+ long deadLine = Utils.getLastMillisecondOfDay(recording.getStartTimeMs());
+ if (pre >= 0 && getHeaderRow(pre).getDeadLineMs() == deadLine) {
+ SchedulesHeaderRow headerRow = ((ScheduleRow) get(pre)).getHeaderRow();
+ headerRow.setItemCount(headerRow.getItemCount() + 1);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(++pre, addedRow);
+ updateHeaderDescription(headerRow);
+ } else if (index < size() && getHeaderRow(index).getDeadLineMs() == deadLine) {
+ SchedulesHeaderRow headerRow = ((ScheduleRow) get(index)).getHeaderRow();
+ headerRow.setItemCount(headerRow.getItemCount() + 1);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(index, addedRow);
+ updateHeaderDescription(headerRow);
+ } else {
+ SchedulesHeaderRow headerRow = new DateHeaderRow(calculateHeaderDate(deadLine),
+ mContext.getResources().getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle, 1, 1), 1, deadLine);
+ add(++pre, headerRow);
+ ScheduleRow addedRow = new ScheduleRow(recording, headerRow);
+ add(pre, addedRow);
+ }
+ }
+ }
+
+ private DateHeaderRow getHeaderRow(int index) {
+ return ((DateHeaderRow) ((ScheduleRow) get(index)).getHeaderRow());
+ }
+
+ private void removeScheduleRow(ScheduleRow scheduleRow) {
+ // This method must not be called from inherited class.
+ SoftPreconditions.checkState(getClass().equals(ScheduleRowAdapter.class));
+ if (scheduleRow != null) {
+ scheduleRow.setSchedule(null);
+ SchedulesHeaderRow headerRow = scheduleRow.getHeaderRow();
+ remove(scheduleRow);
+ // Changes the count information of header which the removed row belongs to.
+ if (headerRow != null) {
+ int currentCount = headerRow.getItemCount();
+ headerRow.setItemCount(--currentCount);
+ if (headerRow.getItemCount() == 0) {
+ remove(headerRow);
+ } else {
+ replace(indexOf(headerRow), headerRow);
+ updateHeaderDescription(headerRow);
+ }
+ }
+ }
+ }
+
+ private void updateHeaderDescription(SchedulesHeaderRow headerRow) {
+ headerRow.setDescription(mContext.getResources().getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle,
+ headerRow.getItemCount(), headerRow.getItemCount()));
+ }
+
+ /**
+ * Called when a schedule recording is added to dvr date manager.
+ */
+ public void onScheduledRecordingAdded(ScheduledRecording schedule) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingAdded: " + schedule);
+ ScheduleRow row = findRowWithStartRequest(schedule);
+ // If the start recording is requested, onScheduledRecordingAdded is called with NOT_STARTED
+ // state. And then onScheduleRecordingUpdated will be called with IN_PROGRESS.
+ // It happens in a short time and causes blinking. To avoid this intermediate state change,
+ // update the row in onScheduleRecordingUpdated when the state changes to IN_PROGRESS
+ // instead of in this method.
+ if (row == null) {
+ addScheduleRow(schedule);
+ sendNextUpdateMessage(System.currentTimeMillis());
+ }
+ }
+
+ /**
+ * Called when a schedule recording is removed from dvr date manager.
+ */
+ public void onScheduledRecordingRemoved(ScheduledRecording schedule) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingRemoved: " + schedule);
+ ScheduleRow row = findRowByScheduledRecording(schedule);
+ if (row != null) {
+ removeScheduleRow(row);
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ sendNextUpdateMessage(System.currentTimeMillis());
+ }
+ }
+
+ /**
+ * Called when a schedule recording is updated in dvr date manager.
+ */
+ public void onScheduledRecordingUpdated(ScheduledRecording schedule, boolean conflictChange) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingUpdated: " + schedule);
+ ScheduleRow row = findRowByScheduledRecording(schedule);
+ if (row != null) {
+ if (conflictChange && isStartOrStopRequested()) {
+ // Delay the conflict update until it gets the response of the start/stop request.
+ // The purpose is to avoid the intermediate conflict change.
+ addPendingUpdate(row);
+ return;
+ }
+ if (row.isStopRecordingRequested()) {
+ // Wait until the recording is finished
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_CLIPPED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED) {
+ row.setStopRecordingRequested(false);
+ if (!isStartOrStopRequested()) {
+ executePendingUpdate();
+ }
+ row.setSchedule(schedule);
+ }
+ } else {
+ row.setSchedule(schedule);
+ if (!willBeKept(schedule)) {
+ removeScheduleRow(row);
+ }
+ }
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ sendNextUpdateMessage(System.currentTimeMillis());
+ } else {
+ row = findRowWithStartRequest(schedule);
+ // When the start recording was requested, we give the highest priority. So it is
+ // guaranteed that the state will be changed from NOT_STARTED to the other state.
+ // Update the row with the next state not to show the intermediate state which causes
+ // blinking.
+ if (row != null
+ && schedule.getState() != ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ // This can be called multiple times, so do not call
+ // ScheduleRow.setStartRecordingRequested(false) here.
+ row.setStartRecordingRequested(false);
+ if (!isStartOrStopRequested()) {
+ executePendingUpdate();
+ }
+ row.setSchedule(schedule);
+ notifyArrayItemRangeChanged(indexOf(row), 1);
+ sendNextUpdateMessage(System.currentTimeMillis());
+ }
+ }
+ }
+
+ /**
+ * Checks if there is a row which requested start/stop recording.
+ */
+ protected boolean isStartOrStopRequested() {
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow) {
+ ScheduleRow row = (ScheduleRow) item;
+ if (row.isStartRecordingRequested() || row.isStopRecordingRequested()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Delays update of the row.
+ */
+ protected void addPendingUpdate(ScheduleRow row) {
+ mPendingUpdate.add(row);
+ }
+
+ /**
+ * Executes the pending updates.
+ */
+ protected void executePendingUpdate() {
+ for (ScheduleRow row : mPendingUpdate) {
+ int index = indexOf(row);
+ if (index != -1) {
+ notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+ mPendingUpdate.clear();
+ }
+
+ /**
+ * To check whether the recording should be kept or not.
+ */
+ protected boolean willBeKept(ScheduledRecording schedule) {
+ // CANCELED state means that the schedule was removed temporarily, which should be shown
+ // in the list so that the user can reschedule it.
+ return schedule.getEndTimeMs() > System.currentTimeMillis()
+ && (schedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_NOT_STARTED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_CANCELED);
+ }
+
+ /**
+ * Handle the message to update/remove rows.
+ */
+ protected void handleUpdateRow(long currentTimeMs) {
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow) {
+ ScheduleRow row = (ScheduleRow) item;
+ if (row.getEndTimeMs() <= currentTimeMs) {
+ removeScheduleRow(row);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the next update time. Return {@link Long#MAX_VALUE} if no timer is necessary.
+ */
+ protected long getNextTimerMs(long currentTimeMs) {
+ long earliest = Long.MAX_VALUE;
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof ScheduleRow) {
+ // If the schedule was finished earlier than the end time, it should be removed
+ // when it reaches the end time in this class.
+ ScheduleRow row = (ScheduleRow) item;
+ if (earliest > row.getEndTimeMs()) {
+ earliest = row.getEndTimeMs();
+ }
+ }
+ }
+ return earliest;
+ }
+
+ /**
+ * Send update message at the time returned by {@link #getNextTimerMs}.
+ */
+ protected final void sendNextUpdateMessage(long currentTimeMs) {
+ mHandler.removeMessages(MSG_UPDATE_ROW);
+ long nextTime = getNextTimerMs(currentTimeMs);
+ if (nextTime != Long.MAX_VALUE) {
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_ROW,
+ nextTime - System.currentTimeMillis());
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
new file mode 100644
index 00000000..1257e725
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
@@ -0,0 +1,795 @@
+/*
+ * 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.list;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.Build;
+import android.support.annotation.IntDef;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Channel;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.DvrStopRecordingFragment;
+import com.android.tv.dvr.ui.HalfSizedDialogFragment;
+import com.android.tv.util.ToastUtils;
+import com.android.tv.util.Utils;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A RowPresenter for {@link ScheduleRow}.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class ScheduleRowPresenter extends RowPresenter {
+ private static final String TAG = "ScheduleRowPresenter";
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ACTION_START_RECORDING, ACTION_STOP_RECORDING, ACTION_CREATE_SCHEDULE,
+ ACTION_REMOVE_SCHEDULE})
+ public @interface ScheduleRowAction {}
+ /** An action to start recording. */
+ public static final int ACTION_START_RECORDING = 1;
+ /** An action to stop recording. */
+ public static final int ACTION_STOP_RECORDING = 2;
+ /** An action to create schedule for the row. */
+ public static final int ACTION_CREATE_SCHEDULE = 3;
+ /** An action to remove the schedule. */
+ public static final int ACTION_REMOVE_SCHEDULE = 4;
+
+ private final Context mContext;
+ private final DvrManager mDvrManager;
+ private final DvrScheduleManager mDvrScheduleManager;
+
+ private final String mTunerConflictWillNotBeRecordedInfo;
+ private final String mTunerConflictWillBePartiallyRecordedInfo;
+ private final int mAnimationDuration;
+
+ private int mLastFocusedViewId;
+
+ /**
+ * A ViewHolder for {@link ScheduleRow}
+ */
+ public static class ScheduleRowViewHolder extends RowPresenter.ViewHolder {
+ private ScheduleRowPresenter mPresenter;
+ @ScheduleRowAction private int[] mActions;
+ private boolean mLtr;
+ private LinearLayout mInfoContainer;
+ // The first action is on the right of the second action.
+ private RelativeLayout mSecondActionContainer;
+ private RelativeLayout mFirstActionContainer;
+ private View mSelectorView;
+ private TextView mTimeView;
+ private TextView mProgramTitleView;
+ private TextView mInfoSeparatorView;
+ private TextView mChannelNameView;
+ private TextView mConflictInfoView;
+ private ImageView mSecondActionView;
+ private ImageView mFirstActionView;
+
+ private Runnable mPendingAnimationRunnable;
+
+ private final int mSelectorTranslationDelta;
+ private final int mSelectorWidthDelta;
+ private final int mInfoContainerTargetWidthWithNoAction;
+ private final int mInfoContainerTargetWidthWithOneAction;
+ private final int mInfoContainerTargetWidthWithTwoAction;
+ private final int mRoundRectRadius;
+
+ private final OnFocusChangeListener mOnFocusChangeListener =
+ new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View view, boolean focused) {
+ view.post(new Runnable() {
+ @Override
+ public void run() {
+ if (view.isFocused()) {
+ mPresenter.mLastFocusedViewId = view.getId();
+ }
+ updateSelector();
+ }
+ });
+ }
+ };
+
+ public ScheduleRowViewHolder(View view, ScheduleRowPresenter presenter) {
+ super(view);
+ mPresenter = presenter;
+ mLtr = view.getContext().getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_LTR;
+ mInfoContainer = (LinearLayout) view.findViewById(R.id.info_container);
+ mSecondActionContainer = (RelativeLayout) view.findViewById(
+ R.id.action_second_container);
+ mSecondActionView = (ImageView) view.findViewById(R.id.action_second);
+ mFirstActionContainer = (RelativeLayout) view.findViewById(
+ R.id.action_first_container);
+ mFirstActionView = (ImageView) view.findViewById(R.id.action_first);
+ mSelectorView = view.findViewById(R.id.selector);
+ mTimeView = (TextView) view.findViewById(R.id.time);
+ mProgramTitleView = (TextView) view.findViewById(R.id.program_title);
+ mInfoSeparatorView = (TextView) view.findViewById(R.id.info_separator);
+ mChannelNameView = (TextView) view.findViewById(R.id.channel_name);
+ mConflictInfoView = (TextView) view.findViewById(R.id.conflict_info);
+ Resources res = view.getResources();
+ mSelectorTranslationDelta =
+ res.getDimensionPixelSize(R.dimen.dvr_schedules_item_section_margin)
+ - res.getDimensionPixelSize(R.dimen.dvr_schedules_item_focus_translation_delta);
+ mSelectorWidthDelta = res.getDimensionPixelSize(
+ R.dimen.dvr_schedules_item_focus_width_delta);
+ mRoundRectRadius = res.getDimensionPixelSize(R.dimen.dvr_schedules_selector_radius);
+ int fullWidth = res.getDimensionPixelSize(
+ R.dimen.dvr_schedules_item_width)
+ - 2 * res.getDimensionPixelSize(R.dimen.dvr_schedules_layout_padding);
+ mInfoContainerTargetWidthWithNoAction = fullWidth + 2 * mRoundRectRadius;
+ mInfoContainerTargetWidthWithOneAction = fullWidth
+ - res.getDimensionPixelSize(R.dimen.dvr_schedules_item_section_margin)
+ - res.getDimensionPixelSize(R.dimen.dvr_schedules_item_delete_width)
+ + mRoundRectRadius + mSelectorWidthDelta;
+ mInfoContainerTargetWidthWithTwoAction = mInfoContainerTargetWidthWithOneAction
+ - res.getDimensionPixelSize(R.dimen.dvr_schedules_item_section_margin)
+ - res.getDimensionPixelSize(R.dimen.dvr_schedules_item_icon_size);
+
+ mInfoContainer.setOnFocusChangeListener(mOnFocusChangeListener);
+ mFirstActionContainer.setOnFocusChangeListener(mOnFocusChangeListener);
+ mSecondActionContainer.setOnFocusChangeListener(mOnFocusChangeListener);
+ }
+
+ /**
+ * Returns time view.
+ */
+ public TextView getTimeView() {
+ return mTimeView;
+ }
+
+ /**
+ * Returns title view.
+ */
+ public TextView getProgramTitleView() {
+ return mProgramTitleView;
+ }
+
+ private void updateSelector() {
+ int animationDuration = mSelectorView.getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+ DecelerateInterpolator interpolator = new DecelerateInterpolator();
+
+ if (mInfoContainer.isFocused() || mSecondActionContainer.isFocused()
+ || mFirstActionContainer.isFocused()) {
+ final ViewGroup.LayoutParams lp = mSelectorView.getLayoutParams();
+ final int targetWidth;
+ if (mInfoContainer.isFocused()) {
+ // Use actions to check the visibility of the actions instead of calling
+ // View.getVisibility() because the view could be on the hiding animation.
+ if (mActions == null || mActions.length == 0) {
+ targetWidth = mInfoContainerTargetWidthWithNoAction;
+ } else if (mActions.length == 1) {
+ targetWidth = mInfoContainerTargetWidthWithOneAction;
+ } else {
+ targetWidth = mInfoContainerTargetWidthWithTwoAction;
+ }
+ } else if (mSecondActionContainer.isFocused()) {
+ targetWidth = Math.max(mSecondActionContainer.getWidth(), 2 * mRoundRectRadius);
+ } else {
+ targetWidth = mFirstActionContainer.getWidth() + mRoundRectRadius
+ + mSelectorTranslationDelta;
+ }
+
+ float targetTranslationX;
+ if (mInfoContainer.isFocused()) {
+ targetTranslationX = mLtr ? mInfoContainer.getLeft() - mRoundRectRadius
+ - mSelectorView.getLeft() :
+ mInfoContainer.getRight() + mRoundRectRadius - mSelectorView.getRight();
+ } else if (mSecondActionContainer.isFocused()) {
+ if (mSecondActionContainer.getWidth() > 2 * mRoundRectRadius) {
+ targetTranslationX = mLtr ? mSecondActionContainer.getLeft() -
+ mSelectorView.getLeft()
+ : mSecondActionContainer.getRight() - mSelectorView.getRight();
+ } else {
+ targetTranslationX = mLtr ? mSecondActionContainer.getLeft() -
+ (mRoundRectRadius - mSecondActionContainer.getWidth() / 2) -
+ mSelectorView.getLeft()
+ : mSecondActionContainer.getRight() +
+ (mRoundRectRadius - mSecondActionContainer.getWidth() / 2) -
+ mSelectorView.getRight();
+ }
+ } else {
+ targetTranslationX = mLtr ? mFirstActionContainer.getLeft()
+ - mSelectorTranslationDelta - mSelectorView.getLeft()
+ : mFirstActionContainer.getRight() + mSelectorTranslationDelta
+ - mSelectorView.getRight();
+ }
+
+ if (mSelectorView.getAlpha() == 0) {
+ mSelectorView.setTranslationX(targetTranslationX);
+ lp.width = targetWidth;
+ mSelectorView.requestLayout();
+ }
+
+ // animate the selector in and to the proper width and translation X.
+ final float deltaWidth = lp.width - targetWidth;
+ mSelectorView.animate().cancel();
+ mSelectorView.animate().translationX(targetTranslationX).alpha(1f)
+ .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // Set width to the proper width for this animation step.
+ lp.width = targetWidth + Math.round(
+ deltaWidth * (1f - animation.getAnimatedFraction()));
+ mSelectorView.requestLayout();
+ }
+ }).setDuration(animationDuration).setInterpolator(interpolator).start();
+ if (mPendingAnimationRunnable != null) {
+ mPendingAnimationRunnable.run();
+ mPendingAnimationRunnable = null;
+ }
+ } else {
+ mSelectorView.animate().cancel();
+ mSelectorView.animate().alpha(0f).setDuration(animationDuration)
+ .setInterpolator(interpolator).setUpdateListener(null).start();
+ }
+ }
+
+ /**
+ * Grey out the information body.
+ */
+ public void greyOutInfo() {
+ mTimeView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info_grey, null));
+ mProgramTitleView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info_grey, null));
+ mInfoSeparatorView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info_grey, null));
+ mChannelNameView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info_grey, null));
+ mConflictInfoView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info_grey, null));
+ }
+
+ /**
+ * Reverse grey out operation.
+ */
+ public void whiteBackInfo() {
+ mTimeView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info, null));
+ mProgramTitleView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_main, null));
+ mInfoSeparatorView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info, null));
+ mChannelNameView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info, null));
+ mConflictInfoView.setTextColor(mInfoContainer.getResources().getColor(R.color
+ .dvr_schedules_item_info, null));
+ }
+ }
+
+ public ScheduleRowPresenter(Context context) {
+ setHeaderPresenter(null);
+ setSelectEffectEnabled(false);
+ mContext = context;
+ 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 = mContext.getString(
+ R.string.dvr_schedules_tuner_conflict_will_be_partially_recorded);
+ mAnimationDuration = mContext.getResources().getInteger(
+ android.R.integer.config_shortAnimTime);
+ }
+
+ @Override
+ public ViewHolder createRowViewHolder(ViewGroup parent) {
+ return onGetScheduleRowViewHolder(LayoutInflater.from(mContext)
+ .inflate(R.layout.dvr_schedules_item, parent, false));
+ }
+
+ /**
+ * Returns context.
+ */
+ protected Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns DVR manager.
+ */
+ protected DvrManager getDvrManager() {
+ return mDvrManager;
+ }
+
+ @Override
+ protected void onBindRowViewHolder(RowPresenter.ViewHolder vh, Object item) {
+ super.onBindRowViewHolder(vh, item);
+ ScheduleRowViewHolder viewHolder = (ScheduleRowViewHolder) vh;
+ ScheduleRow row = (ScheduleRow) item;
+ @ScheduleRowAction int[] actions = getAvailableActions(row);
+ viewHolder.mActions = actions;
+ viewHolder.mInfoContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onInfoClicked(row);
+ }
+ });
+
+ viewHolder.mFirstActionContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onActionClicked(actions[0], row);
+ }
+ });
+
+ viewHolder.mSecondActionContainer.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ onActionClicked(actions[1], row);
+ }
+ });
+
+ viewHolder.mTimeView.setText(onGetRecordingTimeText(row));
+ String programInfoText = onGetProgramInfoText(row);
+ if (TextUtils.isEmpty(programInfoText)) {
+ int durationMins =
+ Math.max((int) TimeUnit.MILLISECONDS.toMinutes(row.getDuration()), 1);
+ programInfoText = mContext.getResources().getQuantityString(
+ R.plurals.dvr_schedules_recording_duration, durationMins, durationMins);
+ }
+ String channelName = getChannelNameText(row);
+ viewHolder.mProgramTitleView.setText(programInfoText);
+ viewHolder.mInfoSeparatorView.setVisibility((!TextUtils.isEmpty(programInfoText)
+ && !TextUtils.isEmpty(channelName)) ? View.VISIBLE : View.GONE);
+ viewHolder.mChannelNameView.setText(channelName);
+ if (actions != null) {
+ switch (actions.length) {
+ case 2:
+ viewHolder.mSecondActionView.setImageResource(getImageForAction(actions[1]));
+ // pass through
+ case 1:
+ viewHolder.mFirstActionView.setImageResource(getImageForAction(actions[0]));
+ break;
+ }
+ }
+ if (mDvrManager.isConflicting(row.getSchedule())) {
+ String conflictInfo;
+ if (mDvrScheduleManager.isPartiallyConflicting(row.getSchedule())) {
+ conflictInfo = mTunerConflictWillBePartiallyRecordedInfo;
+ } else {
+ conflictInfo = mTunerConflictWillNotBeRecordedInfo;
+ }
+ viewHolder.mConflictInfoView.setText(conflictInfo);
+ viewHolder.mConflictInfoView.setVisibility(View.VISIBLE);
+ } else {
+ viewHolder.mConflictInfoView.setVisibility(View.GONE);
+ }
+ if (shouldBeGrayedOut(row)) {
+ viewHolder.greyOutInfo();
+ } else {
+ viewHolder.whiteBackInfo();
+ }
+ updateActionContainer(viewHolder, viewHolder.isSelected());
+ }
+
+ private int getImageForAction(@ScheduleRowAction int action) {
+ switch (action) {
+ case ACTION_START_RECORDING:
+ return R.drawable.ic_record_start;
+ case ACTION_STOP_RECORDING:
+ return R.drawable.ic_record_stop;
+ case ACTION_CREATE_SCHEDULE:
+ return R.drawable.ic_scheduled_recording;
+ case ACTION_REMOVE_SCHEDULE:
+ return R.drawable.ic_dvr_cancel;
+ default:
+ return 0;
+ }
+ }
+
+ /**
+ * Returns view holder for schedule row.
+ */
+ protected ScheduleRowViewHolder onGetScheduleRowViewHolder(View view) {
+ return new ScheduleRowViewHolder(view, this);
+ }
+
+ /**
+ * Returns time text for time view from scheduled recording.
+ */
+ protected String onGetRecordingTimeText(ScheduleRow row) {
+ return Utils.getDurationString(mContext, row.getStartTimeMs(), row.getEndTimeMs(), true,
+ false, true, 0);
+ }
+
+ /**
+ * Returns program info text for program title view.
+ */
+ protected String onGetProgramInfoText(ScheduleRow row) {
+ return row.getProgramTitleWithEpisodeNumber(mContext);
+ }
+
+ private String getChannelNameText(ScheduleRow row) {
+ Channel channel = TvApplication.getSingletons(mContext).getChannelDataManager()
+ .getChannel(row.getChannelId());
+ return channel == null ? null :
+ TextUtils.isEmpty(channel.getDisplayName()) ? channel.getDisplayNumber() :
+ channel.getDisplayName().trim() + " " + channel.getDisplayNumber();
+ }
+
+ /**
+ * Called when user click Info in {@link ScheduleRow}.
+ */
+ protected void onInfoClicked(ScheduleRow scheduleRow) {
+ ScheduledRecording schedule = scheduleRow.getSchedule();
+ if (schedule != null) {
+ DvrUiHelper.startDetailsActivity((Activity) mContext, schedule, null, true);
+ }
+ }
+
+ /**
+ * Called when the button in a row is clicked.
+ */
+ protected void onActionClicked(@ScheduleRowAction final int action, ScheduleRow row) {
+ switch (action) {
+ case ACTION_START_RECORDING:
+ onStartRecording(row);
+ break;
+ case ACTION_STOP_RECORDING:
+ onStopRecording(row);
+ break;
+ case ACTION_CREATE_SCHEDULE:
+ onCreateSchedule(row);
+ break;
+ case ACTION_REMOVE_SCHEDULE:
+ onRemoveSchedule(row);
+ break;
+ }
+ }
+
+ /**
+ * Action handler for {@link #ACTION_START_RECORDING}.
+ */
+ protected void onStartRecording(ScheduleRow row) {
+ ScheduledRecording schedule = row.getSchedule();
+ if (schedule == null) {
+ // This row has been deleted.
+ return;
+ }
+ // Checks if there are current recordings that will be stopped by schedule this program.
+ // If so, shows confirmation dialog to users.
+ List<ScheduledRecording> conflictSchedules = mDvrScheduleManager.getConflictingSchedules(
+ schedule.getChannelId(), System.currentTimeMillis(), schedule.getEndTimeMs());
+ for (int i = conflictSchedules.size() - 1; i >= 0; i--) {
+ ScheduledRecording conflictSchedule = conflictSchedules.get(i);
+ if (conflictSchedule.isInProgress()) {
+ DvrUiHelper.showStopRecordingDialog((Activity) mContext,
+ conflictSchedule.getChannelId(),
+ DvrStopRecordingFragment.REASON_ON_CONFLICT,
+ new HalfSizedDialogFragment.OnActionClickListener() {
+ @Override
+ public void onActionClick(long actionId) {
+ if (actionId == DvrStopRecordingFragment.ACTION_STOP) {
+ onStartRecordingInternal(row);
+ }
+ }
+ });
+ return;
+ }
+ }
+ onStartRecordingInternal(row);
+ }
+
+ private void onStartRecordingInternal(ScheduleRow row) {
+ if (row.isOnAir() && !row.isRecordingInProgress() && !row.isStartRecordingRequested()) {
+ row.setStartRecordingRequested(true);
+ if (row.isRecordingNotStarted()) {
+ mDvrManager.setHighestPriority(row.getSchedule());
+ } else if (row.isRecordingFinished()) {
+ mDvrManager.addSchedule(ScheduledRecording.buildFrom(row.getSchedule())
+ .setId(ScheduledRecording.ID_NOT_SET)
+ .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED)
+ .setPriority(mDvrManager.suggestHighestPriority(row.getSchedule()))
+ .build());
+ } else {
+ SoftPreconditions.checkState(false, TAG, "Invalid row state to start recording: "
+ + row);
+ return;
+ }
+ String msg = mContext.getString(R.string.dvr_msg_current_program_scheduled,
+ row.getSchedule().getProgramTitle(),
+ Utils.toTimeString(row.getEndTimeMs(), false));
+ ToastUtils.show(mContext, msg, Toast.LENGTH_SHORT);
+ }
+ }
+
+ /**
+ * Action handler for {@link #ACTION_STOP_RECORDING}.
+ */
+ protected void onStopRecording(ScheduleRow row) {
+ if (row.getSchedule() == null) {
+ // This row has been deleted.
+ return;
+ }
+ if (row.isOnAir() && row.isRecordingInProgress() && !row.isStopRecordingRequested()) {
+ row.setStopRecordingRequested(true);
+ mDvrManager.stopRecording(row.getSchedule());
+ CharSequence deletedInfo = onGetProgramInfoText(row);
+ if (TextUtils.isEmpty(deletedInfo)) {
+ deletedInfo = getChannelNameText(row);
+ }
+ ToastUtils.show(mContext, mContext.getResources()
+ .getString(R.string.dvr_schedules_deletion_info, deletedInfo),
+ Toast.LENGTH_SHORT);
+ }
+ }
+
+ /**
+ * Action handler for {@link #ACTION_CREATE_SCHEDULE}.
+ */
+ protected void onCreateSchedule(ScheduleRow row) {
+ if (row.getSchedule() == null) {
+ // This row has been deleted.
+ return;
+ }
+ if (!row.isOnAir()) {
+ if (row.isScheduleCanceled()) {
+ mDvrManager.updateScheduledRecording(ScheduledRecording.buildFrom(row.getSchedule())
+ .setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED)
+ .setPriority(mDvrManager.suggestHighestPriority(row.getSchedule()))
+ .build());
+ String msg = mContext.getString(R.string.dvr_msg_program_scheduled,
+ row.getSchedule().getProgramTitle());
+ ToastUtils.show(mContext, msg, Toast.LENGTH_SHORT);
+ } else if (mDvrManager.isConflicting(row.getSchedule())) {
+ mDvrManager.setHighestPriority(row.getSchedule());
+ }
+ }
+ }
+
+ /**
+ * Action handler for {@link #ACTION_REMOVE_SCHEDULE}.
+ */
+ protected void onRemoveSchedule(ScheduleRow row) {
+ if (row.getSchedule() == null) {
+ // This row has been deleted.
+ return;
+ }
+ CharSequence deletedInfo = null;
+ if (row.isOnAir()) {
+ if (row.isRecordingNotStarted()) {
+ deletedInfo = getDeletedInfo(row);
+ mDvrManager.removeScheduledRecording(row.getSchedule());
+ }
+ } else {
+ if (mDvrManager.isConflicting(row.getSchedule())
+ && !shouldKeepScheduleAfterRemoving()) {
+ deletedInfo = getDeletedInfo(row);
+ mDvrManager.removeScheduledRecording(row.getSchedule());
+ } else if (row.isRecordingNotStarted()) {
+ deletedInfo = getDeletedInfo(row);
+ mDvrManager.updateScheduledRecording(ScheduledRecording.buildFrom(row.getSchedule())
+ .setState(ScheduledRecording.STATE_RECORDING_CANCELED)
+ .build());
+ }
+ }
+ if (deletedInfo != null) {
+ ToastUtils.show(mContext, mContext.getResources()
+ .getString(R.string.dvr_schedules_deletion_info, deletedInfo),
+ Toast.LENGTH_SHORT);
+ }
+ }
+
+ private CharSequence getDeletedInfo(ScheduleRow row) {
+ CharSequence deletedInfo = onGetProgramInfoText(row);
+ if (TextUtils.isEmpty(deletedInfo)) {
+ return getChannelNameText(row);
+ }
+ return deletedInfo;
+ }
+
+ @Override
+ protected void onRowViewSelected(ViewHolder vh, boolean selected) {
+ super.onRowViewSelected(vh, selected);
+ updateActionContainer(vh, selected);
+ }
+
+ /**
+ * Internal method for onRowViewSelected, can be customized by subclass.
+ */
+ private void updateActionContainer(ViewHolder vh, boolean selected) {
+ ScheduleRowViewHolder viewHolder = (ScheduleRowViewHolder) vh;
+ viewHolder.mSecondActionContainer.animate().setListener(null).cancel();
+ viewHolder.mFirstActionContainer.animate().setListener(null).cancel();
+ if (selected && viewHolder.mActions != null) {
+ switch (viewHolder.mActions.length) {
+ case 2:
+ prepareShowActionView(viewHolder.mSecondActionContainer);
+ prepareShowActionView(viewHolder.mFirstActionContainer);
+ viewHolder.mPendingAnimationRunnable = new Runnable() {
+ @Override
+ public void run() {
+ showActionView(viewHolder.mSecondActionContainer);
+ showActionView(viewHolder.mFirstActionContainer);
+ }
+ };
+ break;
+ case 1:
+ prepareShowActionView(viewHolder.mFirstActionContainer);
+ viewHolder.mPendingAnimationRunnable = new Runnable() {
+ @Override
+ public void run() {
+ hideActionView(viewHolder.mSecondActionContainer, View.GONE);
+ showActionView(viewHolder.mFirstActionContainer);
+ }
+ };
+ if (mLastFocusedViewId == R.id.action_second_container) {
+ mLastFocusedViewId = R.id.info_container;
+ }
+ break;
+ case 0:
+ default:
+ viewHolder.mPendingAnimationRunnable = new Runnable() {
+ @Override
+ public void run() {
+ hideActionView(viewHolder.mSecondActionContainer, View.GONE);
+ hideActionView(viewHolder.mFirstActionContainer, View.GONE);
+ }
+ };
+ if (mLastFocusedViewId == R.id.action_first_container
+ || mLastFocusedViewId == R.id.action_second_container) {
+ mLastFocusedViewId = R.id.info_container;
+ }
+ break;
+ }
+ View view = viewHolder.view.findViewById(mLastFocusedViewId);
+ if (view != null && view.getVisibility() == View.VISIBLE) {
+ // When the row is selected, information container gets the initial focus.
+ // To give the focus to the same control as the previous row, we need to call
+ // requestFocus() explicitly.
+ if (view.hasFocus()) {
+ viewHolder.mPendingAnimationRunnable.run();
+ } else {
+ view.requestFocus();
+ }
+ }
+ } else {
+ viewHolder.mPendingAnimationRunnable = null;
+ hideActionView(viewHolder.mFirstActionContainer, View.GONE);
+ hideActionView(viewHolder.mSecondActionContainer, View.GONE);
+ }
+ }
+
+ private void prepareShowActionView(View view) {
+ if (view.getVisibility() != View.VISIBLE) {
+ view.setAlpha(0.0f);
+ }
+ view.setVisibility(View.VISIBLE);
+ }
+
+ /**
+ * Add animation when view is visible.
+ */
+ private void showActionView(View view) {
+ view.animate().alpha(1.0f).setInterpolator(new DecelerateInterpolator())
+ .setDuration(mAnimationDuration).start();
+ }
+
+ /**
+ * Add animation when view change to invisible.
+ */
+ private void hideActionView(View view, int visibility) {
+ if (view.getVisibility() != View.VISIBLE) {
+ if (view.getVisibility() != visibility) {
+ view.setVisibility(visibility);
+ }
+ return;
+ }
+ view.animate().alpha(0.0f).setInterpolator(new DecelerateInterpolator())
+ .setDuration(mAnimationDuration)
+ .setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setVisibility(visibility);
+ view.animate().setListener(null);
+ }
+ }).start();
+ }
+
+ /**
+ * Returns the available actions according to the row's state. It should be the reverse order
+ * with that in the screen.
+ */
+ @ScheduleRowAction
+ protected int[] getAvailableActions(ScheduleRow row) {
+ if (row.getSchedule() != null) {
+ if (row.isOnAir()) {
+ if (row.isRecordingInProgress()) {
+ return new int[] {ACTION_STOP_RECORDING};
+ } else if (row.isRecordingNotStarted()) {
+ if (canResolveConflict()) {
+ // The "START" action can change the conflict states.
+ return new int[] {ACTION_REMOVE_SCHEDULE, ACTION_START_RECORDING};
+ } else {
+ return new int[] {ACTION_REMOVE_SCHEDULE};
+ }
+ } else if (row.isRecordingFinished()) {
+ return new int[] {ACTION_START_RECORDING};
+ } else {
+ SoftPreconditions.checkState(false, TAG, "Invalid row state in checking the"
+ + " available actions(on air): " + row);
+ }
+ } else {
+ if (row.isScheduleCanceled()) {
+ return new int[] {ACTION_CREATE_SCHEDULE};
+ } else if (mDvrManager.isConflicting(row.getSchedule()) && canResolveConflict()) {
+ return new int[] {ACTION_REMOVE_SCHEDULE, ACTION_CREATE_SCHEDULE};
+ } else if (row.isRecordingNotStarted()) {
+ return new int[] {ACTION_REMOVE_SCHEDULE};
+ } else {
+ SoftPreconditions.checkState(false, TAG, "Invalid row state in checking the"
+ + " available actions(future schedule): " + row);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Check if the conflict can be resolved in this screen.
+ */
+ protected boolean canResolveConflict() {
+ return true;
+ }
+
+ /**
+ * Check if the schedule should be kept after removing it.
+ */
+ protected boolean shouldKeepScheduleAfterRemoving() {
+ return false;
+ }
+
+ /**
+ * Checks if the row should be grayed out.
+ */
+ protected boolean shouldBeGrayedOut(ScheduleRow row) {
+ return row.getSchedule() == null
+ || (row.isOnAir() && !row.isRecordingInProgress())
+ || mDvrManager.isConflicting(row.getSchedule())
+ || row.isScheduleCanceled();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java
new file mode 100644
index 00000000..0fb0924d
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRow.java
@@ -0,0 +1,122 @@
+/*
+ * 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.list;
+
+import com.android.tv.dvr.SeriesRecording;
+
+/**
+ * A base class for the rows for schedules' header.
+ */
+public abstract class SchedulesHeaderRow {
+ private String mTitle;
+ private String mDescription;
+ private int mItemCount;
+
+ public SchedulesHeaderRow(String title, String description, int itemCount) {
+ mTitle = title;
+ mItemCount = itemCount;
+ mDescription = description;
+ }
+
+ /**
+ * Sets title.
+ */
+ public void setTitle(String title) {
+ mTitle = title;
+ }
+
+ /**
+ * Sets description.
+ */
+ public void setDescription(String description) {
+ mDescription = description;
+ }
+
+ /**
+ * Sets count of items.
+ */
+ public void setItemCount(int itemCount) {
+ mItemCount = itemCount;
+ }
+
+ /**
+ * Returns title.
+ */
+ public String getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns description.
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns count of items.
+ */
+ public int getItemCount() {
+ return mItemCount;
+ }
+
+ /**
+ * The header row which represent the date.
+ */
+ public static class DateHeaderRow extends SchedulesHeaderRow {
+ private long mDeadLineMs;
+
+ public DateHeaderRow(String title, String description, int itemCount, long deadLineMs) {
+ super(title, description, itemCount);
+ mDeadLineMs = deadLineMs;
+ }
+
+ /**
+ * Returns the latest time of the list which belongs to the header row.
+ */
+ public long getDeadLineMs() {
+ return mDeadLineMs;
+ }
+ }
+
+ /**
+ * The header row which represent the series recording.
+ */
+ public static class SeriesRecordingHeaderRow extends SchedulesHeaderRow {
+ private SeriesRecording mSeriesRecording;
+
+ public SeriesRecordingHeaderRow(String title, String description, int itemCount,
+ SeriesRecording series) {
+ super(title, description, itemCount);
+ mSeriesRecording = series;
+ }
+
+ /**
+ * Returns the series recording, it is for series schedules list.
+ */
+ public SeriesRecording getSeriesRecording() {
+ return mSeriesRecording;
+ }
+
+ /**
+ * Sets the series recording.
+ */
+ public void setSeriesRecording(SeriesRecording seriesRecording) {
+ mSeriesRecording = seriesRecording;
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java
new file mode 100644
index 00000000..69c33a96
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/SchedulesHeaderRowPresenter.java
@@ -0,0 +1,273 @@
+/*
+ * 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.list;
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.support.v17.leanback.widget.RowPresenter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.View.OnFocusChangeListener;
+import android.view.ViewGroup;
+import android.view.animation.DecelerateInterpolator;
+import android.widget.TextView;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.ui.DvrSchedulesActivity;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow;
+
+/**
+ * A base class for RowPresenter for {@link SchedulesHeaderRow}
+ */
+public abstract class SchedulesHeaderRowPresenter extends RowPresenter {
+ private Context mContext;
+
+ public SchedulesHeaderRowPresenter(Context context) {
+ setHeaderPresenter(null);
+ setSelectEffectEnabled(false);
+ mContext = context;
+ }
+
+ /**
+ * Returns the context.
+ */
+ Context getContext() {
+ return mContext;
+ }
+
+ /**
+ * A ViewHolder for {@link SchedulesHeaderRow}.
+ */
+ public static class SchedulesHeaderRowViewHolder extends RowPresenter.ViewHolder {
+ private TextView mTitle;
+ private TextView mDescription;
+
+ public SchedulesHeaderRowViewHolder(Context context, ViewGroup parent) {
+ super(LayoutInflater.from(context).inflate(R.layout.dvr_schedules_header, parent,
+ false));
+ mTitle = (TextView) view.findViewById(R.id.header_title);
+ mDescription = (TextView) view.findViewById(R.id.header_description);
+ }
+ }
+
+ @Override
+ protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) {
+ super.onBindRowViewHolder(viewHolder, item);
+ SchedulesHeaderRowViewHolder headerViewHolder = (SchedulesHeaderRowViewHolder) viewHolder;
+ SchedulesHeaderRow header = (SchedulesHeaderRow) item;
+ headerViewHolder.mTitle.setText(header.getTitle());
+ headerViewHolder.mDescription.setText(header.getDescription());
+ }
+
+ /**
+ * A presenter for {@link com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow}.
+ */
+ public static class DateHeaderRowPresenter extends SchedulesHeaderRowPresenter {
+ public DateHeaderRowPresenter(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ return new DateHeaderRowViewHolder(getContext(), parent);
+ }
+
+ /**
+ * A ViewHolder for
+ * {@link com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow}.
+ */
+ public static class DateHeaderRowViewHolder extends SchedulesHeaderRowViewHolder {
+ public DateHeaderRowViewHolder(Context context, ViewGroup parent) {
+ super(context, parent);
+ }
+ }
+ }
+
+ /**
+ * A presenter for {@link SeriesRecordingHeaderRow}.
+ */
+ public static class SeriesRecordingHeaderRowPresenter extends SchedulesHeaderRowPresenter {
+ private final boolean mLtr;
+ private final Drawable mSettingsDrawable;
+ private final Drawable mCancelDrawable;
+ private final Drawable mResumeDrawable;
+
+ private final String mSettingsInfo;
+ private final String mCancelAllInfo;
+ private final String mResumeInfo;
+
+ public SeriesRecordingHeaderRowPresenter(Context context) {
+ super(context);
+ mLtr = context.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_LTR;
+ mSettingsDrawable = context.getDrawable(R.drawable.ic_settings);
+ mCancelDrawable = context.getDrawable(R.drawable.ic_dvr_cancel_large);
+ mResumeDrawable = context.getDrawable(R.drawable.ic_record_start);
+ mSettingsInfo = context.getString(R.string.dvr_series_schedules_settings);
+ mCancelAllInfo = context.getString(R.string.dvr_series_schedules_stop);
+ mResumeInfo = context.getString(R.string.dvr_series_schedules_start);
+ }
+
+ @Override
+ protected ViewHolder createRowViewHolder(ViewGroup parent) {
+ return new SeriesHeaderRowViewHolder(getContext(), parent);
+ }
+
+ @Override
+ protected void onBindRowViewHolder(RowPresenter.ViewHolder viewHolder, Object item) {
+ super.onBindRowViewHolder(viewHolder, item);
+ SeriesHeaderRowViewHolder headerViewHolder =
+ (SeriesHeaderRowViewHolder) viewHolder;
+ SeriesRecordingHeaderRow header = (SeriesRecordingHeaderRow) item;
+ headerViewHolder.mSeriesSettingsButton.setVisibility(
+ header.getSeriesRecording().isStopped() ? View.INVISIBLE : View.VISIBLE);
+ headerViewHolder.mSeriesSettingsButton.setText(mSettingsInfo);
+ setTextDrawable(headerViewHolder.mSeriesSettingsButton, mSettingsDrawable);
+ if (header.getSeriesRecording().isStopped()) {
+ headerViewHolder.mToggleStartStopButton.setText(mResumeInfo);
+ setTextDrawable(headerViewHolder.mToggleStartStopButton, mResumeDrawable);
+ } else {
+ headerViewHolder.mToggleStartStopButton.setText(mCancelAllInfo);
+ setTextDrawable(headerViewHolder.mToggleStartStopButton, mCancelDrawable);
+ }
+ headerViewHolder.mSeriesSettingsButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ // TODO: pass channel list for settings.
+ DvrUiHelper.startSeriesSettingsActivity(getContext(),
+ header.getSeriesRecording().getId(), null, false, false, false);
+ }
+ });
+ headerViewHolder.mToggleStartStopButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if (header.getSeriesRecording().isStopped()) {
+ // Reset priority to the highest.
+ SeriesRecording seriesRecording = SeriesRecording
+ .buildFrom(header.getSeriesRecording())
+ .setPriority(TvApplication.getSingletons(getContext())
+ .getDvrScheduleManager().suggestNewSeriesPriority())
+ .build();
+ TvApplication.getSingletons(getContext()).getDvrManager()
+ .updateSeriesRecording(seriesRecording);
+ // TODO: pass channel list for settings.
+ DvrUiHelper.startSeriesSettingsActivity(getContext(),
+ header.getSeriesRecording().getId(), null, false, false, false);
+ } else {
+ DvrUiHelper.showCancelAllSeriesRecordingDialog(
+ (DvrSchedulesActivity) view.getContext(),
+ header.getSeriesRecording());
+ }
+ }
+ });
+ }
+
+ private void setTextDrawable(TextView textView, Drawable drawableStart) {
+ if (mLtr) {
+ textView.setCompoundDrawablesWithIntrinsicBounds(drawableStart, null, null, null);
+ } else {
+ textView.setCompoundDrawablesWithIntrinsicBounds(null, null, drawableStart, null);
+ }
+ }
+
+ /**
+ * A ViewHolder for {@link SeriesRecordingHeaderRow}.
+ */
+ public static class SeriesHeaderRowViewHolder extends SchedulesHeaderRowViewHolder {
+ private final TextView mSeriesSettingsButton;
+ private final TextView mToggleStartStopButton;
+ private final boolean mLtr;
+
+ private final View mSelector;
+
+ private View mLastFocusedView;
+ public SeriesHeaderRowViewHolder(Context context, ViewGroup parent) {
+ super(context, parent);
+ mLtr = context.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_LTR;
+ view.findViewById(R.id.button_container).setVisibility(View.VISIBLE);
+ mSeriesSettingsButton = (TextView) view.findViewById(R.id.series_settings);
+ mToggleStartStopButton =
+ (TextView) view.findViewById(R.id.series_toggle_start_stop);
+ mSelector = view.findViewById(R.id.selector);
+ OnFocusChangeListener onFocusChangeListener = new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View view, boolean focused) {
+ view.post(new Runnable() {
+ @Override
+ public void run() {
+ updateSelector(view);
+ }
+ });
+ }
+ };
+ mSeriesSettingsButton.setOnFocusChangeListener(onFocusChangeListener);
+ mToggleStartStopButton.setOnFocusChangeListener(onFocusChangeListener);
+ }
+
+ private void updateSelector(View focusedView) {
+ int animationDuration = mSelector.getContext().getResources()
+ .getInteger(android.R.integer.config_shortAnimTime);
+ DecelerateInterpolator interpolator = new DecelerateInterpolator();
+
+ if (focusedView.hasFocus()) {
+ ViewGroup.LayoutParams lp = mSelector.getLayoutParams();
+ final int targetWidth = focusedView.getWidth();
+ float targetTranslationX;
+ if (mLtr) {
+ targetTranslationX = focusedView.getLeft() - mSelector.getLeft();
+ } else {
+ targetTranslationX = focusedView.getRight() - mSelector.getRight();
+ }
+
+ // if the selector is invisible, set the width and translation X directly -
+ // don't animate.
+ if (mSelector.getAlpha() == 0) {
+ mSelector.setTranslationX(targetTranslationX);
+ lp.width = targetWidth;
+ mSelector.requestLayout();
+ }
+
+ // animate the selector in and to the proper width and translation X.
+ final float deltaWidth = lp.width - targetWidth;
+ mSelector.animate().cancel();
+ mSelector.animate().translationX(targetTranslationX).alpha(1f)
+ .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ // Set width to the proper width for this animation step.
+ lp.width = targetWidth + Math.round(
+ deltaWidth * (1f - animation.getAnimatedFraction()));
+ mSelector.requestLayout();
+ }
+ }).setDuration(animationDuration).setInterpolator(interpolator).start();
+ mLastFocusedView = focusedView;
+ } else if (mLastFocusedView == focusedView) {
+ mSelector.animate().setUpdateListener(null).cancel();
+ mSelector.animate().alpha(0f).setDuration(animationDuration)
+ .setInterpolator(interpolator).start();
+ mLastFocusedView = null;
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java
new file mode 100644
index 00000000..3b493774
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowAdapter.java
@@ -0,0 +1,269 @@
+/*
+* 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.list;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.media.tv.TvInputInfo;
+import android.os.Build;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.SeriesRecording;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRow.SeriesRecordingHeaderRow;
+import com.android.tv.util.Utils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An adapter for series schedule row.
+ */
+@TargetApi(Build.VERSION_CODES.N)
+public class SeriesScheduleRowAdapter extends ScheduleRowAdapter {
+ private static final String TAG = "SeriesRowAdapter";
+ private static final boolean DEBUG = false;
+
+ private final SeriesRecording mSeriesRecording;
+ private final String mInputId;
+ private final DvrManager mDvrManager;
+ private final DvrDataManager mDataManager;
+ private final Map<Long, Program> mPrograms = new ArrayMap<>();
+ private SeriesRecordingHeaderRow mHeaderRow;
+
+ public SeriesScheduleRowAdapter(Context context, ClassPresenterSelector classPresenterSelector,
+ SeriesRecording seriesRecording) {
+ super(context, classPresenterSelector);
+ mSeriesRecording = seriesRecording;
+ TvInputInfo input = Utils.getTvInputInfoForInputId(context, mSeriesRecording.getInputId());
+ if (SoftPreconditions.checkNotNull(input) != null) {
+ mInputId = input.getId();
+ } else {
+ mInputId = null;
+ }
+ ApplicationSingletons singletons = TvApplication.getSingletons(context);
+ mDvrManager = singletons.getDvrManager();
+ mDataManager = singletons.getDvrDataManager();
+ setHasStableIds(true);
+ }
+
+ @Override
+ public void start() {
+ setPrograms(Collections.emptyList());
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ }
+
+ /**
+ * Sets the programs to show.
+ */
+ public void setPrograms(List<Program> programs) {
+ if (programs == null) {
+ programs = Collections.emptyList();
+ }
+ clear();
+ mPrograms.clear();
+ List<Program> sortedPrograms = new ArrayList<>(programs);
+ Collections.sort(sortedPrograms);
+ List<EpisodicProgramRow> rows = new ArrayList<>();
+ mHeaderRow = new SeriesRecordingHeaderRow(mSeriesRecording.getTitle(),
+ null, sortedPrograms.size(), mSeriesRecording);
+ for (Program program : sortedPrograms) {
+ ScheduledRecording schedule =
+ mDataManager.getScheduledRecordingForProgramId(program.getId());
+ if (schedule != null && !willBeKept(schedule)) {
+ schedule = null;
+ }
+ rows.add(new EpisodicProgramRow(mInputId, program, schedule, mHeaderRow));
+ mPrograms.put(program.getId(), program);
+ }
+ mHeaderRow.setDescription(getDescription());
+ add(mHeaderRow);
+ for (EpisodicProgramRow row : rows) {
+ add(row);
+ }
+ sendNextUpdateMessage(System.currentTimeMillis());
+ }
+
+ private String getDescription() {
+ int conflicts = 0;
+ for (long programId : mPrograms.keySet()) {
+ if (mDvrManager.isConflicting(
+ mDataManager.getScheduledRecordingForProgramId(programId))) {
+ ++conflicts;
+ }
+ }
+ return conflicts == 0 ? null : getContext().getResources().getQuantityString(
+ R.plurals.dvr_series_schedules_header_description, conflicts, conflicts);
+ }
+
+ @Override
+ public long getId(int position) {
+ Object obj = get(position);
+ if (obj instanceof EpisodicProgramRow) {
+ return ((EpisodicProgramRow) obj).getProgram().getId();
+ }
+ if (obj instanceof SeriesRecordingHeaderRow) {
+ return 0;
+ }
+ return super.getId(position);
+ }
+
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording schedule) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingAdded: " + schedule);
+ int index = findRowIndexByProgramId(schedule.getProgramId());
+ if (index != -1) {
+ EpisodicProgramRow row = (EpisodicProgramRow) get(index);
+ if (!row.isStartRecordingRequested()) {
+ row.setSchedule(schedule);
+ notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording schedule) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingRemoved: " + schedule);
+ int index = findRowIndexByProgramId(schedule.getProgramId());
+ if (index != -1) {
+ EpisodicProgramRow row = (EpisodicProgramRow) get(index);
+ row.setSchedule(null);
+ notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+
+ @Override
+ public void onScheduledRecordingUpdated(ScheduledRecording schedule, boolean conflictChange) {
+ if (DEBUG) Log.d(TAG, "onScheduledRecordingUpdated: " + schedule);
+ int index = findRowIndexByProgramId(schedule.getProgramId());
+ if (index != -1) {
+ EpisodicProgramRow row = (EpisodicProgramRow) get(index);
+ if (conflictChange && isStartOrStopRequested()) {
+ // Delay the conflict update until it gets the response of the start/stop request.
+ // The purpose is to avoid the intermediate conflict change.
+ addPendingUpdate(row);
+ return;
+ }
+ if (row.isStopRecordingRequested()) {
+ // Wait until the recording is finished
+ if (schedule.getState() == ScheduledRecording.STATE_RECORDING_FINISHED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_CLIPPED
+ || schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED) {
+ row.setStopRecordingRequested(false);
+ if (!isStartOrStopRequested()) {
+ executePendingUpdate();
+ }
+ row.setSchedule(null);
+ }
+ } else if (row.isStartRecordingRequested()) {
+ // When the start recording was requested, we give the highest priority. So it is
+ // guaranteed that the state will be changed from NOT_STARTED to the other state.
+ // Update the row with the next state not to show the intermediate state to avoid
+ // blinking.
+ if (schedule.getState() != ScheduledRecording.STATE_RECORDING_NOT_STARTED) {
+ row.setStartRecordingRequested(false);
+ if (!isStartOrStopRequested()) {
+ executePendingUpdate();
+ }
+ row.setSchedule(schedule);
+ }
+ } else if (willBeKept(schedule)) {
+ row.setSchedule(schedule);
+ } else {
+ row.setSchedule(null);
+ }
+ notifyArrayItemRangeChanged(index, 1);
+ }
+ }
+
+ public void onSeriesRecordingUpdated(SeriesRecording seriesRecording) {
+ if (seriesRecording.getId() == mSeriesRecording.getId()) {
+ mHeaderRow.setSeriesRecording(seriesRecording);
+ notifyArrayItemRangeChanged(0, 1);
+ }
+ }
+
+ private int findRowIndexByProgramId(long programId) {
+ for (int i = 0; i < size(); i++) {
+ Object item = get(i);
+ if (item instanceof EpisodicProgramRow) {
+ if (((EpisodicProgramRow) item).getProgram().getId() == programId) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ @Override
+ public void notifyArrayItemRangeChanged(int positionStart, int itemCount) {
+ mHeaderRow.setDescription(getDescription());
+ super.notifyArrayItemRangeChanged(0, 1);
+ super.notifyArrayItemRangeChanged(positionStart, itemCount);
+ }
+
+ @Override
+ protected void handleUpdateRow(long currentTimeMs) {
+ for (Iterator<Program> iter = mPrograms.values().iterator(); iter.hasNext(); ) {
+ Program program = iter.next();
+ if (program.getEndTimeUtcMillis() <= currentTimeMs) {
+ // Remove the old program.
+ removeItems(findRowIndexByProgramId(program.getId()), 1);
+ iter.remove();
+ } else if (program.getStartTimeUtcMillis() < currentTimeMs) {
+ // Change the button "START RECORDING"
+ notifyItemRangeChanged(findRowIndexByProgramId(program.getId()), 1);
+ }
+ }
+ }
+
+ /**
+ * Should take the current time argument which is the time when the programs are checked in
+ * handler.
+ */
+ @Override
+ protected long getNextTimerMs(long currentTimeMs) {
+ long earliest = Long.MAX_VALUE;
+ for (Program program : mPrograms.values()) {
+ if (earliest > program.getStartTimeUtcMillis()
+ && program.getStartTimeUtcMillis() >= currentTimeMs) {
+ // Need the button from "CREATE SCHEDULE" to "START RECORDING"
+ earliest = program.getStartTimeUtcMillis();
+ } else if (earliest > program.getEndTimeUtcMillis()) {
+ // Need to remove the row.
+ earliest = program.getEndTimeUtcMillis();
+ }
+ }
+ return earliest;
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/SeriesScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowPresenter.java
new file mode 100644
index 00000000..5d88579a
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/SeriesScheduleRowPresenter.java
@@ -0,0 +1,143 @@
+/*
+* 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.list;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.tv.R;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.util.Utils;
+
+/**
+ * A RowPresenter for series schedule row.
+ */
+public class SeriesScheduleRowPresenter extends ScheduleRowPresenter {
+ private static final String TAG = "SeriesRowPresenter";
+
+ private boolean mLtr;
+
+ public SeriesScheduleRowPresenter(Context context) {
+ super(context);
+ mLtr = context.getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_LTR;
+ }
+
+ public static class SeriesScheduleRowViewHolder extends ScheduleRowViewHolder {
+ public SeriesScheduleRowViewHolder(View view, ScheduleRowPresenter presenter) {
+ super(view, presenter);
+ ViewGroup.LayoutParams lp = getTimeView().getLayoutParams();
+ lp.width = view.getResources().getDimensionPixelSize(
+ R.dimen.dvr_series_schedules_item_time_width);
+ getTimeView().setLayoutParams(lp);
+ }
+ }
+
+ @Override
+ protected ScheduleRowViewHolder onGetScheduleRowViewHolder(View view) {
+ return new SeriesScheduleRowViewHolder(view, this);
+ }
+
+ @Override
+ protected String onGetRecordingTimeText(ScheduleRow row) {
+ return Utils.getDurationString(getContext(), row.getStartTimeMs(), row.getEndTimeMs(),
+ false, true, true, 0);
+ }
+
+ @Override
+ protected String onGetProgramInfoText(ScheduleRow row) {
+ return row.getEpisodeDisplayTitle(getContext());
+ }
+
+ @Override
+ protected void onBindRowViewHolder(ViewHolder vh, Object item) {
+ super.onBindRowViewHolder(vh, item);
+ SeriesScheduleRowViewHolder viewHolder = (SeriesScheduleRowViewHolder) vh;
+ EpisodicProgramRow row = (EpisodicProgramRow) item;
+ if (getDvrManager().isConflicting(row.getSchedule())) {
+ viewHolder.getProgramTitleView().setCompoundDrawablePadding(getContext()
+ .getResources().getDimensionPixelOffset(
+ R.dimen.dvr_schedules_warning_icon_padding));
+ if (mLtr) {
+ viewHolder.getProgramTitleView().setCompoundDrawablesWithIntrinsicBounds(
+ R.drawable.ic_warning_gray600_36dp, 0, 0, 0);
+ } else {
+ viewHolder.getProgramTitleView().setCompoundDrawablesWithIntrinsicBounds(
+ 0, 0, R.drawable.ic_warning_gray600_36dp, 0);
+ }
+ } else {
+ viewHolder.getProgramTitleView().setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0);
+ }
+ }
+
+ @Override
+ protected void onInfoClicked(ScheduleRow row) {
+ if (row.getSchedule() != null) {
+ DvrUiHelper.startSchedulesActivity(getContext(), row.getSchedule());
+ }
+ }
+
+ @Override
+ protected void onStartRecording(ScheduleRow row) {
+ SoftPreconditions.checkState(row.getSchedule() == null, TAG,
+ "Start request with the existing schedule: " + row);
+ row.setStartRecordingRequested(true);
+ getDvrManager().addScheduleWithHighestPriority(((EpisodicProgramRow) row).getProgram());
+ }
+
+ @Override
+ protected void onStopRecording(ScheduleRow row) {
+ SoftPreconditions.checkState(row.getSchedule() != null, TAG,
+ "Stop request with the null schedule: " + row);
+ row.setStopRecordingRequested(true);
+ getDvrManager().stopRecording(row.getSchedule());
+ }
+
+ @Override
+ protected void onCreateSchedule(ScheduleRow row) {
+ if (row.getSchedule() == null) {
+ getDvrManager().addScheduleWithHighestPriority(((EpisodicProgramRow) row).getProgram());
+ } else {
+ super.onCreateSchedule(row);
+ }
+ }
+
+ @Override
+ @ScheduleRowAction
+ protected int[] getAvailableActions(ScheduleRow row) {
+ if (row.getSchedule() == null) {
+ if (row.isOnAir()) {
+ return new int[] {ACTION_START_RECORDING};
+ } else {
+ return new int[] {ACTION_CREATE_SCHEDULE};
+ }
+ }
+ return super.getAvailableActions(row);
+ }
+
+ @Override
+ protected boolean canResolveConflict() {
+ return false;
+ }
+
+ @Override
+ protected boolean shouldKeepScheduleAfterRemoving() {
+ return true;
+ }
+}
diff --git a/src/com/android/tv/experiments/ExperimentFlag.java b/src/com/android/tv/experiments/ExperimentFlag.java
new file mode 100644
index 00000000..8f60c2b5
--- /dev/null
+++ b/src/com/android/tv/experiments/ExperimentFlag.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+
+/**
+ * Experiments return values based on user, device and other criteria.
+ */
+public final class ExperimentFlag<T> {
+ private final T mDefaultValue;
+
+ /** Returns a boolean experiment */
+ public static ExperimentFlag<Boolean> createFlag(
+ boolean defaultValue) {
+ return new ExperimentFlag<>(
+ defaultValue);
+ }
+
+ private ExperimentFlag(
+ T defaultValue) {
+ mDefaultValue = defaultValue;
+ }
+
+ /** Returns value for this experiment */
+ public T get() {
+ return mDefaultValue;
+ }
+}
diff --git a/src/com/android/tv/experiments/Experiments.java b/src/com/android/tv/experiments/Experiments.java
new file mode 100644
index 00000000..f16c8d1e
--- /dev/null
+++ b/src/com/android/tv/experiments/Experiments.java
@@ -0,0 +1,42 @@
+/*
+ * 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 com.android.tv.experiments.ExperimentFlag.createFlag;
+
+import com.android.tv.common.BuildConfig;
+
+/**
+ * Set of experiments visible in AOSP.
+ *
+ * <p>
+ * This file is maintained by hand.
+ */
+public final class Experiments {
+ public static final ExperimentFlag<Boolean> CLOUD_EPG = createFlag(
+ false);
+
+ /**
+ * Allow developer features such as the dev menu and other aids.
+ *
+ * <p>These features are available to select users(aka fishfooders) on production builds.
+ */
+ public static final ExperimentFlag<Boolean> ENABLE_DEVELOPER_FEATURES = createFlag(
+ BuildConfig.ENG);
+
+ private Experiments() {}
+}
diff --git a/src/com/android/tv/guide/ProgramGuide.java b/src/com/android/tv/guide/ProgramGuide.java
index bfcb8b0d..120b3dba 100644
--- a/src/com/android/tv/guide/ProgramGuide.java
+++ b/src/com/android/tv/guide/ProgramGuide.java
@@ -22,7 +22,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
+import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Point;
@@ -42,6 +42,7 @@ import android.view.View.MeasureSpec;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.view.ViewTreeObserver;
+import android.view.accessibility.AccessibilityManager;
import com.android.tv.ChannelTuner;
import com.android.tv.Features;
@@ -54,7 +55,9 @@ import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.GenreItems;
import com.android.tv.data.ProgramDataManager;
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.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -89,6 +92,7 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
private final MainActivity mActivity;
private final ProgramManager mProgramManager;
+ private final AccessibilityManager mAccessibilityManager;
private final ChannelTuner mChannelTuner;
private final Tracker mTracker;
private final DurationTimer mVisibleDuration = new DurationTimer();
@@ -163,10 +167,11 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
public ProgramGuide(MainActivity activity, ChannelTuner channelTuner,
TvInputManagerHelper tvInputManagerHelper, ChannelDataManager channelDataManager,
ProgramDataManager programDataManager, @Nullable DvrDataManager dvrDataManager,
- Tracker tracker, Runnable preShowRunnable, Runnable postHideRunnable) {
+ @Nullable DvrScheduleManager dvrScheduleManager, Tracker tracker,
+ Runnable preShowRunnable, Runnable postHideRunnable) {
mActivity = activity;
mProgramManager = new ProgramManager(tvInputManagerHelper, channelDataManager,
- programDataManager, dvrDataManager);
+ programDataManager, dvrDataManager, dvrScheduleManager);
mChannelTuner = channelTuner;
mTracker = tracker;
mPreShowRunnable = preShowRunnable;
@@ -372,7 +377,10 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
mProgramTableFadeInAnimator.setTarget(mTable);
mProgramTableFadeInAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(mTable));
mSharedPreference = PreferenceManager.getDefaultSharedPreferences(mActivity);
- mShowGuidePartial = mSharedPreference.getBoolean(KEY_SHOW_GUIDE_PARTIAL, true);
+ mAccessibilityManager =
+ (AccessibilityManager) mActivity.getSystemService(Context.ACCESSIBILITY_SERVICE);
+ mShowGuidePartial = mAccessibilityManager.isEnabled()
+ || mSharedPreference.getBoolean(KEY_SHOW_GUIDE_PARTIAL, true);
}
private void updateGuidePosition() {
@@ -604,7 +612,9 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
}
private void startFull() {
- if (isFull()) {
+ if (isFull() || mAccessibilityManager.isEnabled()) {
+ // If accessibility service is enabled, focus cannot be moved to side panel due to it's
+ // hidden. Therefore, we don't hide side panel when accessibility service is enabled.
return;
}
mShowGuidePartial = false;
@@ -741,7 +751,7 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
View detailView = row.findViewById(R.id.detail);
detailView.findViewById(R.id.detail_content_full).setAlpha(1);
detailView.findViewById(R.id.detail_content_full).setTranslationY(0);
- setLayoutHeight(detailView, mDetailHeight);
+ ViewUtils.setLayoutHeight(detailView, mDetailHeight);
detailView.setVisibility(View.VISIBLE);
final ProgramRow programRow = (ProgramRow) row.findViewById(R.id.row);
@@ -783,8 +793,8 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
fadeOutAnimator.setDuration(mAnimationDuration);
fadeOutAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(outDetailContent));
- Animator collapseAnimator =
- createHeightAnimator(outDetail, getLayoutHeight(outDetail), 0);
+ Animator collapseAnimator = ViewUtils
+ .createHeightAnimator(outDetail, ViewUtils.getLayoutHeight(outDetail), 0);
collapseAnimator.setStartDelay(mAnimationDuration);
collapseAnimator.setDuration(mTableFadeAnimDuration);
collapseAnimator.addListener(new AnimatorListenerAdapter() {
@@ -815,7 +825,7 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
if (inDetail != null) {
final View inDetailContent = inDetail.findViewById(R.id.detail_content_full);
- Animator expandAnimator = createHeightAnimator(inDetail, 0, mDetailHeight);
+ Animator expandAnimator = ViewUtils.createHeightAnimator(inDetail, 0, mDetailHeight);
expandAnimator.setStartDelay(mAnimationDuration);
expandAnimator.setDuration(mTableFadeAnimDuration);
expandAnimator.addListener(new AnimatorListenerAdapter() {
@@ -830,17 +840,15 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
inDetailContent.setAlpha(0);
}
});
-
Animator fadeInAnimator = ObjectAnimator.ofPropertyValuesHolder(inDetailContent,
PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f),
PropertyValuesHolder.ofFloat(View.TRANSLATION_Y,
direction * -mDetailPadding, 0f));
- fadeInAnimator.setStartDelay(mAnimationDuration + mTableFadeAnimDuration);
fadeInAnimator.setDuration(mAnimationDuration);
fadeInAnimator.addListener(new HardwareLayerAnimatorListenerAdapter(inDetailContent));
AnimatorSet inAnimator = new AnimatorSet();
- inAnimator.playTogether(expandAnimator, fadeInAnimator);
+ inAnimator.playSequentially(expandAnimator, fadeInAnimator);
inAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animator) {
@@ -852,41 +860,6 @@ public class ProgramGuide implements ProgramGrid.ChildFocusListener {
}
}
- private Animator createHeightAnimator(
- final View target, int initialHeight, int targetHeight) {
- ValueAnimator animator = ValueAnimator.ofInt(initialHeight, targetHeight);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- int value = (Integer) animation.getAnimatedValue();
- if (value == 0) {
- if (target.getVisibility() != View.GONE) {
- target.setVisibility(View.GONE);
- }
- } else {
- if (target.getVisibility() != View.VISIBLE) {
- target.setVisibility(View.VISIBLE);
- }
- setLayoutHeight(target, value);
- }
- }
- });
- return animator;
- }
-
- private int getLayoutHeight(View view) {
- LayoutParams layoutParams = view.getLayoutParams();
- return layoutParams.height;
- }
-
- private void setLayoutHeight(View view, int height) {
- LayoutParams layoutParams = view.getLayoutParams();
- if (height != layoutParams.height) {
- layoutParams.height = height;
- view.setLayoutParams(layoutParams);
- }
- }
-
private class GlobalFocusChangeListener implements
ViewTreeObserver.OnGlobalFocusChangeListener {
private static final int UNKNOWN = 0;
diff --git a/src/com/android/tv/guide/ProgramItemView.java b/src/com/android/tv/guide/ProgramItemView.java
index 172ee070..4c7a4404 100644
--- a/src/com/android/tv/guide/ProgramItemView.java
+++ b/src/com/android/tv/guide/ProgramItemView.java
@@ -16,6 +16,7 @@
package com.android.tv.guide;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -24,7 +25,6 @@ import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Handler;
import android.os.SystemClock;
-import android.support.v4.os.BuildCompat;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
@@ -34,6 +34,7 @@ import android.util.Log;
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;
@@ -43,10 +44,10 @@ import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.ui.DvrDialogFragment;
-import com.android.tv.dvr.ui.DvrRecordDeleteFragment;
-import com.android.tv.dvr.ui.DvrRecordScheduleFragment;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
import com.android.tv.guide.ProgramManager.TableEntry;
+import com.android.tv.util.ToastUtils;
import com.android.tv.util.Utils;
import java.lang.reflect.InvocationTargetException;
@@ -66,11 +67,13 @@ public class ProgramItemView extends TextView {
private static int sVisibleThreshold;
private static int sItemPadding;
+ private static int sCompoundDrawablePadding;
private static TextAppearanceSpan sProgramTitleStyle;
private static TextAppearanceSpan sGrayedOutProgramTitleStyle;
private static TextAppearanceSpan sEpisodeTitleStyle;
private static TextAppearanceSpan sGrayedOutEpisodeTitleStyle;
+ private DvrManager mDvrManager;
private TableEntry mTableEntry;
private int mMaxWidthForRipple;
private int mTextWidth;
@@ -91,10 +94,9 @@ public class ProgramItemView extends TextView {
ApplicationSingletons singletons = TvApplication.getSingletons(view.getContext());
Tracker tracker = singletons.getTracker();
tracker.sendEpgItemClicked();
+ final MainActivity tvActivity = (MainActivity) view.getContext();
+ final Channel channel = tvActivity.getChannelDataManager().getChannel(entry.channelId);
if (entry.isCurrentProgram()) {
- final MainActivity tvActivity = (MainActivity) view.getContext();
- final Channel channel = tvActivity.getChannelDataManager()
- .getChannel(entry.channelId);
view.postDelayed(new Runnable() {
@Override
public void run() {
@@ -104,37 +106,30 @@ public class ProgramItemView extends TextView {
}, entry.getWidth() > ((ProgramItemView) view).mMaxWidthForRipple ? 0
: view.getResources()
.getInteger(R.integer.program_guide_ripple_anim_duration));
- } else if (CommonFeatures.DVR.isEnabled(view.getContext()) && BuildCompat
- .isAtLeastN()) {
- final MainActivity tvActivity = (MainActivity) view.getContext();
- final DvrManager dvrManager = singletons.getDvrManager();
- final Channel channel = tvActivity.getChannelDataManager()
- .getChannel(entry.channelId);
- if (dvrManager.canRecord(channel.getInputId()) && entry.program != null) {
+ } else if (CommonFeatures.DVR.isEnabled(view.getContext())) {
+ DvrManager dvrManager = singletons.getDvrManager();
+ if (entry.entryStartUtcMillis > System.currentTimeMillis()
+ && dvrManager.isProgramRecordable(entry.program)) {
if (entry.scheduledRecording == null) {
- showDvrDialog(view, entry);
+ if (DvrUiHelper.checkStorageStatusAndShowErrorMessage(tvActivity,
+ channel.getInputId())
+ && DvrUiHelper.handleCreateSchedule(tvActivity, entry.program)) {
+ String msg = view.getContext().getString(
+ R.string.dvr_msg_program_scheduled, entry.program.getTitle());
+ ToastUtils.show(view.getContext(), msg, Toast.LENGTH_SHORT);
+ }
} else {
- showRecordDeleteDialog(view, entry);
+ dvrManager.removeScheduledRecording(entry.scheduledRecording);
+ String msg = view.getResources().getString(
+ R.string.dvr_schedules_deletion_info, entry.program.getTitle());
+ ToastUtils.show(view.getContext(), msg, Toast.LENGTH_SHORT);
}
+ } else {
+ ToastUtils.show(view.getContext(), view.getResources()
+ .getString(R.string.dvr_msg_cannot_record_program), Toast.LENGTH_SHORT);
}
}
}
-
- private void showDvrDialog(final View view, TableEntry entry) {
- Utils.showToastMessageForDeveloperFeature(view.getContext());
- DvrRecordScheduleFragment dvrRecordScheduleFragment =
- new DvrRecordScheduleFragment(entry);
- DvrDialogFragment dvrDialogFragment = new DvrDialogFragment(dvrRecordScheduleFragment);
- ((MainActivity) view.getContext()).getOverlayManager().showDialogFragment(
- DvrDialogFragment.DIALOG_TAG, dvrDialogFragment, true, true);
- }
-
- private void showRecordDeleteDialog(final View view, final TableEntry entry) {
- DvrRecordDeleteFragment recordDeleteDialogFragment = new DvrRecordDeleteFragment(entry);
- DvrDialogFragment dvrDialogFragment = new DvrDialogFragment(recordDeleteDialogFragment);
- ((MainActivity) view.getContext()).getOverlayManager().showDialogFragment(
- DvrDialogFragment.DIALOG_TAG, dvrDialogFragment, true, true);
- }
};
private static final View.OnFocusChangeListener ON_FOCUS_CHANGED =
@@ -185,6 +180,7 @@ public class ProgramItemView extends TextView {
super(context, attrs, defStyle);
setOnClickListener(ON_CLICKED);
setOnFocusChangeListener(ON_FOCUS_CHANGED);
+ mDvrManager = TvApplication.getSingletons(getContext()).getDvrManager();
}
private void initIfNeeded() {
@@ -197,15 +193,18 @@ public class ProgramItemView extends TextView {
R.dimen.program_guide_table_item_visible_threshold);
sItemPadding = res.getDimensionPixelOffset(R.dimen.program_guide_table_item_padding);
-
- ColorStateList programTitleColor = ColorStateList.valueOf(Utils.getColor(res,
- R.color.program_guide_table_item_program_title_text_color));
- ColorStateList grayedOutProgramTitleColor = Utils.getColorStateList(res,
- R.color.program_guide_table_item_grayed_out_program_text_color);
- ColorStateList episodeTitleColor = ColorStateList.valueOf(Utils.getColor(res,
- R.color.program_guide_table_item_program_episode_title_text_color));
- ColorStateList grayedOutEpisodeTitleColor = ColorStateList.valueOf(Utils.getColor(res,
- R.color.program_guide_table_item_grayed_out_program_episode_title_text_color));
+ sCompoundDrawablePadding = res.getDimensionPixelOffset(
+ R.dimen.program_guide_table_item_compound_drawable_padding);
+
+ ColorStateList programTitleColor = ColorStateList.valueOf(res.getColor(
+ R.color.program_guide_table_item_program_title_text_color, null));
+ ColorStateList grayedOutProgramTitleColor = res.getColorStateList(
+ R.color.program_guide_table_item_grayed_out_program_text_color, null);
+ ColorStateList episodeTitleColor = ColorStateList.valueOf(res.getColor(
+ R.color.program_guide_table_item_program_episode_title_text_color, null));
+ ColorStateList grayedOutEpisodeTitleColor = ColorStateList.valueOf(res.getColor(
+ R.color.program_guide_table_item_grayed_out_program_episode_title_text_color,
+ null));
int programTitleSize = res.getDimensionPixelSize(
R.dimen.program_guide_table_item_program_title_font_size);
int episodeTitleSize = res.getDimensionPixelSize(
@@ -247,6 +246,7 @@ public class ProgramItemView extends TextView {
return mTableEntry;
}
+ @SuppressLint("SwitchIntDef")
public void setValues(TableEntry entry, int selectedGenreId, long fromUtcMillis,
long toUtcMillis, String gapTitle) {
mTableEntry = entry;
@@ -275,11 +275,6 @@ public class ProgramItemView extends TextView {
if (TextUtils.isEmpty(title)) {
title = getResources().getString(R.string.program_title_for_no_information);
}
- if (mTableEntry.scheduledRecording != null) {
- //TODO(dvr): use a proper icon for UI status.
- title = "®" + title;
- }
-
SpannableStringBuilder description = new SpannableStringBuilder();
description.append(title);
if (!TextUtils.isEmpty(episode)) {
@@ -302,18 +297,48 @@ public class ProgramItemView extends TextView {
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
setText(description);
+
+ // Sets recording icons if needed.
+ int iconResId = 0;
+ if (mTableEntry.scheduledRecording != null) {
+ if (mDvrManager.isConflicting(mTableEntry.scheduledRecording)) {
+ iconResId = R.drawable.ic_warning_white_18dp;
+ } else {
+ switch (mTableEntry.scheduledRecording.getState()) {
+ case ScheduledRecording.STATE_RECORDING_NOT_STARTED:
+ iconResId = R.drawable.ic_scheduled_recording;
+ break;
+ case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
+ iconResId = R.drawable.ic_recording_program;
+ break;
+ }
+ }
+ }
+ setCompoundDrawablePadding(iconResId != 0 ? sCompoundDrawablePadding : 0);
+ setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, iconResId, 0);
}
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
mTextWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
- int start = GuideUtils.convertMillisToPixel(entry.entryStartUtcMillis);
- int guideStart = GuideUtils.convertMillisToPixel(fromUtcMillis);
- layoutVisibleArea(guideStart - start);
-
// Maximum width for us to use a ripple
mMaxWidthForRipple = GuideUtils.convertMillisToPixel(fromUtcMillis, toUtcMillis);
}
/**
+ * Update programItemView to handle alignments of text.
+ */
+ public void updateVisibleArea() {
+ View parentView = ((View) getParent());
+ if (parentView == null) {
+ return;
+ }
+ if (getLayoutDirection() == LAYOUT_DIRECTION_LTR) {
+ layoutVisibleArea(parentView.getLeft() - getLeft(), getRight() - parentView.getRight());
+ } else {
+ layoutVisibleArea(getRight() - parentView.getRight(), parentView.getLeft() - getLeft());
+ }
+ }
+
+ /**
* Layout title and episode according to visible area.
*
* Here's the spec.
@@ -322,19 +347,25 @@ public class ProgramItemView extends TextView {
* but do not wrap text less than 30min.
* 3. Episode title is visible only if title isn't multi-line.
*
- * @param offset Offset of the start position from the enclosing view's start position.
+ * @param startOffset Offset of the start position from the enclosing view's start position.
+ * @param endOffset Offset of the end position from the enclosing view's end position.
*/
- public void layoutVisibleArea(int offset) {
+ private void layoutVisibleArea(int startOffset, int endOffset) {
int width = mTableEntry.getWidth();
- int startPadding = Math.max(0, offset);
+ int startPadding = Math.max(0, startOffset);
+ int endPadding = Math.max(0, endOffset);
int minWidth = Math.min(width, mTextWidth + 2 * sItemPadding);
if (startPadding > 0 && width - startPadding < minWidth) {
startPadding = Math.max(0, width - minWidth);
}
+ if (endPadding > 0 && width - endPadding < minWidth) {
+ endPadding = Math.max(0, width - minWidth);
+ }
- if (startPadding + sItemPadding != getPaddingStart()) {
+ if (startPadding + sItemPadding != getPaddingStart()
+ || endPadding + sItemPadding != getPaddingEnd()) {
mPreventParentRelayout = true; // The size of this view is kept, no need to tell parent.
- setPaddingRelative(startPadding + sItemPadding, 0, sItemPadding, 0);
+ setPaddingRelative(startPadding + sItemPadding, 0, endPadding + sItemPadding, 0);
mPreventParentRelayout = false;
}
}
diff --git a/src/com/android/tv/guide/ProgramManager.java b/src/com/android/tv/guide/ProgramManager.java
index fe1a981f..e3d919df 100644
--- a/src/com/android/tv/guide/ProgramManager.java
+++ b/src/com/android/tv/guide/ProgramManager.java
@@ -27,6 +27,8 @@ import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrScheduleManager;
+import com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener;
import com.android.tv.dvr.ScheduledRecording;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -59,12 +61,12 @@ public class ProgramManager {
private final ChannelDataManager mChannelDataManager;
private final ProgramDataManager mProgramDataManager;
private final DvrDataManager mDvrDataManager; // Only set if DVR is enabled
+ private final DvrScheduleManager mDvrScheduleManager;
private long mStartUtcMillis;
private long mEndUtcMillis;
private long mFromUtcMillis;
private long mToUtcMillis;
- private Program mSelectedProgram;
/**
* Entry for program guide table. An "entry" can be either an actual program or a gap between
@@ -177,27 +179,42 @@ public class ProgramManager {
// Channel list after applying genre filter.
// Should be matched with mSelectedGenreId always.
private List<Channel> mFilteredChannels = mChannels;
+ private boolean mChannelDataLoaded;
private final Set<Listener> mListeners = new ArraySet<>();
private final Set<TableEntriesUpdatedListener> mTableEntriesUpdatedListeners = new ArraySet<>();
private final Set<TableEntryChangedListener> mTableEntryChangedListeners = new ArraySet<>();
+ private final DvrDataManager.OnDvrScheduleLoadFinishedListener mDvrLoadedListener =
+ new DvrDataManager.OnDvrScheduleLoadFinishedListener() {
+ @Override
+ public void onDvrScheduleLoadFinished() {
+ if (mChannelDataLoaded) {
+ for (ScheduledRecording r : mDvrDataManager.getAllScheduledRecordings()) {
+ mScheduledRecordingListener.onScheduledRecordingAdded(r);
+ }
+ }
+ mDvrDataManager.removeDvrScheduleLoadFinishedListener(this);
+ }
+ };
+
private final ChannelDataManager.Listener mChannelDataManagerListener =
new ChannelDataManager.Listener() {
@Override
public void onLoadFinished() {
- updateChannels(true, false);
+ mChannelDataLoaded = true;
+ updateChannels(false);
}
@Override
public void onChannelListUpdated() {
- updateChannels(true, false);
+ updateChannels(false);
}
@Override
public void onChannelBrowsableChanged() {
- updateChannels(true, false);
+ updateChannels(false);
}
};
@@ -205,53 +222,75 @@ public class ProgramManager {
new ProgramDataManager.Listener() {
@Override
public void onProgramUpdated() {
- updateTableEntries(true, true);
+ updateTableEntries(true);
}
};
private final DvrDataManager.ScheduledRecordingListener mScheduledRecordingListener =
new DvrDataManager.ScheduledRecordingListener() {
@Override
- public void onScheduledRecordingAdded(ScheduledRecording scheduledRecording) {
- TableEntry oldEntry = getTableEntry(scheduledRecording);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
- scheduledRecording, oldEntry.entryStartUtcMillis,
- oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
+ schedule, oldEntry.entryStartUtcMillis,
+ oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
}
}
@Override
- public void onScheduledRecordingRemoved(ScheduledRecording scheduledRecording) {
- TableEntry oldEntry = getTableEntry(scheduledRecording);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program, null,
- oldEntry.entryStartUtcMillis, oldEntry.entryEndUtcMillis,
- oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program, null,
+ oldEntry.entryStartUtcMillis, oldEntry.entryEndUtcMillis,
+ oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
}
}
@Override
- public void onScheduledRecordingStatusChanged(ScheduledRecording scheduledRecording) {
- TableEntry oldEntry = getTableEntry(scheduledRecording);
- if (oldEntry != null) {
- TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
- scheduledRecording, oldEntry.entryStartUtcMillis,
- oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
- updateEntry(oldEntry, newEntry);
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ TableEntry oldEntry = getTableEntry(schedule);
+ if (oldEntry != null) {
+ TableEntry newEntry = new TableEntry(oldEntry.channelId, oldEntry.program,
+ schedule, oldEntry.entryStartUtcMillis,
+ oldEntry.entryEndUtcMillis, oldEntry.isBlocked());
+ updateEntry(oldEntry, newEntry);
+ }
}
}
};
+ private final OnConflictStateChangeListener mOnConflictStateChangeListener =
+ new OnConflictStateChangeListener() {
+ @Override
+ public void onConflictStateChange(boolean conflict,
+ ScheduledRecording... schedules) {
+ for (ScheduledRecording schedule : schedules) {
+ TableEntry entry = getTableEntry(schedule);
+ if (entry != null) {
+ notifyTableEntryUpdated(entry);
+ }
+ }
+ }
+ };
+
public ProgramManager(TvInputManagerHelper tvInputManagerHelper,
ChannelDataManager channelDataManager, ProgramDataManager programDataManager,
- @Nullable DvrDataManager dvrDataManager) {
+ @Nullable DvrDataManager dvrDataManager,
+ @Nullable DvrScheduleManager dvrScheduleManager) {
mTvInputManagerHelper = tvInputManagerHelper;
mChannelDataManager = channelDataManager;
mProgramDataManager = programDataManager;
mDvrDataManager = dvrDataManager;
+ mDvrScheduleManager = dvrScheduleManager;
}
public void programGuideVisibilityChanged(boolean visible) {
@@ -260,14 +299,26 @@ public class ProgramManager {
mChannelDataManager.addListener(mChannelDataManagerListener);
mProgramDataManager.addListener(mProgramDataManagerListener);
if (mDvrDataManager != null) {
+ if (!mDvrDataManager.isDvrScheduleLoadFinished()) {
+ mDvrDataManager.addDvrScheduleLoadFinishedListener(mDvrLoadedListener);
+ }
mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
}
+ if (mDvrScheduleManager != null) {
+ mDvrScheduleManager.addOnConflictStateChangeListener(
+ mOnConflictStateChangeListener);
+ }
} else {
mChannelDataManager.removeListener(mChannelDataManagerListener);
mProgramDataManager.removeListener(mProgramDataManagerListener);
if (mDvrDataManager != null) {
+ mDvrDataManager.removeDvrScheduleLoadFinishedListener(mDvrLoadedListener);
mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener);
}
+ if (mDvrScheduleManager != null) {
+ mDvrScheduleManager.removeOnConflictStateChangeListener(
+ mOnConflictStateChangeListener);
+ }
}
}
@@ -325,7 +376,7 @@ public class ProgramManager {
mGenreChannelList.clear();
for (int i = 0; i < GenreItems.getGenreCount(); i++) {
- mGenreChannelList.add(new ArrayList<Channel>());
+ mGenreChannelList.add(new ArrayList<>());
}
for (Channel channel : mChannels) {
// TODO: Use programs in visible area instead of using current programs only.
@@ -383,18 +434,16 @@ public class ProgramManager {
// Note that This can be happens only if program guide isn't shown
// because an user has to select channels as browsable through UI.
- private void updateChannels(boolean notify, boolean clearPreviousTableEntries) {
+ private void updateChannels(boolean clearPreviousTableEntries) {
if (DEBUG) Log.d(TAG, "updateChannels");
mChannels = mChannelDataManager.getBrowsableChannelList();
mSelectedGenreId = GenreItems.ID_ALL_CHANNELS;
mFilteredChannels = mChannels;
- if (notify) {
- notifyChannelsUpdated();
- }
- updateTableEntries(notify, clearPreviousTableEntries);
+ notifyChannelsUpdated();
+ updateTableEntries(clearPreviousTableEntries);
}
- private void updateTableEntries(boolean notify, boolean clear) {
+ private void updateTableEntries(boolean clear) {
if (clear) {
mChannelIdEntriesMap.clear();
}
@@ -443,9 +492,7 @@ public class ProgramManager {
}
}
- if (notify) {
- notifyTableEntriesUpdated();
- }
+ notifyTableEntriesUpdated();
buildGenreFilters();
}
@@ -528,7 +575,7 @@ public class ProgramManager {
}
mProgramDataManager.setPrefetchTimeRange(mStartUtcMillis);
- updateChannels(true, true);
+ updateChannels(true);
setTimeRange(startUtcMillis, endUtcMillis);
}
@@ -643,20 +690,6 @@ public class ProgramManager {
return entries;
}
- /**
- * Get the currently selected channel.
- */
- public Channel getSelectedChannel() {
- return mChannelDataManager.getChannel(mSelectedProgram.getChannelId());
- }
-
- /**
- * Get the currently selected program.
- */
- public Program getSelectedProgram() {
- return mSelectedProgram;
- }
-
public interface Listener {
void onGenresUpdated();
void onChannelsUpdated();
diff --git a/src/com/android/tv/guide/ProgramRow.java b/src/com/android/tv/guide/ProgramRow.java
index 54b864db..2c98ab2d 100644
--- a/src/com/android/tv/guide/ProgramRow.java
+++ b/src/com/android/tv/guide/ProgramRow.java
@@ -22,8 +22,7 @@ import android.support.v7.widget.LinearLayoutManager;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewParent;
-import android.view.ViewTreeObserver;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import com.android.tv.data.Channel;
import com.android.tv.guide.ProgramManager.TableEntry;
@@ -45,25 +44,26 @@ public class ProgramRow extends TimelineGridView {
interface ChildFocusListener {
/**
- * Is called after focus is moved. Only children to {@code ProgramRow} will be passed.
+ * Is called after focus is moved. It used {@link ChildFocusListener#isChild} to decide if
+ * old and new focuses are listener's children.
* See {@code ProgramRow#setChildFocusListener(ChildFocusListener)}.
*/
void onChildFocus(View oldFocus, View newFocus);
}
- private final ViewTreeObserver.OnGlobalFocusChangeListener mGlobalFocusChangeListener =
- new ViewTreeObserver.OnGlobalFocusChangeListener() {
- @Override
- public void onGlobalFocusChanged(View oldFocus, View newFocus) {
- updateCurrentFocus(oldFocus, newFocus);
- }
- };
-
/**
* Used only for debugging.
*/
private Channel mChannel;
+ private final OnGlobalLayoutListener mLayoutListener = new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ updateChildVisibleArea();
+ }
+ };
+
public ProgramRow(Context context) {
this(context, null);
}
@@ -84,21 +84,25 @@ public class ProgramRow extends TimelineGridView {
}
@Override
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+ ProgramItemView itemView = (ProgramItemView) child;
+ if (getLeft() <= itemView.getRight() && itemView.getLeft() <= getRight()) {
+ itemView.updateVisibleArea();
+ }
+ }
+
+ @Override
public void onScrolled(int dx, int dy) {
+ // Remove callback to prevent updateChildVisibleArea being called twice.
+ getViewTreeObserver().removeOnGlobalLayoutListener(mLayoutListener);
super.onScrolled(dx, dy);
- int childCount = getChildCount();
if (DEBUG) {
Log.d(TAG, "onScrolled by " + dx);
- Log.d(TAG, "channelId=" + mChannel.getId() + ", childCount=" + childCount);
+ Log.d(TAG, "channelId=" + mChannel.getId() + ", childCount=" + getChildCount());
Log.d(TAG, "ProgramRow {" + Utils.toRectString(this) + "}");
}
- for (int i = 0; i < childCount; ++i) {
- ProgramItemView child = (ProgramItemView) getChildAt(i);
- if (getLeft() <= child.getRight() && child.getLeft() <= getRight()) {
- child.layoutVisibleArea(getLayoutDirection() == LAYOUT_DIRECTION_LTR
- ? getLeft() - child.getLeft() : child.getRight() - getRight());
- }
- }
+ updateChildVisibleArea();
}
/**
@@ -109,29 +113,9 @@ public class ProgramRow extends TimelineGridView {
if (currentProgram == null) {
currentProgram = getChildAt(0);
}
- updateCurrentFocus(null, currentProgram);
- }
-
- private void updateCurrentFocus(View oldFocus, View newFocus) {
- if (mChildFocusListener == null) {
- return;
- }
-
- mChildFocusListener.onChildFocus(isChild(oldFocus) ? oldFocus : null,
- isChild(newFocus) ? newFocus : null);
- }
-
- private boolean isChild(View view) {
- if (view == null) {
- return false;
+ if (mChildFocusListener != null) {
+ mChildFocusListener.onChildFocus(null, currentProgram);
}
-
- for (ViewParent p = view.getParent(); p != null; p = p.getParent()) {
- if (p == this) {
- return true;
- }
- }
- return false;
}
// Call this API after RTL is resolved. (i.e. View is measured.)
@@ -160,7 +144,7 @@ public class ProgramRow extends TimelineGridView {
return focused;
}
} else if (isDirectionEnd(direction) || direction == View.FOCUS_FORWARD) {
- if (focusedEntry.entryEndUtcMillis > toMillis + ONE_HOUR_MILLIS) {
+ if (focusedEntry.entryEndUtcMillis >= toMillis + ONE_HOUR_MILLIS) {
// The current entry ends outside of the view; Scroll to the right.
scrollByTime(ONE_HOUR_MILLIS);
return focused;
@@ -172,7 +156,7 @@ public class ProgramRow extends TimelineGridView {
if (isDirectionEnd(direction) || direction == View.FOCUS_FORWARD) {
if (focusedEntry.entryEndUtcMillis != toMillis) {
// The focused entry is the last entry; Align to the right edge.
- scrollByTime(focusedEntry.entryEndUtcMillis - mProgramManager.getToUtcMillis());
+ scrollByTime(focusedEntry.entryEndUtcMillis - toMillis);
return focused;
}
}
@@ -208,23 +192,21 @@ public class ProgramRow extends TimelineGridView {
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- getViewTreeObserver().addOnGlobalFocusChangeListener(mGlobalFocusChangeListener);
- }
-
- @Override
- protected void onDetachedFromWindow() {
- super.onDetachedFromWindow();
- getViewTreeObserver().removeOnGlobalFocusChangeListener(mGlobalFocusChangeListener);
- }
-
- @Override
public void onChildDetachedFromWindow(View child) {
if (child.hasFocus()) {
// Focused view can be detached only if it's updated.
TableEntry entry = ((ProgramItemView) child).getTableEntry();
- if (entry.isCurrentProgram()) {
+ if (entry.program == null) {
+ // The focus is lost due to information loaded. Requests focus immediately.
+ // (Because this entry is detached after real entries attached, we can't take
+ // the below approach to resume focus on entry being attached.)
+ post(new Runnable() {
+ @Override
+ public void run() {
+ requestFocus();
+ }
+ });
+ } else if (entry.isCurrentProgram()) {
if (DEBUG) Log.d(TAG, "Keep focus to the current program");
// Current program is visible in the guide.
// Updated entries including current program's will be attached again soon
@@ -242,13 +224,13 @@ public class ProgramRow extends TimelineGridView {
if (mKeepFocusToCurrentProgram) {
TableEntry entry = ((ProgramItemView) child).getTableEntry();
if (entry.isCurrentProgram()) {
+ mKeepFocusToCurrentProgram = false;
post(new Runnable() {
@Override
public void run() {
requestFocus();
}
});
- mKeepFocusToCurrentProgram = false;
}
}
}
@@ -316,6 +298,22 @@ public class ProgramRow extends TimelineGridView {
mProgramManager.getStartTime(), entry.entryStartUtcMillis) - scrollOffset;
((LinearLayoutManager) getLayoutManager())
.scrollToPositionWithOffset(position, offset);
+ // Workaround to b/31598505. When a program's duration is too long,
+ // RecyclerView.onScrolled() will not be called after scrollToPositionWithOffset().
+ // Therefore we have to update children's visible areas by ourselves in theis case.
+ // Since scrollToPositionWithOffset() will call requestLayout(), we can listen to this
+ // behavior to ensure program items' visible areas are correctly updated after layouts
+ // are adjusted, i.e., scrolling is over.
+ getViewTreeObserver().addOnGlobalLayoutListener(mLayoutListener);
+ }
+ }
+
+ private void updateChildVisibleArea() {
+ for (int i = 0; i < getChildCount(); ++i) {
+ ProgramItemView child = (ProgramItemView) getChildAt(i);
+ if (getLeft() < child.getRight() && child.getLeft() < getRight()) {
+ child.updateVisibleArea();
+ }
}
}
}
diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java
index 83755b5f..e4a67972 100644
--- a/src/com/android/tv/guide/ProgramTableAdapter.java
+++ b/src/com/android/tv/guide/ProgramTableAdapter.java
@@ -32,6 +32,7 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.RecycledViewPool;
+import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
@@ -41,13 +42,22 @@ 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.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.TvApplication;
+import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.Program.CriticScore;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
import com.android.tv.guide.ProgramManager.TableEntriesUpdatedListener;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.ui.HardwareLayerAnimatorListenerAdapter;
@@ -70,11 +80,16 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
private final Context mContext;
private final TvInputManagerHelper mTvInputManagerHelper;
+ private final DvrManager mDvrManager;
+ private final DvrDataManager mDvrDataManager;
private final ProgramManager mProgramManager;
+ private final AccessibilityManager mAccessibilityManager;
private final ProgramGuide mProgramGuide;
private final Handler mHandler = new Handler();
private final List<ProgramListAdapter> mProgramListAdapters = new ArrayList<>();
private final RecycledViewPool mRecycledViewPool;
+ // views to be be reused when displaying critic scores
+ private final List<LinearLayout> mCriticScoreViews;
private final int mChannelLogoWidth;
private final int mChannelLogoHeight;
@@ -89,11 +104,27 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
private final int mAnimationDuration;
private final int mDetailPadding;
private final TextAppearanceSpan mEpisodeTitleStyle;
+ private final String mProgramRecordableText;
+ private final String mRecordingScheduledText;
+ private final String mRecordingConflictText;
+ private final String mRecordingFailedText;
+ private final String mRecordingInProgressText;
+ private final int mDvrPaddingStartWithTrack;
+ private final int mDvrPaddingStartWithOutTrack;
public ProgramTableAdapter(Context context, ProgramManager programManager,
ProgramGuide programGuide) {
mContext = context;
+ mAccessibilityManager =
+ (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE);
mTvInputManagerHelper = TvApplication.getSingletons(context).getTvInputManagerHelper();
+ if (CommonFeatures.DVR.isEnabled(context)) {
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ } else {
+ mDvrManager = null;
+ mDvrDataManager = null;
+ }
mProgramManager = programManager;
mProgramGuide = programGuide;
@@ -110,26 +141,36 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
R.string.program_title_for_no_information);
mProgramTitleForBlockedChannel = res.getString(
R.string.program_title_for_blocked_channel);
- mChannelTextColor = Utils.getColor(res,
- R.color.program_guide_table_header_column_channel_number_text_color);
- mChannelBlockedTextColor = Utils.getColor(res,
- R.color.program_guide_table_header_column_channel_number_blocked_text_color);
- mDetailTextColor = Utils.getColor(res,
- R.color.program_guide_table_detail_title_text_color);
- mDetailGrayedTextColor = Utils.getColor(res,
- R.color.program_guide_table_detail_title_grayed_text_color);
+ mChannelTextColor = res.getColor(
+ R.color.program_guide_table_header_column_channel_number_text_color, null);
+ mChannelBlockedTextColor = res.getColor(
+ R.color.program_guide_table_header_column_channel_number_blocked_text_color, null);
+ mDetailTextColor = res.getColor(
+ R.color.program_guide_table_detail_title_text_color, null);
+ mDetailGrayedTextColor = res.getColor(
+ R.color.program_guide_table_detail_title_grayed_text_color, null);
mAnimationDuration =
res.getInteger(R.integer.program_guide_table_detail_fade_anim_duration);
mDetailPadding = res.getDimensionPixelOffset(
R.dimen.program_guide_table_detail_padding);
+ mProgramRecordableText = res.getString(R.string.dvr_epg_program_recordable);
+ mRecordingScheduledText = res.getString(R.string.dvr_epg_program_recording_scheduled);
+ mRecordingConflictText = res.getString(R.string.dvr_epg_program_recording_conflict);
+ mRecordingFailedText = res.getString(R.string.dvr_epg_program_recording_failed);
+ mRecordingInProgressText = res.getString(R.string.dvr_epg_program_recording_in_progress);
+ mDvrPaddingStartWithTrack = res.getDimensionPixelOffset(
+ R.dimen.program_guide_table_detail_dvr_margin_start);
+ mDvrPaddingStartWithOutTrack = res.getDimensionPixelOffset(
+ R.dimen.program_guide_table_detail_dvr_margin_start_without_track);
int episodeTitleSize = res.getDimensionPixelSize(
R.dimen.program_guide_table_detail_episode_title_text_size);
ColorStateList episodeTitleColor = ColorStateList.valueOf(
- Utils.getColor(res, R.color.program_guide_table_detail_episode_title_text_color));
+ res.getColor(R.color.program_guide_table_detail_episode_title_text_color, null));
mEpisodeTitleStyle = new TextAppearanceSpan(null, 0, episodeTitleSize,
episodeTitleColor, null);
+ mCriticScoreViews = new ArrayList<>();
mRecycledViewPool = new RecycledViewPool();
mRecycledViewPool.setMaxRecycledViews(R.layout.program_guide_table_item,
context.getResources().getInteger(
@@ -137,12 +178,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mProgramManager.addListener(new ProgramManager.ListenerAdapter() {
@Override
public void onChannelsUpdated() {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- update();
- }
- });
+ update();
}
});
update();
@@ -180,6 +216,15 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
}
@Override
+ public void onBindViewHolder(ProgramRowHolder holder, int position, List<Object> payloads) {
+ if (!payloads.isEmpty()) {
+ holder.updateDetailView();
+ } else {
+ super.onBindViewHolder(holder, position, payloads);
+ }
+ }
+
+ @Override
public ProgramRowHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
ProgramRow programRow = (ProgramRow) itemView.findViewById(R.id.row);
@@ -193,6 +238,17 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
int pos = mProgramManager.getProgramIdIndex(tableEntry.channelId, tableEntry.getId());
if (DEBUG) Log.d(TAG, "update(" + channelIndex + ", " + pos + ")");
mProgramListAdapters.get(channelIndex).notifyItemChanged(pos, tableEntry);
+ notifyItemChanged(channelIndex, true);
+ }
+
+ @Override
+ public void onViewAttachedToWindow(ProgramRowHolder holder) {
+ holder.onAttachedToWindow();
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(ProgramRowHolder holder) {
+ holder.onDetachedFromWindow();
}
// TODO: make it static
@@ -222,15 +278,29 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
}
};
+ private final ViewTreeObserver.OnGlobalFocusChangeListener mGlobalFocusChangeListener =
+ new ViewTreeObserver.OnGlobalFocusChangeListener() {
+ @Override
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ onChildFocus(isChild(oldFocus) ? oldFocus : null,
+ isChild(newFocus) ? newFocus : null);
+ }
+ };
+
// Members of Program Details
private final ViewGroup mDetailView;
private final ImageView mImageView;
private final ImageView mBlockView;
private final TextView mTitleView;
private final TextView mTimeView;
+ private final LinearLayout mCriticScoresLayout;
private final TextView mDescriptionView;
private final TextView mAspectRatioView;
private final TextView mResolutionView;
+ private final ImageView mDvrIconView;
+ private final TextView mDvrTextIconView;
+ private final TextView mDvrStatusView;
+ private final ViewGroup mDvrIndicator;
// Members of Channel Header
private Channel mChannel;
@@ -257,6 +327,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mDescriptionView = (TextView) mDetailView.findViewById(R.id.desc);
mAspectRatioView = (TextView) mDetailView.findViewById(R.id.aspect_ratio);
mResolutionView = (TextView) mDetailView.findViewById(R.id.resolution);
+ mDvrIconView = (ImageView) mDetailView.findViewById(R.id.dvr_icon);
+ mDvrTextIconView = (TextView) mDetailView.findViewById(R.id.dvr_text_icon);
+ mDvrStatusView = (TextView) mDetailView.findViewById(R.id.dvr_status);
+ mDvrIndicator = (ViewGroup) mContainer.findViewById(R.id.dvr_indicator);
+ mCriticScoresLayout = (LinearLayout) mDetailView.findViewById(R.id.critic_scores);
mChannelHeaderView = mContainer.findViewById(R.id.header_column);
mChannelNumberView = (TextView) mContainer.findViewById(R.id.channel_number);
@@ -264,6 +339,16 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mChannelLogoView = (ImageView) mContainer.findViewById(R.id.channel_logo);
mChannelBlockView = (ImageView) mContainer.findViewById(R.id.channel_block);
mInputLogoView = (ImageView) mContainer.findViewById(R.id.input_logo);
+ mDetailView.setFocusable(mAccessibilityManager.isEnabled());
+ mChannelHeaderView.setFocusable(mAccessibilityManager.isEnabled());
+ mAccessibilityManager.addAccessibilityStateChangeListener(
+ new AccessibilityManager.AccessibilityStateChangeListener() {
+ @Override
+ public void onAccessibilityStateChanged(boolean enable) {
+ mDetailView.setFocusable(enable);
+ mChannelHeaderView.setFocusable(enable);
+ }
+ });
}
public void onBind(int position) {
@@ -331,12 +416,32 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
}
}
+ public boolean isChild(View view) {
+ if (view == null) {
+ return false;
+ }
+ for (ViewParent p = view.getParent(); p != null; p = p.getParent()) {
+ if (p == mContainer) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@Override
public void onChildFocus(View oldFocus, View newFocus) {
if (newFocus == null) {
return;
}
- mSelectedEntry = ((ProgramItemView) newFocus).getTableEntry();
+ // When the accessibility service is enabled, focus might be put on channel's header or
+ // detail view, besides program items.
+ if (newFocus == mChannelHeaderView) {
+ mSelectedEntry = ((ProgramItemView) mProgramRow.getChildAt(0)).getTableEntry();
+ } else if (newFocus == mDetailView) {
+ return;
+ } else {
+ mSelectedEntry = ((ProgramItemView) newFocus).getTableEntry();
+ }
if (oldFocus == null) {
updateDetailView();
return;
@@ -403,7 +508,23 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
});
}
+ private void onAttachedToWindow() {
+ mContainer.getViewTreeObserver()
+ .addOnGlobalFocusChangeListener(mGlobalFocusChangeListener);
+ }
+
+ private void onDetachedFromWindow() {
+ mContainer.getViewTreeObserver()
+ .removeOnGlobalFocusChangeListener(mGlobalFocusChangeListener);
+ }
+
private void updateDetailView() {
+ if (mSelectedEntry == null) {
+ // The view holder is never on focus before.
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "updateDetailView");
+ mCriticScoresLayout.removeAllViews();
if (Program.isValid(mSelectedEntry.program)) {
mTitleView.setTextColor(mDetailTextColor);
Context context = itemView.getContext();
@@ -417,11 +538,11 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
createProgramPosterArtCallback(this, program));
}
- if (TextUtils.isEmpty(program.getEpisodeTitle())) {
+ String episodeTitle = program.getEpisodeDisplayTitle(mContext);
+ if (TextUtils.isEmpty(episodeTitle)) {
mTitleView.setText(program.getTitle());
} else {
String title = program.getTitle();
- String episodeTitle = program.getEpisodeDisplayTitle(mContext);
String fullTitle = title + " " + episodeTitle;
SpannableString text = new SpannableString(fullTitle);
@@ -435,6 +556,65 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
program.getStartTimeUtcMillis(),
program.getEndTimeUtcMillis(), false));
+ boolean trackMetaDataVisible = false;
+ trackMetaDataVisible |=
+ updateTextView(mAspectRatioView, Utils.getAspectRatioString(
+ program.getVideoWidth(), program.getVideoHeight()));
+
+ int videoDefinitionLevel = Utils.getVideoDefinitionLevelFromSize(
+ program.getVideoWidth(), program.getVideoHeight());
+ trackMetaDataVisible |=
+ updateTextView(mResolutionView, Utils.getVideoDefinitionLevelString(
+ context, videoDefinitionLevel));
+
+ if (mDvrManager != null && mDvrManager.isProgramRecordable(program)) {
+ ScheduledRecording scheduledRecording =
+ mDvrDataManager.getScheduledRecordingForProgramId(program.getId());
+ String statusText = mProgramRecordableText;
+ int iconResId = 0;
+ if (scheduledRecording != null) {
+ if (mDvrManager.isConflicting(scheduledRecording)) {
+ iconResId = R.drawable.ic_warning_white_12dp;
+ statusText = mRecordingConflictText;
+ } else {
+ switch (scheduledRecording.getState()) {
+ case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
+ iconResId = R.drawable.ic_recording_program;
+ statusText = mRecordingInProgressText;
+ break;
+ case ScheduledRecording.STATE_RECORDING_NOT_STARTED:
+ iconResId = R.drawable.ic_scheduled_white;
+ statusText = mRecordingScheduledText;
+ break;
+ case ScheduledRecording.STATE_RECORDING_FAILED:
+ iconResId = R.drawable.ic_warning_white_12dp;
+ statusText = mRecordingFailedText;
+ break;
+ default:
+ iconResId = 0;
+ }
+ }
+ }
+ if (iconResId == 0) {
+ mDvrIconView.setVisibility(View.GONE);
+ mDvrTextIconView.setVisibility(View.VISIBLE);
+ } else {
+ mDvrTextIconView.setVisibility(View.GONE);
+ mDvrIconView.setImageResource(iconResId);
+ mDvrIconView.setVisibility(View.VISIBLE);
+ }
+ if (!trackMetaDataVisible) {
+ mDvrIndicator.setPaddingRelative(mDvrPaddingStartWithOutTrack, 0, 0, 0);
+ } else {
+ mDvrIndicator.setPaddingRelative(mDvrPaddingStartWithTrack, 0, 0, 0);
+ }
+ mDvrIndicator.setVisibility(View.VISIBLE);
+ mDvrStatusView.setText(statusText);
+ } else {
+ mDvrIndicator.setVisibility(View.GONE);
+ }
+
+
if (blockedRating == null) {
mBlockView.setVisibility(View.GONE);
updateTextView(mDescriptionView, program.getDescription());
@@ -442,14 +622,6 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mBlockView.setVisibility(View.VISIBLE);
updateTextView(mDescriptionView, getBlockedDescription(blockedRating));
}
-
- updateTextView(mAspectRatioView, Utils.getAspectRatioString(
- program.getVideoWidth(), program.getVideoHeight()));
-
- int videoDefinitionLevel = Utils.getVideoDefinitionLevelFromSize(
- program.getVideoWidth(), program.getVideoHeight());
- updateTextView(mResolutionView, Utils.getVideoDefinitionLevelString(
- context, videoDefinitionLevel));
} else {
mTitleView.setTextColor(mDetailGrayedTextColor);
if (mSelectedEntry.isBlocked()) {
@@ -460,6 +632,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mImageView.setVisibility(View.GONE);
mBlockView.setVisibility(View.GONE);
mTimeView.setVisibility(View.GONE);
+ mDvrIndicator.setVisibility(View.GONE);
mDescriptionView.setVisibility(View.GONE);
mAspectRatioView.setVisibility(View.GONE);
mResolutionView.setVisibility(View.GONE);
@@ -526,12 +699,16 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
}
}
- private void updateTextView(TextView textView, String text) {
+ // The return value of this method will indicate the target view is visible (true)
+ // or gone (false).
+ private boolean updateTextView(TextView textView, String text) {
if (!TextUtils.isEmpty(text)) {
textView.setVisibility(View.VISIBLE);
textView.setText(text);
+ return true;
} else {
textView.setVisibility(View.GONE);
+ return false;
}
}
@@ -554,6 +731,26 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
mInputLogoView.setVisibility(View.VISIBLE);
}
+ private void updateCriticScoreView(ProgramRowHolder holder, final long programId,
+ CriticScore criticScore, View view) {
+ TextView criticScoreSource = (TextView) view.findViewById(R.id.critic_score_source);
+ TextView criticScoreText = (TextView) view.findViewById(R.id.critic_score_score);
+ ImageView criticScoreLogo = (ImageView) view.findViewById(R.id.critic_score_logo);
+
+ //set the appropriate information in the views
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
+ criticScoreSource.setText(Html.fromHtml(criticScore.source,
+ Html.FROM_HTML_MODE_LEGACY));
+ } else {
+ criticScoreSource.setText(Html.fromHtml(criticScore.source));
+ }
+ criticScoreText.setText(criticScore.score);
+ criticScoreSource.setVisibility(View.VISIBLE);
+ criticScoreText.setVisibility(View.VISIBLE);
+ ImageLoader.loadBitmap(mContext, criticScore.logoUrl,
+ createCriticScoreLogoCallback(holder, programId, criticScoreLogo));
+ }
+
private void onHorizontalScrolled() {
if (mDetailInAnimator != null) {
mHandler.removeCallbacks(mDetailInStarter);
@@ -562,6 +759,23 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
}
}
+ private static ImageLoaderCallback<ProgramRowHolder> createCriticScoreLogoCallback(
+ ProgramRowHolder holder, final long programId, ImageView logoView) {
+ return new ImageLoaderCallback<ProgramRowHolder>(holder) {
+ @Override
+ public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap logoImage) {
+ if (logoImage == null || holder.mSelectedEntry == null
+ || holder.mSelectedEntry.program == null
+ || holder.mSelectedEntry.program.getId() != programId) {
+ logoView.setVisibility(View.GONE);
+ } else {
+ logoView.setImageBitmap(logoImage);
+ logoView.setVisibility(View.VISIBLE);
+ }
+ }
+ };
+ }
+
private static ImageLoaderCallback<ProgramRowHolder> createProgramPosterArtCallback(
ProgramRowHolder holder, final Program program) {
return new ImageLoaderCallback<ProgramRowHolder>(holder) {
@@ -599,7 +813,7 @@ public class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapte
return new ImageLoaderCallback<ProgramRowHolder>(holder) {
@Override
public void onBitmapLoaded(ProgramRowHolder holder, @Nullable Bitmap logo) {
- if (logo != null && info.getId()
+ if (logo != null && holder.mChannel != null && info.getId()
.equals(holder.mChannel.getInputId())) {
holder.updateInputLogoInternal(logo);
}
diff --git a/src/com/android/tv/menu/ActionCardView.java b/src/com/android/tv/menu/ActionCardView.java
index 2d72b06f..54892cac 100644
--- a/src/com/android/tv/menu/ActionCardView.java
+++ b/src/com/android/tv/menu/ActionCardView.java
@@ -69,11 +69,13 @@ public class ActionCardView extends FrameLayout implements ItemListRowView.CardV
mStateView.setText(action.getActionDescription(getContext()));
if (action.isEnabled()) {
setEnabled(true);
+ setFocusable(true);
mIconView.setAlpha(OPACITY_ENABLED);
mLabelView.setAlpha(OPACITY_ENABLED);
mStateView.setAlpha(OPACITY_ENABLED);
} else {
setEnabled(false);
+ setFocusable(false);
mIconView.setAlpha(OPACITY_DISABLED);
mLabelView.setAlpha(OPACITY_DISABLED);
mStateView.setAlpha(OPACITY_DISABLED);
diff --git a/src/com/android/tv/menu/AppLinkCardView.java b/src/com/android/tv/menu/AppLinkCardView.java
index 74375da4..bfb5e3f1 100644
--- a/src/com/android/tv/menu/AppLinkCardView.java
+++ b/src/com/android/tv/menu/AppLinkCardView.java
@@ -30,7 +30,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
@@ -40,7 +39,6 @@ import com.android.tv.data.Channel;
import com.android.tv.util.BitmapUtils;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.TvInputManagerHelper;
-import com.android.tv.util.Utils;
/**
* A view to render an app link card.
@@ -49,10 +47,6 @@ public class AppLinkCardView extends BaseCardView<Channel> {
private static final String TAG = MenuView.TAG;
private static final boolean DEBUG = MenuView.DEBUG;
- private final float mCardHeight;
- private final float mExtendedCardHeight;
- private final float mTextViewHeight;
- private final float mExtendedTextViewCardHeight;
private final int mCardImageWidth;
private final int mCardImageHeight;
private final int mIconWidth;
@@ -63,12 +57,9 @@ public class AppLinkCardView extends BaseCardView<Channel> {
private ImageView mImageView;
private View mGradientView;
private TextView mAppInfoView;
- private TextView mMetaViewFocused;
- private TextView mMetaViewUnfocused;
private View mMetaViewHolder;
private Channel mChannel;
private Intent mIntent;
- private boolean mExtendViewOnFocus;
private final PackageManager mPackageManager;
private final TvInputManagerHelper mTvInputManagerHelper;
@@ -85,19 +76,12 @@ public class AppLinkCardView extends BaseCardView<Channel> {
mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width);
mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.card_image_layout_height);
- mCardHeight = getResources().getDimensionPixelSize(R.dimen.card_layout_height);
- mExtendedCardHeight = getResources().getDimensionPixelOffset(
- R.dimen.card_layout_height_extended);
mIconWidth = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_width);
mIconHeight = getResources().getDimensionPixelSize(R.dimen.app_link_card_icon_height);
mIconPadding = getResources().getDimensionPixelOffset(R.dimen.app_link_card_icon_padding);
mPackageManager = context.getPackageManager();
mTvInputManagerHelper = ((MainActivity) context).getTvInputManagerHelper();
- mTextViewHeight = getResources().getDimensionPixelSize(
- R.dimen.card_meta_layout_height);
- mExtendedTextViewCardHeight = getResources().getDimensionPixelOffset(
- R.dimen.card_meta_layout_height_extended);
- mIconColorFilter = Utils.getColor(getResources(), R.color.app_link_card_icon_color_filter);
+ mIconColorFilter = getResources().getColor(R.color.app_link_card_icon_color_filter, null);
}
/**
@@ -120,7 +104,7 @@ public class AppLinkCardView extends BaseCardView<Channel> {
switch (linkType) {
case Channel.APP_LINK_TYPE_CHANNEL:
- setMetaViewText(mChannel.getAppLinkText());
+ setText(mChannel.getAppLinkText());
mAppInfoView.setVisibility(VISIBLE);
mGradientView.setVisibility(VISIBLE);
mAppInfoView.setCompoundDrawablePadding(mIconPadding);
@@ -138,7 +122,7 @@ public class AppLinkCardView extends BaseCardView<Channel> {
}
break;
case Channel.APP_LINK_TYPE_APP:
- setMetaViewText(getContext().getString(
+ setText(getContext().getString(
R.string.channels_item_app_link_app_launcher,
mPackageManager.getApplicationLabel(appInfo)));
mAppInfoView.setVisibility(GONE);
@@ -164,17 +148,8 @@ public class AppLinkCardView extends BaseCardView<Channel> {
} else {
setCardImageWithBanner(appInfo);
}
-
- mMetaViewFocused.measure(MeasureSpec.makeMeasureSpec(mCardImageWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- mExtendViewOnFocus = mMetaViewFocused.getLineCount() > 1;
- if (mExtendViewOnFocus) {
- setMetaViewFocusedAlpha(selected ? 1f : 0f);
- } else {
- setMetaViewFocusedAlpha(1f);
- }
-
- // Call super.onBind() at the end in order to make getCardHeight() return a proper value.
+ // Call super.onBind() at the end intentionally. In order to correctly handle extension of
+ // text view, text should be set before calling super.onBind.
super.onBind(channel, selected);
}
@@ -228,32 +203,6 @@ public class AppLinkCardView extends BaseCardView<Channel> {
mGradientView = findViewById(R.id.image_gradient);
mAppInfoView = (TextView) findViewById(R.id.app_info);
mMetaViewHolder = findViewById(R.id.app_link_text_holder);
- mMetaViewFocused = (TextView) findViewById(R.id.app_link_text_focused);
- mMetaViewUnfocused = (TextView) findViewById(R.id.app_link_text_unfocused);
- }
-
- @Override
- protected void onFocusAnimationStart(boolean selected) {
- if (mExtendViewOnFocus) {
- setMetaViewFocusedAlpha(selected ? 1f : 0f);
- }
- }
-
- @Override
- protected void onSetFocusAnimatedValue(float animatedValue) {
- super.onSetFocusAnimatedValue(animatedValue);
- if (mExtendViewOnFocus) {
- ViewGroup.LayoutParams params = mMetaViewUnfocused.getLayoutParams();
- params.height = Math.round(mTextViewHeight
- + (mExtendedTextViewCardHeight - mTextViewHeight) * animatedValue);
- setMetaViewLayoutParams(params);
- setMetaViewFocusedAlpha(animatedValue);
- }
- }
-
- @Override
- protected float getCardHeight() {
- return (mExtendViewOnFocus && isFocused()) ? mExtendedCardHeight : mCardHeight;
}
// Try to set the card image with following order:
@@ -302,23 +251,8 @@ public class AppLinkCardView extends BaseCardView<Channel> {
@Override
public void onGenerated(Palette palette) {
mMetaViewHolder.setBackgroundColor(palette.getDarkVibrantColor(
- Utils.getColor(getResources(), R.color.channel_card_meta_background)));
+ getResources().getColor(R.color.channel_card_meta_background, null)));
}
});
}
-
- private void setMetaViewLayoutParams(ViewGroup.LayoutParams params) {
- mMetaViewFocused.setLayoutParams(params);
- mMetaViewUnfocused.setLayoutParams(params);
- }
-
- private void setMetaViewText(String text) {
- mMetaViewFocused.setText(text);
- mMetaViewUnfocused.setText(text);
- }
-
- private void setMetaViewFocusedAlpha(float focusedAlpha) {
- mMetaViewFocused.setAlpha(focusedAlpha);
- mMetaViewUnfocused.setAlpha(1f - focusedAlpha);
- }
}
diff --git a/src/com/android/tv/menu/BaseCardView.java b/src/com/android/tv/menu/BaseCardView.java
index b4500dd1..c6a34a5d 100644
--- a/src/com/android/tv/menu/BaseCardView.java
+++ b/src/com/android/tv/menu/BaseCardView.java
@@ -21,10 +21,13 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Outline;
+import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.widget.LinearLayout;
+import android.widget.TextView;
import com.android.tv.R;
@@ -44,6 +47,16 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo
private final float mVerticalCardMargin;
private final float mCardCornerRadius;
private float mFocusAnimatedValue;
+ private boolean mExtendViewOnFocus;
+ private final float mExtendedCardHeight;
+ private final float mTextViewHeight;
+ private final float mExtendedTextViewHeight;
+ @Nullable
+ private TextView mTextView;
+ @Nullable
+ private TextView mTextViewFocused;
+ private final int mCardImageWidth;
+ private final float mCardHeight;
public BaseCardView(Context context) {
this(context, null);
@@ -72,16 +85,42 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCardCornerRadius);
}
});
+ mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width);
+ mCardHeight = getResources().getDimensionPixelSize(R.dimen.card_layout_height);
+ mExtendedCardHeight = getResources().getDimensionPixelSize(
+ R.dimen.card_layout_height_extended);
+ mTextViewHeight = getResources().getDimensionPixelSize(R.dimen.card_meta_layout_height);
+ mExtendedTextViewHeight = getResources().getDimensionPixelOffset(
+ R.dimen.card_meta_layout_height_extended);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTextView = (TextView) findViewById(R.id.card_text);
+ mTextViewFocused = (TextView) findViewById(R.id.card_text_focused);
}
/**
* Called when the view is displayed.
+ *
+ * Before onBind is called, this view's text should be set to determine if it'll be extended
+ * or not in focus state.
*/
@Override
public void onBind(T item, boolean selected) {
- // Note that getCardHeight() will be called by setFocusAnimatedValue().
- // Therefore, be sure that getCardHeight() has a proper value before this method is called.
- setFocusAnimatedValue(selected ? SCALE_FACTOR_1F : SCALE_FACTOR_0F);
+ if (mTextView != null && mTextViewFocused != null) {
+ mTextViewFocused.measure(
+ MeasureSpec.makeMeasureSpec(mCardImageWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
+ mExtendViewOnFocus = mTextViewFocused.getLineCount() > 1;
+ if (mExtendViewOnFocus) {
+ setTextViewFocusedAlpha(selected ? 1f : 0f);
+ } else {
+ setTextViewFocusedAlpha(1f);
+ }
+ }
+ setFocusAnimatedValue(selected ? SCALE_FACTOR_1F : SCALE_FACTOR_0F);
}
@Override
@@ -108,10 +147,48 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo
}
/**
+ * Sets text of this card view.
+ */
+ public void setText(int resId) {
+ if (mTextViewFocused != null) {
+ mTextViewFocused.setText(resId);
+ }
+ if (mTextView != null) {
+ mTextView.setText(resId);
+ }
+ }
+
+ /**
+ * Sets text of this card view.
+ */
+ public void setText(String text) {
+ if (mTextViewFocused != null) {
+ mTextViewFocused.setText(text);
+ }
+ if (mTextView != null) {
+ mTextView.setText(text);
+ }
+ }
+
+ /**
+ * Enables or disables text view of this card view.
+ */
+ public void setTextViewEnabled(boolean enabled) {
+ if (mTextViewFocused != null) {
+ mTextViewFocused.setEnabled(enabled);
+ }
+ if (mTextView != null) {
+ mTextView.setEnabled(enabled);
+ }
+ }
+
+ /**
* Called when the focus animation started.
*/
protected void onFocusAnimationStart(boolean selected) {
- // do nothing.
+ if (mExtendViewOnFocus) {
+ setTextViewFocusedAlpha(selected ? 1f : 0f);
+ }
}
/**
@@ -126,10 +203,19 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo
* between {@code SCALE_FACTOR_0F} and {@code SCALE_FACTOR_1F}.
*/
protected void onSetFocusAnimatedValue(float animatedValue) {
- float scale = 1f + (mVerticalCardMargin / getCardHeight()) * animatedValue;
+ float cardViewHeight = (mExtendViewOnFocus && isFocused())
+ ? mExtendedCardHeight : mCardHeight;
+ float scale = 1f + (mVerticalCardMargin / cardViewHeight) * animatedValue;
setScaleX(scale);
setScaleY(scale);
setTranslationZ(mFocusTranslationZ * animatedValue);
+ if (mExtendViewOnFocus) {
+ ViewGroup.LayoutParams params = mTextView.getLayoutParams();
+ params.height = Math.round(mTextViewHeight
+ + (mExtendedTextViewHeight - mTextViewHeight) * animatedValue);
+ setTextViewLayoutParams(params);
+ setTextViewFocusedAlpha(animatedValue);
+ }
}
private void setFocusAnimatedValue(float animatedValue) {
@@ -171,8 +257,13 @@ public abstract class BaseCardView<T> extends LinearLayout implements ItemListRo
}
}
- /**
- * The implementation should return the height of the card.
- */
- protected abstract float getCardHeight();
+ private void setTextViewLayoutParams(ViewGroup.LayoutParams params) {
+ mTextViewFocused.setLayoutParams(params);
+ mTextView.setLayoutParams(params);
+ }
+
+ private void setTextViewFocusedAlpha(float focusedAlpha) {
+ mTextViewFocused.setAlpha(focusedAlpha);
+ mTextView.setAlpha(1f - focusedAlpha);
+ }
}
diff --git a/src/com/android/tv/menu/ChannelCardView.java b/src/com/android/tv/menu/ChannelCardView.java
index 860da224..1c8015a6 100644
--- a/src/com/android/tv/menu/ChannelCardView.java
+++ b/src/com/android/tv/menu/ChannelCardView.java
@@ -23,7 +23,6 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
@@ -42,10 +41,6 @@ public class ChannelCardView extends BaseCardView<Channel> {
private static final String TAG = MenuView.TAG;
private static final boolean DEBUG = MenuView.DEBUG;
- private final float mCardHeight;
- private final float mExtendedCardHeight;
- private final float mProgramNameViewHeight;
- private final float mExtendedTextViewCardHeight;
private final int mCardImageWidth;
private final int mCardImageHeight;
@@ -53,11 +48,8 @@ public class ChannelCardView extends BaseCardView<Channel> {
private View mGradientView;
private TextView mChannelNumberNameView;
private ProgressBar mProgressBar;
- private TextView mMetaViewFocused;
- private TextView mMetaViewUnfocused;
private Channel mChannel;
private Program mProgram;
- private boolean mExtendViewOnFocus;
private final MainActivity mMainActivity;
public ChannelCardView(Context context) {
@@ -70,17 +62,8 @@ public class ChannelCardView extends BaseCardView<Channel> {
public ChannelCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
mCardImageWidth = getResources().getDimensionPixelSize(R.dimen.card_image_layout_width);
mCardImageHeight = getResources().getDimensionPixelSize(R.dimen.card_image_layout_height);
- mCardHeight = getResources().getDimensionPixelSize(R.dimen.card_layout_height);
- mExtendedCardHeight = getResources().getDimensionPixelSize(
- R.dimen.card_layout_height_extended);
- mProgramNameViewHeight = getResources().getDimensionPixelSize(
- R.dimen.card_meta_layout_height);
- mExtendedTextViewCardHeight = getResources().getDimensionPixelOffset(
- R.dimen.card_meta_layout_height_extended);
-
mMainActivity = (MainActivity) context;
}
@@ -90,8 +73,6 @@ public class ChannelCardView extends BaseCardView<Channel> {
mImageView = (ImageView) findViewById(R.id.image);
mGradientView = findViewById(R.id.image_gradient);
mChannelNumberNameView = (TextView) findViewById(R.id.channel_number_and_name);
- mMetaViewFocused = (TextView) findViewById(R.id.channel_title_focused);
- mMetaViewUnfocused = (TextView) findViewById(R.id.channel_title_unfocused);
mProgressBar = (ProgressBar) findViewById(R.id.progress);
}
@@ -103,38 +84,25 @@ public class ChannelCardView extends BaseCardView<Channel> {
}
mChannel = channel;
mProgram = null;
- if (TextUtils.isEmpty(mChannel.getDisplayName())) {
- mChannelNumberNameView.setText(mChannel.getDisplayNumber());
- } else {
- mChannelNumberNameView.setText(mChannel.getDisplayNumber() + " "
- + mChannel.getDisplayName());
- }
+ mChannelNumberNameView.setText(mChannel.getDisplayText());
mChannelNumberNameView.setVisibility(VISIBLE);
mImageView.setImageResource(R.drawable.ic_recent_thumbnail_default);
mImageView.setBackgroundResource(R.color.channel_card);
mGradientView.setVisibility(View.GONE);
mProgressBar.setVisibility(GONE);
- setMetaViewEnabled(true);
+ setTextViewEnabled(true);
if (mMainActivity.getParentalControlSettings().isParentalControlsEnabled()
&& mChannel.isLocked()) {
- setMetaViewText(R.string.program_title_for_blocked_channel);
+ setText(R.string.program_title_for_blocked_channel);
return;
} else {
- setMetaViewText("");
+ setText("");
}
updateProgramInformation();
- mMetaViewFocused.measure(
- MeasureSpec.makeMeasureSpec(mCardImageWidth, MeasureSpec.EXACTLY),
- MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
- if (mExtendViewOnFocus = mMetaViewFocused.getLineCount() > 1) {
- setMetaViewFocusedAlpha(selected ? 1f : 0f);
- } else {
- setMetaViewFocusedAlpha(1f);
- }
-
- // Call super.onBind() at the end in order to make getCardHeight() return a proper value.
+ // Call super.onBind() at the end intentionally. In order to correctly handle extension of
+ // text view, text should be set before calling super.onBind.
super.onBind(channel, selected);
}
@@ -158,40 +126,16 @@ public class ChannelCardView extends BaseCardView<Channel> {
mGradientView.setVisibility(View.VISIBLE);
}
- @Override
- protected void onFocusAnimationStart(boolean selected) {
- if (mExtendViewOnFocus) {
- setMetaViewFocusedAlpha(selected ? 1f : 0f);
- }
- }
-
- @Override
- protected void onSetFocusAnimatedValue(float animatedValue) {
- super.onSetFocusAnimatedValue(animatedValue);
- if (mExtendViewOnFocus) {
- ViewGroup.LayoutParams params = mMetaViewUnfocused.getLayoutParams();
- params.height = Math.round(mProgramNameViewHeight
- + (mExtendedTextViewCardHeight - mProgramNameViewHeight) * animatedValue);
- setMetaViewLayoutParams(params);
- setMetaViewFocusedAlpha(animatedValue);
- }
- }
-
- @Override
- protected float getCardHeight() {
- return (mExtendViewOnFocus && isFocused()) ? mExtendedCardHeight : mCardHeight;
- }
-
private void updateProgramInformation() {
if (mChannel == null) {
return;
}
mProgram = mMainActivity.getProgramDataManager().getCurrentProgram(mChannel.getId());
if (mProgram == null || TextUtils.isEmpty(mProgram.getTitle())) {
- setMetaViewEnabled(false);
- setMetaViewText(R.string.program_title_for_no_information);
+ setTextViewEnabled(false);
+ setText(R.string.program_title_for_no_information);
} else {
- setMetaViewText(mProgram.getTitle());
+ setText(mProgram.getTitle());
}
if (mProgram == null) {
@@ -222,29 +166,4 @@ public class ChannelCardView extends BaseCardView<Channel> {
createProgramPosterArtCallback(this, mProgram));
}
}
-
- private void setMetaViewLayoutParams(ViewGroup.LayoutParams params) {
- mMetaViewFocused.setLayoutParams(params);
- mMetaViewUnfocused.setLayoutParams(params);
- }
-
- private void setMetaViewText(String text) {
- mMetaViewFocused.setText(text);
- mMetaViewUnfocused.setText(text);
- }
-
- private void setMetaViewText(int resId) {
- mMetaViewFocused.setText(resId);
- mMetaViewUnfocused.setText(resId);
- }
-
- private void setMetaViewEnabled(boolean enabled) {
- mMetaViewFocused.setEnabled(enabled);
- mMetaViewUnfocused.setEnabled(enabled);
- }
-
- private void setMetaViewFocusedAlpha(float focusedAlpha) {
- mMetaViewFocused.setAlpha(focusedAlpha);
- mMetaViewUnfocused.setAlpha(1f - focusedAlpha);
- }
}
diff --git a/src/com/android/tv/menu/ChannelsRowAdapter.java b/src/com/android/tv/menu/ChannelsRowAdapter.java
index 200f4ac0..c8e1bd05 100644
--- a/src/com/android/tv/menu/ChannelsRowAdapter.java
+++ b/src/com/android/tv/menu/ChannelsRowAdapter.java
@@ -19,16 +19,15 @@ package com.android.tv.menu;
import android.content.Context;
import android.content.Intent;
import android.media.tv.TvInputInfo;
-import android.os.Build;
-import android.support.v4.os.BuildCompat;
import android.view.View;
-import com.android.tv.MainActivity;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
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;
@@ -41,15 +40,17 @@ import java.util.List;
* An adapter of the Channels row.
*/
public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel> {
- // There are four special cards: guide, setup, dvr, record, applink.
+ private static final String TAG = "ChannelsRowAdapter";
+
+ // There are four special cards: guide, setup, dvr, applink.
private static final int SIZE_OF_VIEW_TYPE = 5;
private final Context mContext;
private final Tracker mTracker;
private final Recommender mRecommender;
+ private final DvrDataManager mDvrDataManager;
private final int mMaxCount;
private final int mMinCount;
- private final boolean mDvrFeatureEnabled;
private final int[] mViewType = new int[SIZE_OF_VIEW_TYPE];
private final View.OnClickListener mGuideOnClickListener = new View.OnClickListener() {
@@ -71,28 +72,11 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
private final View.OnClickListener mDvrOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
- Utils.showToastMessageForDeveloperFeature(view.getContext());
mTracker.sendMenuClicked(R.string.channels_item_dvr);
getMainActivity().getOverlayManager().showDvrManager();
}
};
- private final View.OnClickListener mRecordOnClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- Utils.showToastMessageForDeveloperFeature(view.getContext());
- RecordCardView v = ((RecordCardView) view);
- boolean isRecording = v.isRecording();
- mTracker.sendMenuClicked(isRecording ? R.string.channels_item_record_start
- : R.string.channels_item_record_stop);
- if (!isRecording) {
- v.startRecording();
- } else {
- v.stopRecording();
- }
- }
- };
-
private final View.OnClickListener mAppLinkOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -118,12 +102,17 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
public ChannelsRowAdapter(Context context, Recommender recommender,
int minCount, int maxCount) {
super(context);
- mTracker = TvApplication.getSingletons(context).getTracker();
mContext = context;
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ mTracker = appSingletons.getTracker();
+ if (CommonFeatures.DVR.isEnabled(context)) {
+ mDvrDataManager = appSingletons.getDvrDataManager();
+ } else {
+ mDvrDataManager = null;
+ }
mRecommender = recommender;
mMinCount = minCount;
mMaxCount = maxCount;
- mDvrFeatureEnabled = CommonFeatures.DVR.isEnabled(mContext) && BuildCompat.isAtLeastN();
}
@Override
@@ -152,8 +141,8 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
viewHolder.itemView.setOnClickListener(mAppLinkOnClickListener);
} else if (viewType == R.layout.menu_card_dvr) {
viewHolder.itemView.setOnClickListener(mDvrOnClickListener);
- } else if (viewType == R.layout.menu_card_record) {
- viewHolder.itemView.setOnClickListener(mRecordOnClickListener);
+ SimpleCardView view = (SimpleCardView) viewHolder.itemView;
+ view.setText(R.string.channels_item_dvr);
} else {
viewHolder.itemView.setTag(getItemList().get(position));
viewHolder.itemView.setOnClickListener(mChannelOnClickListener);
@@ -170,25 +159,19 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
TvInputManagerHelper inputManager = TvApplication.getSingletons(mContext)
.getTvInputManagerHelper();
boolean showSetupCard = SetupUtils.getInstance(mContext).hasNewInput(inputManager);
- Channel currentChannel = ((MainActivity) mContext).getCurrentChannel();
- boolean showAppLinkCard = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
- && currentChannel != null
- && currentChannel.getAppLinkType(mContext) != Channel.APP_LINK_TYPE_NONE;
+ Channel currentChannel = getMainActivity().getCurrentChannel();
+ boolean showAppLinkCard = currentChannel != null
+ && currentChannel.getAppLinkType(mContext) != Channel.APP_LINK_TYPE_NONE
+ // Sometimes applicationInfo can be null. b/28932537
+ && inputManager.getTvInputAppInfo(currentChannel.getInputId()) != null;
boolean showDvrCard = false;
- boolean showRecordCard = false;
- if (mDvrFeatureEnabled) {
+ if (mDvrDataManager != null) {
for (TvInputInfo info : inputManager.getTvInputInfos(true, true)) {
if (info.canRecord()) {
showDvrCard = true;
break;
}
}
- if (currentChannel != null && currentChannel.getInputId() != null) {
- TvInputInfo inputInfo = inputManager.getTvInputInfo(currentChannel.getInputId());
- if ((inputInfo.canRecord() && inputInfo.getTunerCount() > 1)) {
- showRecordCard = true;
- }
- }
}
mViewType[0] = R.layout.menu_card_guide;
@@ -201,10 +184,6 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
channelList.add(dummyChannel);
mViewType[index++] = R.layout.menu_card_dvr;
}
- if (showRecordCard) {
- channelList.add(currentChannel);
- mViewType[index++] = R.layout.menu_card_record;
- }
if (showAppLinkCard) {
channelList.add(currentChannel);
mViewType[index++] = R.layout.menu_card_app_link;
@@ -226,8 +205,8 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channel>
int count = channelList.size();
// If the number of recommended channels is not enough, add more from the recent channel
// list.
- if (count < mMinCount && mContext instanceof MainActivity) {
- for (long channelId : ((MainActivity) mContext).getRecentChannels()) {
+ if (count < mMinCount) {
+ for (long channelId : getMainActivity().getRecentChannels()) {
Channel channel = mRecommender.getChannel(channelId);
if (channel == null || channelList.contains(channel)
|| !channel.isBrowsable()) {
diff --git a/src/com/android/tv/menu/IMenuView.java b/src/com/android/tv/menu/IMenuView.java
index 99fb4126..87c5d9f6 100644
--- a/src/com/android/tv/menu/IMenuView.java
+++ b/src/com/android/tv/menu/IMenuView.java
@@ -54,6 +54,13 @@ public interface IMenuView {
boolean update(boolean menuActive);
/**
+ * Updates the menu row.
+ *
+ * <p>Returns <@code true> if the contents have been changed, otherwise {@code false}.
+ */
+ boolean update(String rowId, boolean menuActive);
+
+ /**
* Checks if the menu view is visible or not.
*/
boolean isVisible();
diff --git a/src/com/android/tv/menu/Menu.java b/src/com/android/tv/menu/Menu.java
index 7bb0787e..1160a5b5 100644
--- a/src/com/android/tv/menu/Menu.java
+++ b/src/com/android/tv/menu/Menu.java
@@ -35,10 +35,10 @@ import com.android.tv.analytics.DurationTimer;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.TvCommonUtils;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
import com.android.tv.menu.MenuRowFactory.PartnerRow;
import com.android.tv.menu.MenuRowFactory.PipOptionsRow;
import com.android.tv.menu.MenuRowFactory.TvOptionsRow;
+import com.android.tv.ui.TunableTvView;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -56,7 +56,7 @@ public class Menu {
@IntDef({REASON_NONE, REASON_GUIDE, REASON_PLAY_CONTROLS_PLAY, REASON_PLAY_CONTROLS_PAUSE,
REASON_PLAY_CONTROLS_PLAY_PAUSE, REASON_PLAY_CONTROLS_REWIND,
REASON_PLAY_CONTROLS_FAST_FORWARD, REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS,
- REASON_PLAY_CONTROLS_JUMP_TO_NEXT, REASON_RECORDING_PLAYBACK})
+ REASON_PLAY_CONTROLS_JUMP_TO_NEXT})
public @interface MenuShowReason {}
public static final int REASON_NONE = 0;
public static final int REASON_GUIDE = 1;
@@ -67,20 +67,18 @@ public class Menu {
public static final int REASON_PLAY_CONTROLS_FAST_FORWARD = 6;
public static final int REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS = 7;
public static final int REASON_PLAY_CONTROLS_JUMP_TO_NEXT = 8;
- public static final int REASON_RECORDING_PLAYBACK = 9;
private static final List<String> sRowIdListForReason = new ArrayList<>();
static {
- sRowIdListForReason.add(null); // REASON_NONE
- sRowIdListForReason.add(ChannelsRow.ID); // REASON_GUIDE
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PLAY
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PAUSE
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PLAY_PAUSE
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_REWIND
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_FAST_FORWARD
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_JUMP_TO_NEXT
- sRowIdListForReason.add(PlayControlsRow.ID); // REASON_RECORDING_PLAYBACK
+ sRowIdListForReason.add(null); // REASON_NONE
+ sRowIdListForReason.add(ChannelsRow.ID); // REASON_GUIDE
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PLAY
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PAUSE
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_PLAY_PAUSE
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_REWIND
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_FAST_FORWARD
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS
+ sRowIdListForReason.add(PlayControlsRow.ID); // REASON_PLAY_CONTROLS_JUMP_TO_NEXT
}
private static final String SCREEN_NAME = "Menu";
@@ -94,37 +92,26 @@ public class Menu {
private final OnMenuVisibilityChangeListener mOnMenuVisibilityChangeListener;
private final WeakHandler<Menu> mHandler = new MenuWeakHandler(this, Looper.getMainLooper());
- private final ChannelTuner.Listener mChannelTunerListener = new ChannelTuner.Listener() {
- @Override
- public void onLoadFinished() {}
-
- @Override
- public void onBrowsableChannelListChanged() {
- mMenuView.update(isActive());
- }
-
- @Override
- public void onCurrentChannelUnavailable(Channel channel) {}
-
- @Override
- public void onChannelChanged(Channel previousChannel, Channel currentChannel) {}
- };
-
+ private final MenuUpdater mMenuUpdater;
private final List<MenuRow> mMenuRows = new ArrayList<>();
private final Animator mShowAnimator;
private final Animator mHideAnimator;
- private ChannelTuner mChannelTuner;
private boolean mKeepVisible;
private boolean mAnimationDisabledForTest;
- /**
- * A constructor.
- */
- public Menu(Context context, IMenuView menuView, MenuRowFactory menuRowFactory,
- OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) {
+ @VisibleForTesting
+ Menu(Context context, IMenuView menuView, MenuRowFactory menuRowFactory,
+ OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) {
+ this(context, null, menuView, menuRowFactory, onMenuVisibilityChangeListener);
+ }
+
+ public Menu(Context context, TunableTvView tvView, IMenuView menuView,
+ MenuRowFactory menuRowFactory,
+ OnMenuVisibilityChangeListener onMenuVisibilityChangeListener) {
mMenuView = menuView;
mTracker = TvApplication.getSingletons(context).getTracker();
+ mMenuUpdater = new MenuUpdater(context, tvView, this);
Resources res = context.getResources();
mShowDurationMillis = res.getInteger(R.integer.menu_show_duration);
mOnMenuVisibilityChangeListener = onMenuVisibilityChangeListener;
@@ -152,14 +139,7 @@ public class Menu {
* or not available any more.
*/
public void setChannelTuner(ChannelTuner channelTuner) {
- if (mChannelTuner != null) {
- mChannelTuner.removeListener(mChannelTunerListener);
- }
- mChannelTuner = channelTuner;
- if (mChannelTuner != null) {
- mChannelTuner.addListener(mChannelTunerListener);
- }
- mMenuView.update(isActive());
+ mMenuUpdater.setChannelTuner(channelTuner);
}
private void addMenuRow(MenuRow row) {
@@ -172,7 +152,7 @@ public class Menu {
* Call this method to end the lifetime of the menu.
*/
public void release() {
- setChannelTuner(null);
+ mMenuUpdater.release();
for (MenuRow row : mMenuRows) {
row.release();
}
@@ -199,7 +179,9 @@ public class Menu {
mMenuView.onShow(reason, rowIdToSelect, mAnimationDisabledForTest ? null : new Runnable() {
@Override
public void run() {
- mShowAnimator.start();
+ if (isActive()) {
+ mShowAnimator.start();
+ }
}
});
scheduleHide();
@@ -209,6 +191,9 @@ public class Menu {
* Closes the menu.
*/
public void hide(boolean withAnimation) {
+ if (mShowAnimator.isStarted()) {
+ mShowAnimator.cancel();
+ }
if (!isActive()) {
return;
}
@@ -284,6 +269,16 @@ public class Menu {
}
/**
+ * Updates the menu row.
+ *
+ * <p>Returns <@code true> if the contents have been changed, otherwise {@code false}.
+ */
+ public boolean update(String rowId) {
+ if (DEBUG) Log.d(TAG, "update main menu");
+ return mMenuView.update(rowId, isActive());
+ }
+
+ /**
* This method is called when channels are changed.
*/
public void onRecentChannelsChanged() {
diff --git a/src/com/android/tv/menu/MenuAction.java b/src/com/android/tv/menu/MenuAction.java
index 86153084..0d59552a 100644
--- a/src/com/android/tv/menu/MenuAction.java
+++ b/src/com/android/tv/menu/MenuAction.java
@@ -41,13 +41,16 @@ public class MenuAction {
R.drawable.ic_tvoption_pip);
public static final MenuAction SYSTEMWIDE_PIP_ACTION =
new MenuAction(R.string.options_item_pip, TvOptionsManager.OPTION_SYSTEMWIDE_PIP,
- R.drawable.ic_tvoption_pip);
+ R.drawable.ic_pip_option_layout2);
public static final MenuAction SELECT_AUDIO_LANGUAGE_ACTION =
new MenuAction(R.string.options_item_multi_audio, TvOptionsManager.OPTION_MULTI_AUDIO,
R.drawable.ic_tvoption_multi_track);
public static final MenuAction MORE_CHANNELS_ACTION =
new MenuAction(R.string.options_item_more_channels,
TvOptionsManager.OPTION_MORE_CHANNELS, R.drawable.ic_store);
+ public static final MenuAction DEV_ACTION =
+ new MenuAction(R.string.options_item_developer,
+ TvOptionsManager.OPTION_DEVELOPER, R.drawable.ic_developer_mode_tv_white_48dp);
// TODO: Change the icon.
public static final MenuAction SETTINGS_ACTION =
new MenuAction(R.string.options_item_settings, TvOptionsManager.OPTION_SETTINGS,
diff --git a/src/com/android/tv/menu/MenuLayoutManager.java b/src/com/android/tv/menu/MenuLayoutManager.java
index 1f377f54..6c767247 100644
--- a/src/com/android/tv/menu/MenuLayoutManager.java
+++ b/src/com/android/tv/menu/MenuLayoutManager.java
@@ -219,8 +219,8 @@ public class MenuLayoutManager {
* @param bottom The bottom coordinate of the menu view.
*/
private List<Rect> getViewLayouts(int left, int top, int right, int bottom) {
- return getViewLayouts(left, top, right, bottom, Collections.<Integer>emptyList(),
- Collections.<Integer>emptyList());
+ return getViewLayouts(left, top, right, bottom, Collections.emptyList(),
+ Collections.emptyList());
}
/**
diff --git a/src/com/android/tv/menu/MenuRow.java b/src/com/android/tv/menu/MenuRow.java
index fe73edd2..6f98e615 100644
--- a/src/com/android/tv/menu/MenuRow.java
+++ b/src/com/android/tv/menu/MenuRow.java
@@ -17,6 +17,7 @@
package com.android.tv.menu;
import android.content.Context;
+import android.view.View;
/**
* A base class of the item which will be displayed in the main menu.
@@ -30,6 +31,8 @@ public abstract class MenuRow {
private final int mHeight;
private final Menu mMenu;
+ private MenuRowView mMenuRowView;
+
// TODO: Check if the heightResId is really necessary.
public MenuRow(Context context, Menu menu, int titleResId, int heightResId) {
this(context, menu, context.getString(titleResId), heightResId);
@@ -71,6 +74,20 @@ public abstract class MenuRow {
}
/**
+ * Sets the menu row view.
+ */
+ public void setMenuRowView(MenuRowView menuRowView) {
+ mMenuRowView = menuRowView;
+ }
+
+ /**
+ * Returns the menu row view.
+ */
+ protected MenuRowView getMenuRowView() {
+ return mMenuRowView;
+ }
+
+ /**
* Updates the contents in this row.
* This method is called only by the menu when necessary.
*/
diff --git a/src/com/android/tv/menu/MenuRowFactory.java b/src/com/android/tv/menu/MenuRowFactory.java
index b0b000f1..c67a0e04 100644
--- a/src/com/android/tv/menu/MenuRowFactory.java
+++ b/src/com/android/tv/menu/MenuRowFactory.java
@@ -24,6 +24,7 @@ import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.customization.CustomAction;
import com.android.tv.customization.TvCustomizationManager;
+import com.android.tv.ui.TunableTvView;
import java.util.List;
@@ -32,13 +33,15 @@ import java.util.List;
*/
public class MenuRowFactory {
private final MainActivity mMainActivity;
+ private final TunableTvView mTvView;
private final TvCustomizationManager mTvCustomizationManager;
/**
* A constructor.
*/
- public MenuRowFactory(MainActivity mainActivity) {
+ public MenuRowFactory(MainActivity mainActivity, TunableTvView tvView) {
mMainActivity = mainActivity;
+ mTvView = tvView;
mTvCustomizationManager = new TvCustomizationManager(mainActivity);
mTvCustomizationManager.initialize();
}
@@ -49,7 +52,8 @@ public class MenuRowFactory {
@Nullable
public MenuRow createMenuRow(Menu menu, Class<?> key) {
if (PlayControlsRow.class.equals(key)) {
- return new PlayControlsRow(mMainActivity, menu, mMainActivity.getTimeShiftManager());
+ return new PlayControlsRow(mMainActivity, mTvView, menu,
+ mMainActivity.getTimeShiftManager());
} else if (ChannelsRow.class.equals(key)) {
return new ChannelsRow(mMainActivity, menu, mMainActivity.getProgramDataManager());
} else if (PartnerRow.class.equals(key)) {
diff --git a/src/com/android/tv/menu/MenuRowView.java b/src/com/android/tv/menu/MenuRowView.java
index 7cdbfe9e..97dea29a 100644
--- a/src/com/android/tv/menu/MenuRowView.java
+++ b/src/com/android/tv/menu/MenuRowView.java
@@ -35,25 +35,6 @@ public abstract class MenuRowView extends LinearLayout {
private static final String TAG = "MenuRowView";
private static final boolean DEBUG = false;
- /**
- * For setting ListView visible, and TitleView visible with the selected text size and color
- * without animation.
- */
- public static final int ANIM_NONE_SELECTED = 1;
- /**
- * For setting ListView gone, and TitleView visible with the deselected text size and color
- * without animation.
- */
- public static final int ANIM_NONE_DESELECTED = 2;
- /**
- * An animation for the selected item list view.
- */
- public static final int ANIM_SELECTED = 3;
- /**
- * An animation for the deselected item list view.
- */
- public static final int ANIM_DESELECTED = 4;
-
private TextView mTitleView;
private View mContentsView;
diff --git a/src/com/android/tv/menu/MenuUpdater.java b/src/com/android/tv/menu/MenuUpdater.java
new file mode 100644
index 00000000..075b299e
--- /dev/null
+++ b/src/com/android/tv/menu/MenuUpdater.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.menu;
+
+import android.content.Context;
+import android.support.annotation.Nullable;
+
+import com.android.tv.ChannelTuner;
+import com.android.tv.data.Channel;
+import com.android.tv.ui.TunableTvView;
+import com.android.tv.ui.TunableTvView.OnScreenBlockingChangedListener;
+
+/**
+ * Update menu items when needed.
+ *
+ * <p>As the menu is updated when it shows up, this class handles only the dynamic updates.
+ */
+public class MenuUpdater {
+ // Can be null for testing.
+ @Nullable
+ private final TunableTvView mTvView;
+ private final Menu mMenu;
+ private ChannelTuner mChannelTuner;
+
+ private final ChannelTuner.Listener mChannelTunerListener = new ChannelTuner.Listener() {
+ @Override
+ public void onLoadFinished() {}
+
+ @Override
+ public void onBrowsableChannelListChanged() {
+ mMenu.update();
+ }
+
+ @Override
+ public void onCurrentChannelUnavailable(Channel channel) {}
+
+ @Override
+ public void onChannelChanged(Channel previousChannel, Channel currentChannel) {
+ mMenu.update(ChannelsRow.ID);
+ }
+ };
+
+ public MenuUpdater(Context context, TunableTvView tvView, Menu menu) {
+ mTvView = tvView;
+ mMenu = menu;
+ if (mTvView != null) {
+ mTvView.setOnScreenBlockedListener(new OnScreenBlockingChangedListener() {
+ @Override
+ public void onScreenBlockingChanged(boolean blocked) {
+ mMenu.update(PlayControlsRow.ID);
+ }
+ });
+ }
+ }
+
+ /**
+ * Sets the instance of {@link ChannelTuner}. Call this method when the channel tuner is ready
+ * or not available any more.
+ */
+ public void setChannelTuner(ChannelTuner channelTuner) {
+ if (mChannelTuner != null) {
+ mChannelTuner.removeListener(mChannelTunerListener);
+ }
+ mChannelTuner = channelTuner;
+ if (mChannelTuner != null) {
+ mChannelTuner.addListener(mChannelTunerListener);
+ }
+ mMenu.update();
+ }
+
+ /**
+ * Called at the end of the menu's lifetime.
+ */
+ public void release() {
+ if (mChannelTuner != null) {
+ mChannelTuner.removeListener(mChannelTunerListener);
+ }
+ if (mTvView != null) {
+ mTvView.setOnScreenBlockedListener(null);
+ }
+ }
+}
diff --git a/src/com/android/tv/menu/MenuView.java b/src/com/android/tv/menu/MenuView.java
index e012dfca..ee0b036e 100644
--- a/src/com/android/tv/menu/MenuView.java
+++ b/src/com/android/tv/menu/MenuView.java
@@ -24,6 +24,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewParent;
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
import com.android.tv.menu.Menu.MenuShowReason;
@@ -57,6 +58,8 @@ public class MenuView extends FrameLayout implements IMenuView {
public MenuView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mLayoutInflater = LayoutInflater.from(context);
+ // Set hardware layer type for smooth animation of lots of views.
+ setLayerType(LAYER_TYPE_HARDWARE, null);
getViewTreeObserver().addOnGlobalFocusChangeListener(new OnGlobalFocusChangeListener() {
@Override
public void onGlobalFocusChanged(View oldFocus, View newFocus) {
@@ -89,6 +92,7 @@ public class MenuView extends FrameLayout implements IMenuView {
private MenuRowView createMenuRowView(MenuRow row) {
MenuRowView view = (MenuRowView) mLayoutInflater.inflate(row.getLayoutResId(), this, false);
view.onBind(row);
+ row.setMenuRowView(view);
return view;
}
@@ -128,7 +132,15 @@ public class MenuView extends FrameLayout implements IMenuView {
// Make the selected row have the focus.
requestFocus();
if (runnableAfterShow != null) {
- runnableAfterShow.run();
+ getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
+ @Override
+ public void onGlobalLayout() {
+ getViewTreeObserver().removeOnGlobalLayoutListener(this);
+ // Start show animation after layout finishes for smooth animation because the
+ // layout can take long time.
+ runnableAfterShow.run();
+ }
+ });
}
mLayoutManager.onMenuShow();
}
@@ -160,6 +172,19 @@ public class MenuView extends FrameLayout implements IMenuView {
}
@Override
+ public boolean update(String rowId, boolean menuActive) {
+ if (menuActive) {
+ MenuRow row = getMenuRow(rowId);
+ if (row != null) {
+ row.update();
+ mLayoutManager.onMenuRowUpdated();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
int selectedPosition = mLayoutManager.getSelectedPosition();
// When the menu shows up, the selected row should have focus.
@@ -169,6 +194,16 @@ public class MenuView extends FrameLayout implements IMenuView {
return super.onRequestFocusInDescendants(direction, previouslyFocusedRect);
}
+ @Override
+ public void focusableViewAvailable(View v) {
+ // Workaround of b/30788222 and b/32074688.
+ // The re-layout of RecyclerView gives the focus to the card view even when the menu is not
+ // visible. Don't report focusable view when the menu is not visible.
+ if (getVisibility() == VISIBLE) {
+ super.focusableViewAvailable(v);
+ }
+ }
+
private void setSelectedPosition(int position) {
mLayoutManager.setSelectedPosition(position);
}
@@ -183,6 +218,15 @@ public class MenuView extends FrameLayout implements IMenuView {
}
}
+ private MenuRow getMenuRow(String rowId) {
+ for (MenuRow item : mMenuRows) {
+ if (rowId.equals(item.getId())) {
+ return item;
+ }
+ }
+ return null;
+ }
+
private int getItemPosition(String rowIdToSelect) {
if (rowIdToSelect == null) {
return -1;
diff --git a/src/com/android/tv/menu/PlayControlsButton.java b/src/com/android/tv/menu/PlayControlsButton.java
index 957f2e94..aff39db3 100644
--- a/src/com/android/tv/menu/PlayControlsButton.java
+++ b/src/com/android/tv/menu/PlayControlsButton.java
@@ -16,6 +16,8 @@
package com.android.tv.menu;
+import android.R.integer;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -33,6 +35,9 @@ public class PlayControlsButton extends FrameLayout {
private final ImageView mButton;
private final ImageView mIcon;
private final TextView mLabel;
+ private final long mFocusAnimationTimeMs;
+ private final int mIconColor;
+ private int mIconFocusedColor;
public PlayControlsButton(Context context) {
this(context, null);
@@ -53,6 +58,9 @@ public class PlayControlsButton extends FrameLayout {
mButton = (ImageView) findViewById(R.id.button);
mIcon = (ImageView) findViewById(R.id.icon);
mLabel = (TextView) findViewById(R.id.label);
+ mFocusAnimationTimeMs = context.getResources().getInteger(integer.config_shortAnimTime);
+ mIconColor = context.getResources().getColor(R.color.play_controls_icon_color);
+ mIconFocusedColor = mIconColor;
}
/**
@@ -60,6 +68,9 @@ public class PlayControlsButton extends FrameLayout {
*/
public void setImageResId(int imageResId) {
mIcon.setImageResource(imageResId);
+ // Since on foucus changing, icons' color should be switched with animation,
+ // as a result, selectors cannot be used to switch colors in this case.
+ mIcon.getDrawable().setTint(hasFocus() ? mIconFocusedColor : mIconColor);
}
/**
@@ -74,6 +85,31 @@ public class PlayControlsButton extends FrameLayout {
});
}
+ /**
+ * Sets the icon's color should change to when the button is on focus.
+ */
+ public void setFocusedIconColor(int color) {
+ final ValueAnimator valueAnimator = ValueAnimator.ofArgb(mIconColor, color);
+ valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(final ValueAnimator animator) {
+ mIcon.getDrawable().setTint((int) animator.getAnimatedValue());
+ }
+ });
+ valueAnimator.setDuration(mFocusAnimationTimeMs);
+ mButton.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+ @Override
+ public void onFocusChange(View v, boolean hasFocus) {
+ if (hasFocus) {
+ valueAnimator.start();
+ } else {
+ valueAnimator.reverse();
+ }
+ }
+ });
+ mIconFocusedColor = color;
+ }
+
public void setLabel(String label) {
if (TextUtils.isEmpty(label)) {
mIcon.setVisibility(View.VISIBLE);
@@ -93,6 +129,7 @@ public class PlayControlsButton extends FrameLayout {
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mButton.setEnabled(enabled);
+ mButton.setFocusable(enabled);
mIcon.setEnabled(enabled);
mIcon.setAlpha(enabled ? ALPHA_ENABLED : ALPHA_DISABLED);
mLabel.setEnabled(enabled);
diff --git a/src/com/android/tv/menu/PlayControlsRow.java b/src/com/android/tv/menu/PlayControlsRow.java
index 588ecf6a..a60ff153 100644
--- a/src/com/android/tv/menu/PlayControlsRow.java
+++ b/src/com/android/tv/menu/PlayControlsRow.java
@@ -20,19 +20,24 @@ import android.content.Context;
import com.android.tv.R;
import com.android.tv.TimeShiftManager;
+import com.android.tv.ui.TunableTvView;
public class PlayControlsRow extends MenuRow {
public static final String ID = PlayControlsRow.class.getName();
+ private final TunableTvView mTvView;
private final TimeShiftManager mTimeShiftManager;
- public PlayControlsRow(Context context, Menu menu, TimeShiftManager timeShiftManager) {
+ public PlayControlsRow(Context context, TunableTvView tvView, Menu menu,
+ TimeShiftManager timeShiftManager) {
super(context, menu, R.string.menu_title_play_controls, R.dimen.play_controls_height);
+ mTvView = tvView;
mTimeShiftManager = timeShiftManager;
}
@Override
public void update() {
+ ((PlayControlsRowView) getMenuRowView()).update();
}
@Override
@@ -41,6 +46,13 @@ public class PlayControlsRow extends MenuRow {
}
/**
+ * Returns TV view.
+ */
+ public TunableTvView getTvView() {
+ return mTvView;
+ }
+
+ /**
* Returns an instance of {@link TimeShiftManager}.
*/
public TimeShiftManager getTimeShiftManager() {
diff --git a/src/com/android/tv/menu/PlayControlsRowView.java b/src/com/android/tv/menu/PlayControlsRowView.java
index 058d5108..a620d4dd 100644
--- a/src/com/android/tv/menu/PlayControlsRowView.java
+++ b/src/com/android/tv/menu/PlayControlsRowView.java
@@ -19,20 +19,35 @@ package com.android.tv.menu;
import android.content.Context;
import android.content.res.Resources;
import android.text.format.DateFormat;
-import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
+import android.widget.Toast;
+import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TimeShiftManager;
import com.android.tv.TimeShiftManager.TimeShiftActionId;
+import com.android.tv.TvApplication;
import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.dvr.DvrDataManager;
+import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
+import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.DvrUiHelper;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.dvr.ui.DvrStopRecordingFragment;
+import com.android.tv.dvr.ui.HalfSizedDialogFragment;
import com.android.tv.menu.Menu.MenuShowReason;
+import com.android.tv.ui.TunableTvView;
+import com.android.tv.util.Utils;
public class PlayControlsRowView extends MenuRowView {
+ private static final int NORMAL_WIDTH_MAX_BUTTON_COUNT = 5;
// Dimensions
private final int mTimeIndicatorLeftMargin;
private final int mTimeTextLeftMargin;
@@ -51,14 +66,44 @@ public class PlayControlsRowView extends MenuRowView {
private PlayControlsButton mPlayPauseButton;
private PlayControlsButton mFastForwardButton;
private PlayControlsButton mJumpNextButton;
+ private PlayControlsButton mRecordButton;
private TextView mProgramStartTimeText;
private TextView mProgramEndTimeText;
private View mUnavailableMessageText;
+ private TunableTvView mTvView;
private TimeShiftManager mTimeShiftManager;
+ private final DvrDataManager mDvrDataManager;
+ private final DvrManager mDvrManager;
+ private final MainActivity mMainActivity;
private final java.text.DateFormat mTimeFormat;
private long mProgramStartTimeMs;
private long mProgramEndTimeMs;
+ private boolean mUseCompactLayout;
+ private final int mNormalButtonMargin;
+ private final int mCompactButtonMargin;
+
+ private final ScheduledRecordingListener mScheduledRecordingListener
+ = new ScheduledRecordingListener() {
+ @Override
+ public void onScheduledRecordingAdded(ScheduledRecording... scheduledRecordings) { }
+
+ @Override
+ public void onScheduledRecordingRemoved(ScheduledRecording... scheduledRecordings) { }
+
+ @Override
+ public void onScheduledRecordingStatusChanged(ScheduledRecording... scheduledRecordings) {
+ Channel currentChannel = mMainActivity.getCurrentChannel();
+ if (currentChannel != null && isShown()) {
+ for (ScheduledRecording schedule : scheduledRecordings) {
+ if (schedule.getChannelId() == currentChannel.getId()) {
+ updateRecordButton();
+ break;
+ }
+ }
+ }
+ }
+ };
public PlayControlsRowView(Context context) {
this(context, null);
@@ -82,6 +127,38 @@ public class PlayControlsRowView extends MenuRowView {
- res.getDimensionPixelOffset(R.dimen.play_controls_time_width) / 2;
mTimelineWidth = res.getDimensionPixelSize(R.dimen.play_controls_width);
mTimeFormat = DateFormat.getTimeFormat(context);
+ mNormalButtonMargin = res.getDimensionPixelSize(R.dimen.play_controls_button_normal_margin);
+ mCompactButtonMargin =
+ res.getDimensionPixelSize(R.dimen.play_controls_button_compact_margin);
+ if (CommonFeatures.DVR.isEnabled(context)) {
+ mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
+ mDvrManager = TvApplication.getSingletons(context).getDvrManager();
+ } else {
+ mDvrDataManager = null;
+ mDvrManager = null;
+ }
+ mMainActivity = (MainActivity) context;
+ }
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ if (mDvrDataManager != null) {
+ mDvrDataManager.addScheduledRecordingListener(mScheduledRecordingListener);
+ if (!mDvrDataManager.isDvrScheduleLoadFinished()) {
+ mDvrDataManager.addDvrScheduleLoadFinishedListener(
+ new OnDvrScheduleLoadFinishedListener() {
+ @Override
+ public void onDvrScheduleLoadFinished() {
+ mDvrDataManager.removeDvrScheduleLoadFinishedListener(this);
+ if (isShown()) {
+ updateRecordButton();
+ }
+ }
+ });
+ }
+
+ }
}
@Override
@@ -107,22 +184,23 @@ public class PlayControlsRowView extends MenuRowView {
mPlayPauseButton = (PlayControlsButton) findViewById(R.id.play_pause);
mFastForwardButton = (PlayControlsButton) findViewById(R.id.fast_forward);
mJumpNextButton = (PlayControlsButton) findViewById(R.id.jump_next);
+ mRecordButton = (PlayControlsButton) findViewById(R.id.record);
mProgramStartTimeText = (TextView) findViewById(R.id.program_start_time);
mProgramEndTimeText = (TextView) findViewById(R.id.program_end_time);
mUnavailableMessageText = findViewById(R.id.unavailable_text);
initializeButton(mJumpPreviousButton, R.drawable.lb_ic_skip_previous,
- R.string.play_controls_description_skip_previous, new Runnable() {
+ R.string.play_controls_description_skip_previous, null, new Runnable() {
@Override
public void run() {
if (mTimeShiftManager.isAvailable()) {
mTimeShiftManager.jumpToPrevious();
- updateAll();
+ updateControls();
}
}
});
initializeButton(mRewindButton, R.drawable.lb_ic_fast_rewind,
- R.string.play_controls_description_fast_rewind, new Runnable() {
+ R.string.play_controls_description_fast_rewind, null, new Runnable() {
@Override
public void run() {
if (mTimeShiftManager.isAvailable()) {
@@ -132,7 +210,7 @@ public class PlayControlsRowView extends MenuRowView {
}
});
initializeButton(mPlayPauseButton, R.drawable.lb_ic_play,
- R.string.play_controls_description_play_pause, new Runnable() {
+ R.string.play_controls_description_play_pause, null, new Runnable() {
@Override
public void run() {
if (mTimeShiftManager.isAvailable()) {
@@ -142,7 +220,7 @@ public class PlayControlsRowView extends MenuRowView {
}
});
initializeButton(mFastForwardButton, R.drawable.lb_ic_fast_forward,
- R.string.play_controls_description_fast_forward, new Runnable() {
+ R.string.play_controls_description_fast_forward, null, new Runnable() {
@Override
public void run() {
if (mTimeShiftManager.isAvailable()) {
@@ -152,21 +230,80 @@ public class PlayControlsRowView extends MenuRowView {
}
});
initializeButton(mJumpNextButton, R.drawable.lb_ic_skip_next,
- R.string.play_controls_description_skip_next, new Runnable() {
+ R.string.play_controls_description_skip_next, null, new Runnable() {
@Override
public void run() {
if (mTimeShiftManager.isAvailable()) {
mTimeShiftManager.jumpToNext();
- updateAll();
+ updateControls();
}
}
});
+ int color = getResources().getColor(R.color.play_controls_recording_icon_color_on_focus,
+ null);
+ initializeButton(mRecordButton, R.drawable.ic_record_start, R.string
+ .channels_item_record_start, color, new Runnable() {
+ @Override
+ public void run() {
+ onRecordButtonClicked();
+ }
+ });
+ }
+
+ private boolean isCurrentChannelRecording() {
+ Channel currentChannel = mMainActivity.getCurrentChannel();
+ return currentChannel != null && mDvrManager != null
+ && mDvrManager.getCurrentRecording(currentChannel.getId()) != null;
+ }
+
+ private void onRecordButtonClicked() {
+ boolean isRecording = isCurrentChannelRecording();
+ Channel currentChannel = mMainActivity.getCurrentChannel();
+ TvApplication.getSingletons(getContext()).getTracker().sendMenuClicked(isRecording ?
+ R.string.channels_item_record_start : R.string.channels_item_record_stop);
+ if (!isRecording) {
+ if (!(mDvrManager != null && mDvrManager.isChannelRecordable(currentChannel))) {
+ Toast.makeText(mMainActivity, R.string.dvr_msg_cannot_record_channel,
+ Toast.LENGTH_SHORT).show();
+ } else if (DvrUiHelper.checkStorageStatusAndShowErrorMessage(mMainActivity,
+ currentChannel.getInputId())) {
+ Program program = TvApplication.getSingletons(mMainActivity).getProgramDataManager()
+ .getCurrentProgram(currentChannel.getId());
+ if (program == null) {
+ DvrUiHelper.showChannelRecordDurationOptions(mMainActivity, currentChannel);
+ } else if (DvrUiHelper.handleCreateSchedule(mMainActivity, program)) {
+ String msg = mMainActivity.getString(R.string.dvr_msg_current_program_scheduled,
+ program.getTitle(),
+ Utils.toTimeString(program.getEndTimeUtcMillis(), false));
+ Toast.makeText(mMainActivity, msg, Toast.LENGTH_SHORT).show();
+ }
+ }
+ } else if (currentChannel != null) {
+ DvrUiHelper.showStopRecordingDialog(mMainActivity, 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);
+ }
+ }
+ }
+ });
+ }
}
private void initializeButton(PlayControlsButton button, int imageResId,
- int descriptionId, Runnable clickAction) {
+ int descriptionId, Integer focusedIconColor, Runnable clickAction) {
button.setImageResId(imageResId);
button.setAction(clickAction);
+ if (focusedIconColor != null) {
+ button.setFocusedIconColor(focusedIconColor);
+ }
button.findViewById(R.id.button)
.setContentDescription(getResources().getString(descriptionId));
}
@@ -175,46 +312,46 @@ public class PlayControlsRowView extends MenuRowView {
public void onBind(MenuRow row) {
super.onBind(row);
PlayControlsRow playControlsRow = (PlayControlsRow) row;
+ mTvView = playControlsRow.getTvView();
mTimeShiftManager = playControlsRow.getTimeShiftManager();
mTimeShiftManager.setListener(new TimeShiftManager.Listener() {
@Override
public void onAvailabilityChanged() {
updateMenuVisibility();
- PlayControlsRowView.this.onAvailabilityChanged();
+ if (isShown()) {
+ PlayControlsRowView.this.updateAll();
+ }
}
@Override
public void onPlayStatusChanged(int status) {
updateMenuVisibility();
- if (mTimeShiftManager.isAvailable()) {
- updateAll();
+ if (mTimeShiftManager.isAvailable() && isShown()) {
+ updateControls();
}
}
@Override
public void onRecordTimeRangeChanged() {
- if (!mTimeShiftManager.isAvailable()) {
- return;
+ if (mTimeShiftManager.isAvailable() && isShown()) {
+ updateControls();
}
- updateAll();
}
@Override
public void onCurrentPositionChanged() {
- if (!mTimeShiftManager.isAvailable()) {
- return;
+ if (mTimeShiftManager.isAvailable() && isShown()) {
+ initializeTimeline();
+ updateControls();
}
- initializeTimeline();
- updateAll();
}
@Override
public void onProgramInfoChanged() {
- if (!mTimeShiftManager.isAvailable()) {
- return;
+ if (mTimeShiftManager.isAvailable() && isShown()) {
+ initializeTimeline();
+ updateControls();
}
- initializeTimeline();
- updateAll();
}
@Override
@@ -235,31 +372,14 @@ public class PlayControlsRowView extends MenuRowView {
}
}
});
- onAvailabilityChanged();
- }
-
- private void onAvailabilityChanged() {
- if (mTimeShiftManager.isAvailable()) {
- setEnabled(true);
- initializeTimeline();
- mBackgroundView.setEnabled(true);
- } else {
- setEnabled(false);
- mBackgroundView.setEnabled(false);
- }
updateAll();
}
private void initializeTimeline() {
- if (mTimeShiftManager.isRecordingPlayback()) {
- mProgramStartTimeMs = mTimeShiftManager.getRecordStartTimeMs();
- mProgramEndTimeMs = mTimeShiftManager.getRecordEndTimeMs();
- } else {
- Program program = mTimeShiftManager.getProgramAt(
- mTimeShiftManager.getCurrentPositionMs());
- mProgramStartTimeMs = program.getStartTimeUtcMillis();
- mProgramEndTimeMs = program.getEndTimeUtcMillis();
- }
+ Program program = mTimeShiftManager.getProgramAt(
+ mTimeShiftManager.getCurrentPositionMs());
+ mProgramStartTimeMs = program.getStartTimeUtcMillis();
+ mProgramEndTimeMs = program.getEndTimeUtcMillis();
SoftPreconditions.checkArgument(mProgramStartTimeMs <= mProgramEndTimeMs);
}
@@ -272,7 +392,7 @@ public class PlayControlsRowView extends MenuRowView {
@Override
public void onSelected(boolean showTitle) {
super.onSelected(showTitle);
- updateAll();
+ updateControls();
postHideRippleAnimation();
}
@@ -350,11 +470,32 @@ public class PlayControlsRowView extends MenuRowView {
}
}
+ /**
+ * Updates the view contents. It is called from the PlayControlsRow.
+ */
+ public void update() {
+ updateAll();
+ }
+
private void updateAll() {
+ if (mTimeShiftManager.isAvailable() && !mTvView.isScreenBlocked()) {
+ setEnabled(true);
+ initializeTimeline();
+ mBackgroundView.setEnabled(true);
+ } else {
+ setEnabled(false);
+ mBackgroundView.setEnabled(false);
+ }
+ updateControls();
+ }
+
+ private void updateControls() {
updateTime();
updateProgress();
updateRecTimeText();
updateButtons();
+ updateRecordButton();
+ updateButtonMargin();
}
private void updateTime() {
@@ -423,12 +564,8 @@ public class PlayControlsRowView extends MenuRowView {
private void updateRecTimeText() {
if (isEnabled()) {
- if (mTimeShiftManager.isRecordingPlayback()) {
- mProgramStartTimeText.setVisibility(View.GONE);
- } else {
- mProgramStartTimeText.setVisibility(View.VISIBLE);
- mProgramStartTimeText.setText(getTimeString(mProgramStartTimeMs));
- }
+ mProgramStartTimeText.setVisibility(View.VISIBLE);
+ mProgramStartTimeText.setText(getTimeString(mProgramStartTimeMs));
mProgramEndTimeText.setVisibility(View.VISIBLE);
mProgramEndTimeText.setText(getTimeString(mProgramEndTimeMs));
} else {
@@ -464,6 +601,9 @@ public class PlayControlsRowView extends MenuRowView {
TimeShiftManager.TIME_SHIFT_ACTION_ID_FAST_FORWARD));
mJumpNextButton.setEnabled(mTimeShiftManager.isActionEnabled(
TimeShiftManager.TIME_SHIFT_ACTION_ID_JUMP_TO_NEXT));
+ mJumpPreviousButton.setVisibility(VISIBLE);
+ mJumpNextButton.setVisibility(VISIBLE);
+ updateButtonMargin();
PlayControlsButton button;
if (mTimeShiftManager.getPlayDirection() == TimeShiftManager.PLAY_DIRECTION_FORWARD) {
@@ -481,10 +621,51 @@ public class PlayControlsRowView extends MenuRowView {
}
}
+ private void updateRecordButton() {
+ if (!(mDvrManager != null
+ && mDvrManager.isChannelRecordable(mMainActivity.getCurrentChannel()))) {
+ mRecordButton.setVisibility(View.GONE);
+ updateButtonMargin();
+ return;
+ }
+ mRecordButton.setVisibility(View.VISIBLE);
+ updateButtonMargin();
+ if (isCurrentChannelRecording()) {
+ mRecordButton.setImageResId(R.drawable.ic_record_stop);
+ } else {
+ mRecordButton.setImageResId(R.drawable.ic_record_start);
+ }
+ }
+
+ private void updateButtonMargin() {
+ int numOfVisibleButtons = (mJumpPreviousButton.getVisibility() == View.VISIBLE ? 1 : 0)
+ + (mRewindButton.getVisibility() == View.VISIBLE ? 1 : 0)
+ + (mPlayPauseButton.getVisibility() == View.VISIBLE ? 1 : 0)
+ + (mFastForwardButton.getVisibility() == View.VISIBLE ? 1 : 0)
+ + (mJumpNextButton.getVisibility() == View.VISIBLE ? 1 : 0)
+ + (mRecordButton.getVisibility() == View.VISIBLE ? 1 : 0);
+ boolean useCompactLayout = numOfVisibleButtons > NORMAL_WIDTH_MAX_BUTTON_COUNT;
+ if (mUseCompactLayout == useCompactLayout) {
+ return;
+ }
+ mUseCompactLayout = useCompactLayout;
+ int margin = mUseCompactLayout ? mCompactButtonMargin : mNormalButtonMargin;
+ updateButtonMargin(mJumpPreviousButton, margin);
+ updateButtonMargin(mRewindButton, margin);
+ updateButtonMargin(mPlayPauseButton, margin);
+ updateButtonMargin(mFastForwardButton, margin);
+ updateButtonMargin(mJumpNextButton, margin);
+ updateButtonMargin(mRecordButton, margin);
+ }
+
+ private void updateButtonMargin(PlayControlsButton button, int margin) {
+ MarginLayoutParams params = (MarginLayoutParams) button.getLayoutParams();
+ params.setMargins(margin, 0, margin, 0);
+ button.setLayoutParams(params);
+ }
+
private String getTimeString(long timeMs) {
- return mTimeShiftManager.isRecordingPlayback()
- ? DateUtils.formatElapsedTime(timeMs / 1000)
- : mTimeFormat.format(timeMs);
+ return mTimeFormat.format(timeMs);
}
private int convertDurationToPixel(long duration) {
@@ -493,4 +674,12 @@ public class PlayControlsRowView extends MenuRowView {
}
return (int) (duration * mTimelineWidth / (mProgramEndTimeMs - mProgramStartTimeMs));
}
+
+ @Override
+ public void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mDvrDataManager != null) {
+ mDvrDataManager.removeScheduledRecordingListener(mScheduledRecordingListener);
+ }
+ }
}
diff --git a/src/com/android/tv/menu/RecordCardView.java b/src/com/android/tv/menu/RecordCardView.java
deleted file mode 100644
index de30894e..00000000
--- a/src/com/android/tv/menu/RecordCardView.java
+++ /dev/null
@@ -1,189 +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.menu;
-
-import android.app.AlertDialog;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.res.Resources;
-import android.util.AttributeSet;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.tv.MainActivity;
-import com.android.tv.R;
-import com.android.tv.TvApplication;
-import com.android.tv.data.Channel;
-import com.android.tv.data.Program;
-import com.android.tv.dvr.DvrDataManager;
-import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.ScheduledRecording;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A view to render an item of TV options.
- */
-public class RecordCardView extends SimpleCardView implements
- DvrDataManager.ScheduledRecordingListener {
- private static final String TAG = MenuView.TAG;
- private static final boolean DEBUG = MenuView.DEBUG;
- private static final long MIN_PROGRAM_RECORD_DURATION = TimeUnit.MINUTES.toMillis(5);
-
- private ImageView mIconView;
- private TextView mLabelView;
- private Channel mCurrentChannel;
- private final DvrManager mDvrManager;
- private final DvrDataManager mDvrDataManager;
- private boolean mIsRecording;
- private ScheduledRecording mCurrentRecording;
-
- public RecordCardView(Context context) {
- this(context, null);
- }
-
- public RecordCardView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public RecordCardView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mDvrManager = TvApplication.getSingletons(context).getDvrManager();
- mDvrDataManager = TvApplication.getSingletons(context).getDvrDataManager();
- }
-
- @Override
- public void onBind(Channel channel, boolean selected) {
- super.onBind(channel, selected);
- mIconView = (ImageView) findViewById(R.id.record_icon);
- mLabelView = (TextView) findViewById(R.id.record_label);
- mCurrentChannel = channel;
- mCurrentRecording = null;
- for (ScheduledRecording recording : mDvrDataManager.getStartedRecordings()) {
- if (recording.getChannelId() == channel.getId()) {
- mIsRecording = true;
- mCurrentRecording = recording;
- }
- }
- mDvrDataManager.addScheduledRecordingListener(this);
- updateCardView();
- }
-
- @Override
- public void onRecycled() {
- super.onRecycled();
- mDvrDataManager.removeScheduledRecordingListener(this);
- }
-
- public boolean isRecording() {
- return mIsRecording;
- }
-
- public void startRecording() {
- showStartRecordingDialog();
- }
-
- public void stopRecording() {
- mDvrManager.stopRecording(mCurrentRecording);
- }
-
- private void updateCardView() {
- if (mIsRecording) {
- mIconView.setImageResource(R.drawable.ic_record_stop);
- mLabelView.setText(R.string.channels_item_record_stop);
- } else {
- mIconView.setImageResource(R.drawable.ic_record_start);
- mLabelView.setText(R.string.channels_item_record_start);
- }
- }
-
- private void showStartRecordingDialog() {
- final long endOfProgram = -1;
-
- final List<CharSequence> items = new ArrayList<>();
- final List<Long> durations = new ArrayList<>();
- Resources res = getResources();
- items.add(res.getString(R.string.recording_start_dialog_10_min_duration));
- durations.add(TimeUnit.MINUTES.toMillis(10));
- items.add(res.getString(R.string.recording_start_dialog_30_min_duration));
- durations.add(TimeUnit.MINUTES.toMillis(30));
- items.add(res.getString(R.string.recording_start_dialog_1_hour_duration));
- durations.add(TimeUnit.HOURS.toMillis(1));
- items.add(res.getString(R.string.recording_start_dialog_3_hours_duration));
- durations.add(TimeUnit.HOURS.toMillis(3));
-
- Program currenProgram = ((MainActivity) getContext()).getCurrentProgram(false);
- if (currenProgram != null) {
- long duration = currenProgram.getEndTimeUtcMillis() - System.currentTimeMillis();
- if (duration > MIN_PROGRAM_RECORD_DURATION) {
- items.add(res.getString(R.string.recording_start_dialog_till_end_of_program));
- durations.add(duration);
- }
- }
-
- DialogInterface.OnClickListener onClickListener
- = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(final DialogInterface dialog, int which) {
- long startTime = System.currentTimeMillis();
- long endTime = System.currentTimeMillis() + durations.get(which);
- mDvrManager.addSchedule(mCurrentChannel, startTime, endTime);
- dialog.dismiss();
- }
- };
- new AlertDialog.Builder(getContext())
- .setItems(items.toArray(new CharSequence[items.size()]), onClickListener)
- .create()
- .show();
- }
-
- @Override
- public void onScheduledRecordingAdded(ScheduledRecording recording) {
- }
-
- @Override
- public void onScheduledRecordingRemoved(ScheduledRecording recording) {
- if (recording.getChannelId() != mCurrentChannel.getId()) {
- return;
- }
- if (mIsRecording) {
- mIsRecording = false;
- mCurrentRecording = null;
- updateCardView();
- }
- }
-
- @Override
- public void onScheduledRecordingStatusChanged(ScheduledRecording recording) {
- if (recording.getChannelId() != mCurrentChannel.getId()) {
- return;
- }
- int state = recording.getState();
- if (state == ScheduledRecording.STATE_RECORDING_FAILED
- || state == ScheduledRecording.STATE_RECORDING_FINISHED) {
- mIsRecording = false;
- mCurrentRecording = null;
- updateCardView();
- } else if (state == ScheduledRecording.STATE_RECORDING_IN_PROGRESS) {
- mIsRecording = true;
- mCurrentRecording = recording;
- updateCardView();
- }
- }
-}
diff --git a/src/com/android/tv/menu/SetupCardView.java b/src/com/android/tv/menu/SetupCardView.java
deleted file mode 100644
index 7ad5e9d0..00000000
--- a/src/com/android/tv/menu/SetupCardView.java
+++ /dev/null
@@ -1,53 +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.menu;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import com.android.tv.R;
-import com.android.tv.data.Channel;
-
-/**
- * A view to render a guide card.
- */
-public class SetupCardView extends BaseCardView<Channel> {
- private static final String TAG = "GuideCardView";
- private static final boolean DEBUG = false;
-
- private static final int INVALID_COUNT = -1;
-
- private final float mCardHeight;
-
- public SetupCardView(Context context) {
- this(context, null, 0);
- }
-
- public SetupCardView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SetupCardView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- mCardHeight = getResources().getDimension(R.dimen.card_layout_height);
- }
-
- @Override
- protected float getCardHeight() {
- return mCardHeight;
- }
-}
diff --git a/src/com/android/tv/menu/SimpleCardView.java b/src/com/android/tv/menu/SimpleCardView.java
index 24a44244..c99834be 100644
--- a/src/com/android/tv/menu/SimpleCardView.java
+++ b/src/com/android/tv/menu/SimpleCardView.java
@@ -19,16 +19,12 @@ package com.android.tv.menu;
import android.content.Context;
import android.util.AttributeSet;
-import com.android.tv.R;
import com.android.tv.data.Channel;
/**
* A view to render a guide card.
*/
public class SimpleCardView extends BaseCardView<Channel> {
- private static final String TAG = "GuideCardView";
- private static final boolean DEBUG = false;
- private final float mCardHeight;
public SimpleCardView(Context context) {
this(context, null, 0);
@@ -40,11 +36,5 @@ public class SimpleCardView extends BaseCardView<Channel> {
public SimpleCardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
- mCardHeight = getResources().getDimension(R.dimen.card_layout_height);
- }
-
- @Override
- protected float getCardHeight() {
- return mCardHeight;
}
}
diff --git a/src/com/android/tv/menu/TvOptionsRowAdapter.java b/src/com/android/tv/menu/TvOptionsRowAdapter.java
index ba84247b..fb062246 100644
--- a/src/com/android/tv/menu/TvOptionsRowAdapter.java
+++ b/src/com/android/tv/menu/TvOptionsRowAdapter.java
@@ -19,7 +19,6 @@ package com.android.tv.menu;
import android.content.Context;
import android.media.tv.TvTrackInfo;
import android.support.annotation.VisibleForTesting;
-import android.support.v4.os.BuildCompat;
import com.android.tv.Features;
import com.android.tv.R;
@@ -28,6 +27,7 @@ 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.PipInputManager;
@@ -39,14 +39,14 @@ import java.util.List;
* An adapter of options.
*/
public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
+ private static final boolean ENABLE_IN_APP_PIP = false;
+
private int mPositionPipAction;
// If mInAppPipAction is false, system-wide PIP is used.
private boolean mInAppPipAction = true;
- private final Context mContext;
public TvOptionsRowAdapter(Context context, List<CustomAction> customActions) {
super(context, customActions);
- mContext = context;
}
@Override
@@ -61,8 +61,9 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
mPositionPipAction = actionList.size() - 1;
actionList.add(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION);
setOptionChangedListener(MenuAction.SELECT_AUDIO_LANGUAGE_ACTION);
- if (Features.ONBOARDING_PLAY_STORE.isEnabled(getMainActivity())) {
- actionList.add(MenuAction.MORE_CHANNELS_ACTION);
+ actionList.add(MenuAction.MORE_CHANNELS_ACTION);
+ if (DeveloperOptionFragment.shouldShow()) {
+ actionList.add(MenuAction.DEV_ACTION);
}
actionList.add(MenuAction.SETTINGS_ACTION);
@@ -109,23 +110,23 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
// Case 1
PipInputManager pipInputManager = getMainActivity().getPipInputManager();
- if (pipInputManager.getPipInputSize(false) < 2) {
+ if (ENABLE_IN_APP_PIP && pipInputManager.getPipInputSize(false) > 1) {
+ if (!mInAppPipAction) {
+ removeAction(mPositionPipAction);
+ addAction(mPositionPipAction, MenuAction.PIP_IN_APP_ACTION);
+ mInAppPipAction = true;
+ changed = true;
+ }
+ } else {
if (mInAppPipAction) {
removeAction(mPositionPipAction);
mInAppPipAction = false;
- if (BuildCompat.isAtLeastN()) {
+ if (Features.PICTURE_IN_PICTURE.isEnabled(getMainActivity())) {
addAction(mPositionPipAction, MenuAction.SYSTEMWIDE_PIP_ACTION);
}
return true;
}
return false;
- } else {
- if (!mInAppPipAction) {
- removeAction(mPositionPipAction);
- addAction(mPositionPipAction, MenuAction.PIP_IN_APP_ACTION);
- mInAppPipAction = true;
- changed = true;
- }
}
// Case 2
@@ -175,12 +176,12 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
protected void executeBaseAction(int type) {
switch (type) {
case TvOptionsManager.OPTION_CLOSED_CAPTIONS:
- getMainActivity().getOverlayManager().getSideFragmentManager().show(
- new ClosedCaptionFragment());
+ getMainActivity().getOverlayManager().getSideFragmentManager()
+ .show(new ClosedCaptionFragment());
break;
case TvOptionsManager.OPTION_DISPLAY_MODE:
- getMainActivity().getOverlayManager().getSideFragmentManager().show(
- new DisplayModeFragment());
+ getMainActivity().getOverlayManager().getSideFragmentManager()
+ .show(new DisplayModeFragment());
break;
case TvOptionsManager.OPTION_IN_APP_PIP:
getMainActivity().togglePipView();
@@ -189,12 +190,16 @@ public class TvOptionsRowAdapter extends CustomizableOptionsRowAdapter {
getMainActivity().enterPictureInPictureMode();
break;
case TvOptionsManager.OPTION_MULTI_AUDIO:
- getMainActivity().getOverlayManager().getSideFragmentManager().show(
- new MultiAudioFragment());
+ getMainActivity().getOverlayManager().getSideFragmentManager()
+ .show(new MultiAudioFragment());
break;
case TvOptionsManager.OPTION_MORE_CHANNELS:
getMainActivity().showMerchantCollection();
break;
+ case TvOptionsManager.OPTION_DEVELOPER:
+ getMainActivity().getOverlayManager().getSideFragmentManager()
+ .show(new DeveloperOptionFragment());
+ break;
case TvOptionsManager.OPTION_SETTINGS:
getMainActivity().showSettingsFragment();
break;
diff --git a/src/com/android/tv/onboarding/NewSourcesFragment.java b/src/com/android/tv/onboarding/NewSourcesFragment.java
index ebaf0b6c..8509b50c 100644
--- a/src/com/android/tv/onboarding/NewSourcesFragment.java
+++ b/src/com/android/tv/onboarding/NewSourcesFragment.java
@@ -17,7 +17,6 @@
package com.android.tv.onboarding;
import android.app.Fragment;
-import android.os.Build;
import android.os.Bundle;
import android.transition.Slide;
import android.view.Gravity;
@@ -27,7 +26,6 @@ import android.view.ViewGroup;
import com.android.tv.R;
import com.android.tv.TvApplication;
-import com.android.tv.common.ui.setup.OnActionClickListener;
import com.android.tv.common.ui.setup.SetupActionHelper;
import com.android.tv.util.SetupUtils;
@@ -35,12 +33,20 @@ import com.android.tv.util.SetupUtils;
* A fragment for new channel source info/setup.
*/
public class NewSourcesFragment extends Fragment {
- public static final String ACTION_CATEOGRY = NewSourcesFragment.class.getCanonicalName();
+ /**
+ * The action category.
+ */
+ 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.
+ */
public static final int ACTION_SKIP = 2;
- private OnActionClickListener mOnActionClickListener;
-
public NewSourcesFragment() {
setAllowEnterTransitionOverlap(false);
setAllowReturnTransitionOverlap(false);
@@ -62,21 +68,8 @@ public class NewSourcesFragment extends Fragment {
return view;
}
- /**
- * Sets the {@link OnActionClickListener}. This method should be called before the views are
- * created.
- */
- public void setOnActionClickListener(OnActionClickListener onActionClickListener) {
- mOnActionClickListener = onActionClickListener;
- }
-
private void initializeButton(View view, int actionId) {
- view.setOnClickListener(SetupActionHelper.createOnClickListenerForAction(
- mOnActionClickListener, ACTION_CATEOGRY, actionId));
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // Prior to M, foreground ripple animation is not supported.
- // Use background ripple drawable instead of drawing in the foreground manually.
- view.setBackground(getActivity().getDrawable(R.drawable.setup_selector_background));
- }
+ view.setOnClickListener(SetupActionHelper.createOnClickListenerForAction(this,
+ ACTION_CATEOGRY, actionId, null));
}
}
diff --git a/src/com/android/tv/onboarding/OnboardingActivity.java b/src/com/android/tv/onboarding/OnboardingActivity.java
index 0685d14b..45205c4c 100644
--- a/src/com/android/tv/onboarding/OnboardingActivity.java
+++ b/src/com/android/tv/onboarding/OnboardingActivity.java
@@ -17,32 +17,40 @@
package com.android.tv.onboarding;
import android.app.Fragment;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.os.Build;
+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.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.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;
public class OnboardingActivity extends SetupActivity {
private static final String KEY_INTENT_AFTER_COMPLETION = "key_intent_after_completion";
private static final int PERMISSIONS_REQUEST_READ_TV_LISTINGS = 1;
- private static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
private static final int SHOW_RIPPLE_DURATION_MS = 266;
+ private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
+
private ChannelDataManager mChannelDataManager;
+ private TvInputManagerHelper mInputManager;
private final ChannelDataManager.Listener mChannelListener = new ChannelDataManager.Listener() {
@Override
public void onLoadFinished() {
@@ -73,16 +81,20 @@ public class OnboardingActivity extends SetupActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- if (!PermissionUtils.hasAccessAllEpg(this)) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Toast.makeText(this, R.string.msg_not_supported_device, Toast.LENGTH_LONG).show();
- finish();
- return;
- } else if (checkSelfPermission(PERMISSION_READ_TV_LISTINGS)
- != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(new String[]{PERMISSION_READ_TV_LISTINGS},
- PERMISSIONS_REQUEST_READ_TV_LISTINGS);
+ ApplicationSingletons singletons = TvApplication.getSingletons(this);
+ mInputManager = singletons.getTvInputManagerHelper();
+ 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()) {
+ SetupUtils.getInstance(this).markNewChannelsBrowsable();
+ } else {
+ mChannelDataManager.addListener(mChannelListener);
}
+ } else {
+ requestPermissions(new String[] {PermissionUtils.PERMISSION_READ_TV_LISTINGS},
+ PERMISSIONS_REQUEST_READ_TV_LISTINGS);
}
}
@@ -97,14 +109,6 @@ public class OnboardingActivity extends SetupActivity {
@Override
protected Fragment onCreateInitialFragment() {
if (PermissionUtils.hasAccessAllEpg(this) || PermissionUtils.hasReadTvListings(this)) {
- // Make the channels of the new inputs which have been setup outside Live TV
- // browsable.
- mChannelDataManager = TvApplication.getSingletons(this).getChannelDataManager();
- if (mChannelDataManager.isDbLoadFinished()) {
- SetupUtils.getInstance(this).markNewChannelsBrowsable();
- } else {
- mChannelDataManager.addListener(mChannelListener);
- }
return OnboardingUtils.isFirstRunWithCurrentVersion(this) ? new WelcomeFragment()
: new SetupSourcesFragment();
}
@@ -115,8 +119,7 @@ public class OnboardingActivity extends SetupActivity {
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_TV_LISTINGS) {
- if (grantResults != null && grantResults.length > 0
- && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
finish();
Intent intentForNextActivity = getIntent().getParcelableExtra(
KEY_INTENT_AFTER_COMPLETION);
@@ -129,7 +132,7 @@ public class OnboardingActivity extends SetupActivity {
}
}
- void finishActivity() {
+ private void finishActivity() {
Intent intentForNextActivity = getIntent().getParcelableExtra(
KEY_INTENT_AFTER_COMPLETION);
if (intentForNextActivity != null) {
@@ -138,17 +141,17 @@ public class OnboardingActivity extends SetupActivity {
finish();
}
- void showMerchantCollection() {
+ private void showMerchantCollection() {
executeActionWithDelay(new Runnable() {
@Override
public void run() {
- startActivity(OnboardingUtils.PLAY_STORE_INTENT);
+ startActivity(OnboardingUtils.ONLINE_STORE_INTENT);
}
}, SHOW_RIPPLE_DURATION_MS);
}
@Override
- protected void executeAction(String category, int actionId) {
+ protected boolean executeAction(String category, int actionId, Bundle params) {
switch (category) {
case WelcomeFragment.ACTION_CATEGORY:
switch (actionId) {
@@ -156,14 +159,40 @@ public class OnboardingActivity extends SetupActivity {
OnboardingUtils.setFirstRunWithCurrentVersionCompleted(
OnboardingActivity.this);
showFragment(new SetupSourcesFragment(), false);
- break;
+ return true;
}
break;
case SetupSourcesFragment.ACTION_CATEGORY:
switch (actionId) {
- case SetupSourcesFragment.ACTION_PLAY_STORE:
+ case SetupSourcesFragment.ACTION_ONLINE_STORE:
showMerchantCollection();
- break;
+ return true;
+ case SetupSourcesFragment.ACTION_SETUP_INPUT: {
+ String inputId = params.getString(
+ SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
+ TvInputInfo input = mInputManager.getTvInputInfo(inputId);
+ Intent intent = TvCommonUtils.createSetupIntent(input);
+ if (intent == null) {
+ Toast.makeText(this, R.string.msg_no_setup_activity, Toast.LENGTH_SHORT)
+ .show();
+ return true;
+ }
+ // Even though other app can handle the intent, the setup launched by Live
+ // channels should go through Live channels SetupPassthroughActivity.
+ intent.setComponent(new ComponentName(this,
+ SetupPassthroughActivity.class));
+ try {
+ // Now we know that the user intends to set up this input. Grant
+ // permission for writing EPG data.
+ SetupUtils.grantEpgPermission(this, input.getServiceInfo().packageName);
+ startActivityForResult(intent, REQUEST_CODE_START_SETUP_ACTIVITY);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this,
+ getString(R.string.msg_unable_to_start_setup_activity,
+ input.loadLabel(this)), Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
case SetupMultiPaneFragment.ACTION_DONE: {
ChannelDataManager manager = TvApplication.getSingletons(
OnboardingActivity.this).getChannelDataManager();
@@ -172,10 +201,11 @@ public class OnboardingActivity extends SetupActivity {
} else {
finishActivity();
}
- break;
+ return true;
}
}
break;
}
+ return false;
}
}
diff --git a/src/com/android/tv/onboarding/SetupSourcesFragment.java b/src/com/android/tv/onboarding/SetupSourcesFragment.java
index 23145503..7607822c 100644
--- a/src/com/android/tv/onboarding/SetupSourcesFragment.java
+++ b/src/com/android/tv/onboarding/SetupSourcesFragment.java
@@ -16,12 +16,8 @@
package com.android.tv.onboarding;
-import android.content.ActivityNotFoundException;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager.TvInputCallback;
import android.os.Bundle;
@@ -33,23 +29,18 @@ import android.support.v17.leanback.widget.VerticalGridView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageView;
import android.widget.TextView;
-import android.widget.Toast;
import com.android.tv.ApplicationSingletons;
-import com.android.tv.Features;
import com.android.tv.R;
-import com.android.tv.SetupPassthroughActivity;
import com.android.tv.TvApplication;
-import com.android.tv.common.TvCommonUtils;
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.ui.GuidedActionsStylistWithDivider;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
-import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
@@ -59,17 +50,30 @@ import java.util.List;
* A fragment for channel source info/setup.
*/
public class SetupSourcesFragment extends SetupMultiPaneFragment {
- private static final String TAG = "SetupSourcesFragment";
-
+ /**
+ * 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 int ACTION_PLAY_STORE = 1;
-
- private static final String SETUP_TRACKER_LABEL = "Setup fragment";
+ /**
+ * An action to open the merchant collection.
+ */
+ public static final int ACTION_ONLINE_STORE = 1;
+ /**
+ * An action to show the setup activity of TV input.
+ * <p>
+ * This action is not added to the action list. This is sent outside of the fragment.
+ * Use {@link #ACTION_PARAM_KEY_INPUT_ID} to get the input ID from the parameter.
+ */
+ public static final int ACTION_SETUP_INPUT = 2;
- private InputSetupRunnable mInputSetupRunnable;
+ /**
+ * The key for the action parameter which contains the TV input ID. It's used for the action
+ * {@link #ACTION_SETUP_INPUT}.
+ */
+ public static final String ACTION_PARAM_KEY_INPUT_ID = "input_id";
- private ContentFragment mContentFragment;
+ private static final String SETUP_TRACKER_LABEL = "Setup fragment";
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
@@ -81,19 +85,21 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
@Override
protected void onEnterTransitionEnd() {
- if (mContentFragment != null) {
- mContentFragment.executePendingAction();
+ SetupGuidedStepFragment f = getContentFragment();
+ if (f instanceof ContentFragment) {
+ // If the enter transition is canceled quickly, the child fragment can be null because
+ // the fragment is added asynchronously.
+ ((ContentFragment) f).executePendingAction();
}
}
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
- mContentFragment = new ContentFragment();
- mContentFragment.setParentFragment(this);
+ SetupGuidedStepFragment f = new ContentFragment();
Bundle arguments = new Bundle();
arguments.putBoolean(SetupGuidedStepFragment.KEY_THREE_PANE, true);
- mContentFragment.setArguments(arguments);
- return mContentFragment;
+ f.setArguments(arguments);
+ return f;
}
@Override
@@ -101,32 +107,8 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
return ACTION_CATEGORY;
}
- /**
- * Call this method to run customized input setup.
- *
- * @param runnable runnable to be called when the input setup is necessary.
- */
- public void setInputSetupRunnable(InputSetupRunnable runnable) {
- mInputSetupRunnable = runnable;
- }
-
- /**
- * Interface for the customized input setup.
- */
- public interface InputSetupRunnable {
- /**
- * Called for the input setup.
- *
- * @param input TV input for setup.
- */
- void runInputSetup(TvInputInfo input);
- }
-
public static class ContentFragment extends SetupGuidedStepFragment {
- private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
-
- // ACTION_PLAY_STORE is defined in the outer class.
- private static final int ACTION_DIVIDER = 2;
+ // ACTION_ONLINE_STORE is defined in the outer class.
private static final int ACTION_HEADER = 3;
private static final int ACTION_INPUT_START = 4;
@@ -163,6 +145,11 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
handleInputChanged();
}
+ @Override
+ public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
+ handleInputChanged();
+ }
+
private void handleInputChanged() {
// The actions created while enter transition is running will not be included in the
// fragment transition.
@@ -175,10 +162,6 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
}
};
- void setParentFragment(SetupSourcesFragment parentFragment) {
- mParentFragment = parentFragment;
- }
-
private final ChannelDataManager.Listener mChannelDataManagerListener
= new ChannelDataManager.Listener() {
@Override
@@ -211,7 +194,6 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
- // TODO: Handle USB TV tuner differently.
Context context = getActivity();
ApplicationSingletons app = TvApplication.getSingletons(context);
mInputManager = app.getTvInputManagerHelper();
@@ -221,6 +203,7 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
mInputManager.addCallback(mInputCallback);
mChannelDataManager.addListener(mChannelDataManagerListener);
super.onCreate(savedInstanceState);
+ mParentFragment = (SetupSourcesFragment) getParentFragment();
}
@Override
@@ -289,16 +272,24 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
int position = 0;
if (mDoneInputStartIndex > 0) {
// Need a "New" category
- actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_HEADER)
- .title(null).description(getString(R.string.setup_category_new))
- .focusable(false).build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_HEADER)
+ .title(null)
+ .description(getString(R.string.setup_category_new))
+ .focusable(false)
+ .infoOnly(true)
+ .build());
}
for (int i = 0; i < mInputs.size(); ++i) {
if (i == mDoneInputStartIndex) {
++position;
- actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_HEADER)
- .title(null).description(getString(R.string.setup_category_done))
- .focusable(false).build());
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_HEADER)
+ .title(null)
+ .description(getString(R.string.setup_category_done))
+ .focusable(false)
+ .infoOnly(true)
+ .build());
}
TvInputInfo input = mInputs.get(i);
String inputId = input.getId();
@@ -320,24 +311,26 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
if (input.getId().equals(mNewlyAddedInputId)) {
newPosition = position;
}
- actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_INPUT_START + i)
- .title(input.loadLabel(getActivity()).toString()).description(description)
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_INPUT_START + i)
+ .title(input.loadLabel(getActivity()).toString())
+ .description(description)
.build());
}
- if (Features.ONBOARDING_PLAY_STORE.isEnabled(getActivity())) {
- if (mInputs.size() > 0) {
- // Divider
- ++position;
- actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_DIVIDER)
- .title(null).description(null).focusable(false).build());
- }
- // Play store action
+ if (mInputs.size() > 0) {
+ // Divider
++position;
- actions.add(new GuidedAction.Builder(getActivity()).id(ACTION_PLAY_STORE)
- .title(getString(R.string.setup_play_store_action_title))
- .description(getString(R.string.setup_play_store_action_description))
- .icon(R.drawable.ic_playstore).build());
+ actions.add(GuidedActionsStylistWithDivider.createDividerAction(getContext()));
}
+ // online store action
+ ++position;
+ actions.add(new GuidedAction.Builder(getActivity())
+ .id(ACTION_ONLINE_STORE)
+ .title(getString(R.string.setup_store_action_title))
+ .description(getString(R.string.setup_store_action_description))
+ .icon(R.drawable.ic_store)
+ .build());
+
if (newPosition != -1) {
VerticalGridView gridView = getGuidedActionsStylist().getActionsGridView();
gridView.setSelectedPosition(newPosition);
@@ -351,38 +344,17 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
@Override
public void onGuidedActionClicked(GuidedAction action) {
- if (action.getId() == ACTION_PLAY_STORE) {
+ if (action.getId() == ACTION_ONLINE_STORE) {
mParentFragment.onActionClick(ACTION_CATEGORY, (int) action.getId());
return;
}
- TvInputInfo input = mInputs.get((int) action.getId() - ACTION_INPUT_START);
- if (mParentFragment.mInputSetupRunnable != null) {
- mParentFragment.mInputSetupRunnable.runInputSetup(input);
- return;
+ int index = (int) action.getId() - ACTION_INPUT_START;
+ if (index >= 0) {
+ TvInputInfo input = mInputs.get(index);
+ Bundle params = new Bundle();
+ params.putString(ACTION_PARAM_KEY_INPUT_ID, input.getId());
+ mParentFragment.onActionClick(ACTION_CATEGORY, ACTION_SETUP_INPUT, params);
}
- Intent intent = TvCommonUtils.createSetupIntent(input);
- if (intent == null) {
- Toast.makeText(getActivity(), R.string.msg_no_setup_activity, Toast.LENGTH_SHORT)
- .show();
- return;
- }
- // Even though other app can handle the intent, the setup launched by Live channels
- // should go through Live channels SetupPassthroughActivity.
- intent.setComponent(new ComponentName(getActivity(), SetupPassthroughActivity.class));
- try {
- // Now we know that the user intends to set up this input. Grant permission for
- // writing EPG data.
- SetupUtils.grantEpgPermission(getActivity(), input.getServiceInfo().packageName);
- startActivityForResult(intent, REQUEST_CODE_START_SETUP_ACTIVITY);
- } catch (ActivityNotFoundException e) {
- Toast.makeText(getActivity(), getString(R.string.msg_unable_to_start_setup_activity,
- input.loadLabel(getActivity())), Toast.LENGTH_SHORT).show();
- }
- }
-
- @Override
- public void onActivityResult(int requestCode, int resultCode, Intent data) {
- updateActions();
}
void executePendingAction() {
@@ -397,60 +369,28 @@ public class SetupSourcesFragment extends SetupMultiPaneFragment {
mPendingAction = PENDING_ACTION_NONE;
}
- private class SetupSourceGuidedActionsStylist extends GuidedActionsStylist {
- private static final int VIEW_TYPE_DIVIDER = 1;
-
+ private class SetupSourceGuidedActionsStylist extends GuidedActionsStylistWithDivider {
private static final float ALPHA_CATEGORY = 1.0f;
private static final float ALPHA_INPUT_DESCRIPTION = 0.5f;
@Override
- public int getItemViewType(GuidedAction action) {
- if (action.getId() == ACTION_DIVIDER) {
- return VIEW_TYPE_DIVIDER;
- }
- return super.getItemViewType(action);
- }
-
- @Override
- public int onProvideItemLayoutId(int viewType) {
- if (viewType == VIEW_TYPE_DIVIDER) {
- return R.layout.onboarding_item_divider;
- }
- return super.onProvideItemLayoutId(viewType);
- }
-
- @Override
public void onBindViewHolder(ViewHolder vh, GuidedAction action) {
super.onBindViewHolder(vh, action);
TextView descriptionView = vh.getDescriptionView();
if (descriptionView != null) {
if (action.getId() == ACTION_HEADER) {
descriptionView.setAlpha(ALPHA_CATEGORY);
- descriptionView.setTextColor(Utils.getColor(getResources(),
- R.color.setup_category));
+ descriptionView.setTextColor(getResources().getColor(R.color.setup_category,
+ null));
descriptionView.setTypeface(Typeface.create(
getString(R.string.condensed_font), 0));
} else {
descriptionView.setAlpha(ALPHA_INPUT_DESCRIPTION);
- descriptionView.setTextColor(Utils.getColor(getResources(),
- R.color.common_setup_input_description));
+ descriptionView.setTextColor(getResources().getColor(
+ R.color.common_setup_input_description, null));
descriptionView.setTypeface(Typeface.create(getString(R.string.font), 0));
}
}
- // Workaround for b/26473407.
- ImageView iconView = vh.getIconView();
- if (iconView != null) {
- Drawable icon = action.getIcon();
- if (icon != null) {
- // setImageDrawable resets the drawable's level unless we set the view level
- // first.
- iconView.setImageLevel(icon.getLevel());
- iconView.setImageDrawable(icon);
- iconView.setVisibility(View.VISIBLE);
- } else {
- iconView.setVisibility(View.GONE);
- }
- }
}
}
}
diff --git a/src/com/android/tv/onboarding/WelcomeFragment.java b/src/com/android/tv/onboarding/WelcomeFragment.java
index 00f7fe8d..f12233e9 100644
--- a/src/com/android/tv/onboarding/WelcomeFragment.java
+++ b/src/com/android/tv/onboarding/WelcomeFragment.java
@@ -591,12 +591,6 @@ public class WelcomeFragment extends OnboardingFragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
- initialize();
- }
-
- @Override
public void onAttach(Context context) {
super.onAttach(context);
initialize();
diff --git a/src/com/android/tv/receiver/BootCompletedReceiver.java b/src/com/android/tv/receiver/BootCompletedReceiver.java
index da88f70d..8d6c5a14 100644
--- a/src/com/android/tv/receiver/BootCompletedReceiver.java
+++ b/src/com/android/tv/receiver/BootCompletedReceiver.java
@@ -21,11 +21,11 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.support.v4.os.BuildCompat;
import android.util.Log;
import com.android.tv.Features;
import com.android.tv.TvActivity;
+import com.android.tv.TvApplication;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.dvr.DvrRecordingService;
import com.android.tv.recommendation.NotificationService;
@@ -50,6 +50,7 @@ public class BootCompletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "boot completed " + intent);
+ TvApplication.setCurrentRunningProcess(context, true);
// Start {@link NotificationService}.
Intent notificationIntent = new Intent(context, NotificationService.class);
notificationIntent.setAction(NotificationService.ACTION_SHOW_RECOMMENDATION);
@@ -73,7 +74,7 @@ public class BootCompletedReceiver extends BroadcastReceiver {
}
}
- if (CommonFeatures.DVR.isEnabled(context) && BuildCompat.isAtLeastN()) {
+ if (CommonFeatures.DVR.isEnabled(context)) {
DvrRecordingService.startService(context);
}
}
diff --git a/src/com/android/tv/receiver/GlobalKeyReceiver.java b/src/com/android/tv/receiver/GlobalKeyReceiver.java
index 2e19c089..8cd4fdf1 100644
--- a/src/com/android/tv/receiver/GlobalKeyReceiver.java
+++ b/src/com/android/tv/receiver/GlobalKeyReceiver.java
@@ -35,6 +35,7 @@ public class GlobalKeyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ TvApplication.setCurrentRunningProcess(context, true);
if (ACTION_GLOBAL_BUTTON.equals(intent.getAction())) {
KeyEvent event = intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT);
if (DEBUG) Log.d(TAG, "onReceive: " + event);
diff --git a/src/com/android/tv/receiver/PackageIntentsReceiver.java b/src/com/android/tv/receiver/PackageIntentsReceiver.java
index 4c850402..26d000e7 100644
--- a/src/com/android/tv/receiver/PackageIntentsReceiver.java
+++ b/src/com/android/tv/receiver/PackageIntentsReceiver.java
@@ -29,6 +29,7 @@ public class PackageIntentsReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ TvApplication.setCurrentRunningProcess(context, true);
((TvApplication) context.getApplicationContext()).handleInputCountChanged();
}
}
diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java
index 0095482d..30ec73e3 100644
--- a/src/com/android/tv/recommendation/NotificationService.java
+++ b/src/com/android/tv/recommendation/NotificationService.java
@@ -28,7 +28,6 @@ import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.media.tv.TvInputInfo;
-import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -52,7 +51,6 @@ import com.android.tv.data.Program;
import com.android.tv.util.BitmapUtils;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
import com.android.tv.util.ImageLoader;
-import com.android.tv.util.PermissionUtils;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -128,14 +126,8 @@ public class NotificationService extends Service implements Recommender.Listener
@Override
public void onCreate() {
if (DEBUG) Log.d(TAG, "onCreate");
+ TvApplication.setCurrentRunningProcess(this, true);
super.onCreate();
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
- && !PermissionUtils.hasAccessAllEpg(this)) {
- Log.w(TAG, "Live TV requires the system permission on this platform.");
- stopSelf();
- return;
- }
-
mCurrentNotificationCount = 0;
mNotificationChannels = new long[NOTIFICATION_COUNT];
for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
@@ -426,8 +418,7 @@ public class NotificationService extends Service implements Recommender.Listener
}
private void sendNotification(int notificationId, Bitmap channelLogo, Channel channel,
- Bitmap posterArtBitmap, Program program, String inputDisplayName1) {
-
+ Bitmap posterArtBitmap, Program program, String inputDisplayName) {
final long programDurationMs = program.getEndTimeUtcMillis() - program
.getStartTimeUtcMillis();
long programLeftTimsMs = program.getEndTimeUtcMillis() - System.currentTimeMillis();
@@ -442,16 +433,18 @@ public class NotificationService extends Service implements Recommender.Listener
: overlayChannelLogo(channelLogo, posterArtBitmap);
String channelDisplayName = channel.getDisplayName();
Notification notification = new Notification.Builder(this)
- .setContentIntent(notificationIntent).setContentTitle(program.getTitle())
- .setContentText(inputDisplayName1 + " " +
- (TextUtils.isEmpty(channelDisplayName) ? channel.getDisplayNumber()
- : channelDisplayName)).setContentInfo(channelDisplayName)
+ .setContentIntent(notificationIntent)
+ .setContentTitle(program.getTitle())
+ .setContentText(TextUtils.isEmpty(channelDisplayName) ? channel.getDisplayNumber()
+ : channelDisplayName)
+ .setContentInfo(channelDisplayName)
.setAutoCancel(true).setLargeIcon(largeIconBitmap)
.setSmallIcon(R.drawable.ic_launcher_s)
.setCategory(Notification.CATEGORY_RECOMMENDATION)
.setProgress((programProgress > 0) ? 100 : 0, programProgress, false)
- .setSortKey(mRecommender.getChannelSortKey(channel.getId())).build();
- notification.color = Utils.getColor(getResources(), R.color.recommendation_card_background);
+ .setSortKey(mRecommender.getChannelSortKey(channel.getId()))
+ .build();
+ notification.color = getResources().getColor(R.color.recommendation_card_background, null);
if (!TextUtils.isEmpty(program.getThumbnailUri())) {
notification.extras
.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, program.getThumbnailUri());
diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java
index a7d4c46d..62ccd578 100644
--- a/src/com/android/tv/recommendation/RecommendationDataManager.java
+++ b/src/com/android/tv/recommendation/RecommendationDataManager.java
@@ -16,8 +16,8 @@
package com.android.tv.recommendation;
+import android.annotation.SuppressLint;
import android.content.Context;
-import android.content.UriMatcher;
import android.database.ContentObserver;
import android.database.Cursor;
import android.media.tv.TvContract;
@@ -41,6 +41,7 @@ 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.TvProviderUriMatcher;
import java.util.ArrayList;
import java.util.Collection;
@@ -52,17 +53,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class RecommendationDataManager implements WatchedHistoryManager.Listener {
- 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_WATCHED_PROGRAM_ID = 3;
- static {
- sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- sUriMatcher.addURI(TvContract.AUTHORITY, "channel", MATCH_CHANNEL);
- sUriMatcher.addURI(TvContract.AUTHORITY, "channel/#", MATCH_CHANNEL_ID);
- sUriMatcher.addURI(TvContract.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID);
- }
-
private static final int MSG_START = 1000;
private static final int MSG_STOP = 1001;
private static final int MSG_UPDATE_CHANNELS = 1002;
@@ -130,8 +120,9 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
public synchronized static RecommendationDataManager acquireManager(
Context context, @NonNull Listener listener) {
if (sManager == null) {
- sManager = new RecommendationDataManager(context, listener);
+ sManager = new RecommendationDataManager(context);
}
+ sManager.addListener(listener);
return sManager;
}
@@ -191,7 +182,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
public void onInputUpdated(String inputId) { }
};
- private RecommendationDataManager(Context context, final Listener listener) {
+ private RecommendationDataManager(Context context) {
mContext = context.getApplicationContext();
mHandlerThread = new HandlerThread("RecommendationDataManager");
mHandlerThread.start();
@@ -202,7 +193,6 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
runOnMainThread(new Runnable() {
@Override
public void run() {
- addListener(listener);
start();
}
});
@@ -273,9 +263,13 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
.sendToTarget();
}
- @MainThread
private void addListener(Listener listener) {
- mListeners.add(listener);
+ runOnMainThread(new Runnable() {
+ @Override
+ public void run() {
+ mListeners.add(listener);
+ }
+ });
}
@MainThread
@@ -493,7 +487,7 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
private ChannelRecord updateChannelRecordFromWatchedProgram(WatchedProgram program) {
ChannelRecord channelRecord = null;
- if (program != null && program.getWatchEndTimeMs() != 0l) {
+ if (program != null && program.getWatchEndTimeMs() != 0L) {
channelRecord = mChannelRecordMap.get(program.getProgram().getChannelId());
if (channelRecord != null
&& channelRecord.getLastWatchEndTimeMs() < program.getWatchEndTimeMs()) {
@@ -508,10 +502,11 @@ public class RecommendationDataManager implements WatchedHistoryManager.Listener
super(handler);
}
+ @SuppressLint("SwitchIntDef")
@Override
public void onChange(final boolean selfChange, final Uri uri) {
- switch (sUriMatcher.match(uri)) {
- case MATCH_WATCHED_PROGRAM_ID:
+ switch (TvProviderUriMatcher.match(uri)) {
+ case TvProviderUriMatcher.MATCH_WATCHED_PROGRAM_ID:
if (!mHandler.hasMessages(MSG_UPDATE_WATCH_HISTORY,
TvContract.WatchedPrograms.CONTENT_URI)) {
mHandler.obtainMessage(MSG_UPDATE_WATCH_HISTORY, uri).sendToTarget();
diff --git a/src/com/android/tv/search/DataManagerSearch.java b/src/com/android/tv/search/DataManagerSearch.java
index d26ae334..5f89a21a 100644
--- a/src/com/android/tv/search/DataManagerSearch.java
+++ b/src/com/android/tv/search/DataManagerSearch.java
@@ -22,6 +22,7 @@ import android.media.tv.TvContentRating;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Programs;
import android.media.tv.TvInputManager;
+import android.os.SystemClock;
import android.support.annotation.MainThread;
import android.text.TextUtils;
import android.util.Log;
@@ -50,8 +51,8 @@ import java.util.concurrent.Future;
* and {@link ProgramDataManager}.
*/
public class DataManagerSearch implements SearchInterface {
- private static final boolean DEBUG = false;
private static final String TAG = "TvProviderSearch";
+ private static final boolean DEBUG = false;
private final Context mContext;
private final TvInputManager mTvInputManager;
@@ -98,6 +99,8 @@ public class DataManagerSearch implements SearchInterface {
// Voice search query should be handled by the a system TV app.
return results;
}
+ if (DEBUG) Log.d(TAG, "Searching channels: '" + query + "'");
+ long time = SystemClock.elapsedRealtime();
Set<Long> channelsFound = new HashSet<>();
List<Channel> channelList = mChannelDataManager.getBrowsableChannelList();
query = query.toLowerCase();
@@ -110,6 +113,11 @@ public class DataManagerSearch implements SearchInterface {
addResult(results, channelsFound, channel, null);
}
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " channels. Elapsed time for" +
+ " searching channels: " + (SystemClock.elapsedRealtime() - time) +
+ "(msec)");
+ }
return results;
}
}
@@ -124,9 +132,21 @@ public class DataManagerSearch implements SearchInterface {
addResult(results, channelsFound, channel, null);
}
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " channels. Elapsed time for" +
+ " searching channels: " + (SystemClock.elapsedRealtime() - time) +
+ "(msec)");
+ }
return results;
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " channels. Elapsed time for" +
+ " searching channels: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
+ int channelResult = results.size();
+ if (DEBUG) Log.d(TAG, "Searching programs: '" + query + "'");
+ time = SystemClock.elapsedRealtime();
for (Channel channel : channelList) {
if (channelsFound.contains(channel.getId())) {
continue;
@@ -140,6 +160,11 @@ public class DataManagerSearch implements SearchInterface {
addResult(results, channelsFound, channel, program);
}
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + (results.size() - channelResult) + " programs. Elapsed" +
+ " time for searching programs: " +
+ (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return results;
}
}
@@ -156,9 +181,18 @@ public class DataManagerSearch implements SearchInterface {
addResult(results, channelsFound, channel, program);
}
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + (results.size() - channelResult) + " programs. Elapsed" +
+ " time for searching programs: " +
+ (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return results;
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Found " + (results.size() - channelResult) + " programs. Elapsed time for" +
+ " searching programs: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return results;
}
diff --git a/src/com/android/tv/search/LocalSearchProvider.java b/src/com/android/tv/search/LocalSearchProvider.java
index 7edb07dc..9255a43d 100644
--- a/src/com/android/tv/search/LocalSearchProvider.java
+++ b/src/com/android/tv/search/LocalSearchProvider.java
@@ -22,6 +22,7 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
+import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
@@ -32,8 +33,8 @@ import java.util.Arrays;
import java.util.List;
public class LocalSearchProvider extends ContentProvider {
- private static final boolean DEBUG = false;
private static final String TAG = "LocalSearchProvider";
+ private static final boolean DEBUG = false;
public static final int PROGRESS_PERCENTAGE_HIDE = -1;
@@ -76,10 +77,13 @@ public class LocalSearchProvider extends ContentProvider {
Log.d(TAG, "query(" + uri + ", " + Arrays.toString(projection) + ", " + selection + ", "
+ Arrays.toString(selectionArgs) + ", " + sortOrder + ")");
}
+ long time = SystemClock.elapsedRealtime();
SearchInterface search;
if (PermissionUtils.hasAccessAllEpg(getContext())) {
+ if (DEBUG) Log.d(TAG, "Performing TV Provider search.");
search = new TvProviderSearch(getContext());
} else {
+ if (DEBUG) Log.d(TAG, "Performing Data Manager search.");
search = new DataManagerSearch(getContext());
}
String query = uri.getLastPathSegment();
@@ -95,7 +99,9 @@ public class LocalSearchProvider extends ContentProvider {
if (!TextUtils.isEmpty(query)) {
results.addAll(search.search(query, limit, action));
}
- return createSuggestionsCursor(results);
+ Cursor c = createSuggestionsCursor(results);
+ if (DEBUG) Log.d(TAG, "Elapsed time: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ return c;
}
private Cursor createSuggestionsCursor(List<SearchResult> results) {
diff --git a/src/com/android/tv/search/TvProviderSearch.java b/src/com/android/tv/search/TvProviderSearch.java
index bd4ae5e5..3804f2de 100644
--- a/src/com/android/tv/search/TvProviderSearch.java
+++ b/src/com/android/tv/search/TvProviderSearch.java
@@ -28,6 +28,7 @@ import android.media.tv.TvContract.WatchedPrograms;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.net.Uri;
+import android.os.SystemClock;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.util.Log;
@@ -54,8 +55,8 @@ import java.util.Set;
* An implementation of {@link SearchInterface} to search query from TvProvider directly.
*/
public class TvProviderSearch implements SearchInterface {
- private static final boolean DEBUG = false;
private static final String TAG = "TvProviderSearch";
+ private static final boolean DEBUG = false;
private static final int NO_LIMIT = 0;
@@ -159,6 +160,8 @@ public class TvProviderSearch implements SearchInterface {
@WorkerThread
private List<SearchResult> searchChannels(String query, Set<Long> channels, int limit) {
+ if (DEBUG) Log.d(TAG, "Searching channels: '" + query + "'");
+ long time = SystemClock.elapsedRealtime();
List<SearchResult> results = new ArrayList<>();
if (TextUtils.isDigitsOnly(query)) {
results.addAll(searchChannels(query, new String[] { Channels.COLUMN_DISPLAY_NUMBER },
@@ -178,6 +181,10 @@ public class TvProviderSearch implements SearchInterface {
for (SearchResult result : results) {
fillProgramInfo(result);
}
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " channels. Elapsed time for searching" +
+ " channels: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return results;
}
@@ -305,6 +312,8 @@ public class TvProviderSearch implements SearchInterface {
@WorkerThread
private List<SearchResult> searchPrograms(String query, String[] columnForExactMatching,
String[] columnForPartialMatching, Set<Long> channelsFound, int limit) {
+ if (DEBUG) Log.d(TAG, "Searching programs: '" + query + "'");
+ long time = SystemClock.elapsedRealtime();
Assert.assertTrue(
(columnForExactMatching != null && columnForExactMatching.length > 0) ||
(columnForPartialMatching != null && columnForPartialMatching.length > 0));
@@ -395,6 +404,10 @@ public class TvProviderSearch implements SearchInterface {
}
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Found " + searchResults.size() + " programs. Elapsed time for searching" +
+ " programs: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return searchResults;
}
@@ -420,9 +433,8 @@ public class TvProviderSearch implements SearchInterface {
}
private List<SearchResult> searchInputs(String query, int limit) {
- if (DEBUG) {
- Log.d(TAG, "searchInputs(" + query + ", limit=" + limit + ")");
- }
+ if (DEBUG) Log.d(TAG, "Searching inputs: '" + query + "'");
+ long time = SystemClock.elapsedRealtime();
query = canonicalizeLabel(query);
List<TvInputInfo> inputList = mTvInputManager.getTvInputList();
@@ -435,6 +447,11 @@ public class TvProviderSearch implements SearchInterface {
if (TextUtils.equals(query, label) || TextUtils.equals(query, customLabel)) {
results.add(buildSearchResultForInput(input.getId()));
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " inputs. Elapsed time for" +
+ " searching inputs: " + (SystemClock.elapsedRealtime() - time) +
+ "(msec)");
+ }
return results;
}
}
@@ -448,10 +465,19 @@ public class TvProviderSearch implements SearchInterface {
(customLabel != null && customLabel.contains(query))) {
results.add(buildSearchResultForInput(input.getId()));
if (results.size() >= limit) {
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " inputs. Elapsed time for" +
+ " searching inputs: " + (SystemClock.elapsedRealtime() - time) +
+ "(msec)");
+ }
return results;
}
}
}
+ if (DEBUG) {
+ Log.d(TAG, "Found " + results.size() + " inputs. Elapsed time for searching" +
+ " inputs: " + (SystemClock.elapsedRealtime() - time) + "(msec)");
+ }
return results;
}
diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java
new file mode 100644
index 00000000..7e627410
--- /dev/null
+++ b/src/com/android/tv/setup/SystemSetupActivity.java
@@ -0,0 +1,124 @@
+/*
+ * 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.setup;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+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.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.TvApplication;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.onboarding.SetupSourcesFragment;
+import com.android.tv.util.OnboardingUtils;
+import com.android.tv.util.SetupUtils;
+import com.android.tv.util.TvInputManagerHelper;
+
+/**
+ * A activity to start input sources setup fragment for initial setup flow.
+ */
+public class SystemSetupActivity extends SetupActivity {
+ private static final String SYSTEM_SETUP =
+ "com.android.tv.action.LAUNCH_SYSTEM_SETUP";
+ private static final int SHOW_RIPPLE_DURATION_MS = 266;
+ private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
+
+ private TvInputManagerHelper mInputManager;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ Intent intent = getIntent();
+ if (!SYSTEM_SETUP.equals(intent.getAction())) {
+ finish();
+ return;
+ }
+ ApplicationSingletons singletons = TvApplication.getSingletons(this);
+ mInputManager = singletons.getTvInputManagerHelper();
+ }
+
+ @Override
+ protected Fragment onCreateInitialFragment() {
+ return new SetupSourcesFragment();
+ }
+
+ private void showMerchantCollection() {
+ executeActionWithDelay(new Runnable() {
+ @Override
+ public void run() {
+ startActivity(OnboardingUtils.ONLINE_STORE_INTENT);
+ }
+ }, SHOW_RIPPLE_DURATION_MS);
+ }
+
+ @Override
+ public boolean executeAction(String category, int actionId, Bundle params) {
+ switch (category) {
+ case SetupSourcesFragment.ACTION_CATEGORY:
+ switch (actionId) {
+ case SetupSourcesFragment.ACTION_ONLINE_STORE:
+ showMerchantCollection();
+ return true;
+ case SetupSourcesFragment.ACTION_SETUP_INPUT: {
+ String inputId = params.getString(
+ SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
+ TvInputInfo input = mInputManager.getTvInputInfo(inputId);
+ Intent intent = TvCommonUtils.createSetupIntent(input);
+ if (intent == null) {
+ Toast.makeText(this, R.string.msg_no_setup_activity, Toast.LENGTH_SHORT)
+ .show();
+ return true;
+ }
+ // Even though other app can handle the intent, the setup launched by Live
+ // channels should go through Live channels SetupPassthroughActivity.
+ intent.setComponent(new ComponentName(this,
+ SetupPassthroughActivity.class));
+ try {
+ // Now we know that the user intends to set up this input. Grant
+ // permission for writing EPG data.
+ SetupUtils.grantEpgPermission(this, input.getServiceInfo().packageName);
+ startActivityForResult(intent, REQUEST_CODE_START_SETUP_ACTIVITY);
+ } catch (ActivityNotFoundException e) {
+ Toast.makeText(this,
+ getString(R.string.msg_unable_to_start_setup_activity,
+ input.loadLabel(this)), Toast.LENGTH_SHORT).show();
+ }
+ return true;
+ }
+ case SetupMultiPaneFragment.ACTION_DONE: {
+ // To make sure user can finish setup flow, set result as RESULT_OK.
+ setResult(Activity.RESULT_OK);
+ finish();
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/ChannelScanFileParser.java b/src/com/android/tv/tuner/ChannelScanFileParser.java
index ef9d8425..8b06aaa9 100644
--- a/usbtuner/src/com/android/usbtuner/ChannelScanFileParser.java
+++ b/src/com/android/tv/tuner/ChannelScanFileParser.java
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
import android.util.Log;
-import com.android.usbtuner.data.Channel;
+import com.android.tv.tuner.data.Channel;
import java.io.BufferedReader;
import java.io.IOException;
@@ -38,20 +38,30 @@ public class ChannelScanFileParser {
public final int frequency;
public final String modulation;
public final String filename;
+ /**
+ * Radio frequency (channel) number specified at
+ * https://en.wikipedia.org/wiki/North_American_television_frequencies
+ * This can be {@code null} for cases like cable signal.
+ */
+ public final Integer radioFrequencyNumber;
- public static ScanChannel forTuner(int frequency, String modulation) {
- return new ScanChannel(Channel.TYPE_TUNER, frequency, modulation, null);
+ public static ScanChannel forTuner(int frequency, String modulation,
+ Integer radioFrequencyNumber) {
+ return new ScanChannel(Channel.TYPE_TUNER, frequency, modulation, null,
+ radioFrequencyNumber);
}
public static ScanChannel forFile(int frequency, String filename) {
- return new ScanChannel(Channel.TYPE_FILE, frequency, "file:", filename);
+ return new ScanChannel(Channel.TYPE_FILE, frequency, "file:", filename, null);
}
- private ScanChannel(int type, int frequency, String modulation, String filename) {
+ private ScanChannel(int type, int frequency, String modulation, String filename,
+ Integer radioFrequencyNumber) {
this.type = type;
this.frequency = frequency;
this.modulation = modulation;
this.filename = filename;
+ this.radioFrequencyNumber = radioFrequencyNumber;
}
}
@@ -77,14 +87,15 @@ public class ChannelScanFileParser {
continue;
}
String[] tokens = line.split("\\s+");
- if (tokens.length != 3) {
+ if (tokens.length != 3 && tokens.length != 4) {
continue;
}
if (!tokens[0].equals("A")) {
// Only support ATSC
continue;
}
- scanChannelList.add(ScanChannel.forTuner(Integer.parseInt(tokens[1]), tokens[2]));
+ scanChannelList.add(ScanChannel.forTuner(Integer.parseInt(tokens[1]), tokens[2],
+ tokens.length == 4 ? Integer.parseInt(tokens[3]) : null));
}
} catch (IOException e) {
Log.e(TAG, "error on parseScanFile()", e);
diff --git a/usbtuner/src/com/android/usbtuner/DvbDeviceAccessor.java b/src/com/android/tv/tuner/DvbDeviceAccessor.java
index b1cdcfe0..4f5d8ee4 100644
--- a/usbtuner/src/com/android/usbtuner/DvbDeviceAccessor.java
+++ b/src/com/android/tv/tuner/DvbDeviceAccessor.java
@@ -14,25 +14,17 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
-import android.annotation.TargetApi;
-import android.content.ComponentName;
import android.content.Context;
-import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
-import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v4.os.BuildCompat;
import android.util.Log;
-import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.common.recording.RecordingCapability;
-import com.android.usbtuner.tvinput.UsbTunerTvInputService;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -41,6 +33,7 @@ import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
/**
* Provides with the file descriptors to access DVB device.
@@ -77,7 +70,7 @@ public class DvbDeviceAccessor {
}
public DvbDeviceAccessor(Context context) {
- mTvInputManager = (TvInputManager) context.getSystemService(context.TV_INPUT_SERVICE);
+ mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
}
public List<DvbDeviceInfoWrapper> getDvbDeviceList() {
@@ -97,6 +90,14 @@ public class DvbDeviceAccessor {
return null;
}
+ /**
+ * Returns the number of currently connected DVB devices.
+ */
+ public int getNumOfDvbDevices() {
+ List<DvbDeviceInfoWrapper> dvbDeviceList = getDvbDeviceList();
+ return dvbDeviceList == null ? 0 : dvbDeviceList.size();
+ }
+
public boolean isDvbDeviceAvailable() {
try {
List dvbDeviceInfoList = (List) sGetDvbDeviceListMethod.invoke(mTvInputManager);
@@ -137,22 +138,6 @@ public class DvbDeviceAccessor {
.build();
}
- @Nullable
- @TargetApi(Build.VERSION_CODES.N)
- public TvInputInfo buildTvInputInfo(Context context) {
- List<DvbDeviceInfoWrapper> deviceList = getDvbDeviceList();
- TvInputInfo.Builder builder = new TvInputInfo.Builder(context, new ComponentName(context,
- UsbTunerTvInputService.class));
- if (deviceList.size() > 0) {
- return builder.setCanRecord(
- CommonFeatures.DVR.isEnabled(context) && BuildCompat.isAtLeastN())
- .setTunerCount(deviceList.size())
- .build();
- } else {
- return null;
- }
- }
-
public static class DvbDeviceInfoWrapper implements Comparable<DvbDeviceInfoWrapper> {
private static Method sGetAdapterIdMethod;
private static Method sGetDeviceIdMethod;
@@ -230,7 +215,8 @@ public class DvbDeviceAccessor {
@Override
public String toString() {
- return String.format("DvbDeviceInfo {adapterId: %d, deviceId: %d}", getAdapterId(),
+ return String.format(Locale.US, "DvbDeviceInfo {adapterId: %d, deviceId: %d}",
+ getAdapterId(),
getDeviceId());
}
}
diff --git a/usbtuner/src/com/android/usbtuner/TunerHal.java b/src/com/android/tv/tuner/TunerHal.java
index fc04b2da..de19766e 100644
--- a/usbtuner/src/com/android/usbtuner/TunerHal.java
+++ b/src/com/android/tv/tuner/TunerHal.java
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
import android.content.Context;
import android.support.annotation.IntDef;
import android.support.annotation.StringDef;
import android.util.Log;
-import com.android.usbtuner.util.TisConfiguration;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
@@ -48,6 +46,9 @@ public abstract class TunerHal implements AutoCloseable {
public static final String MODULATION_8VSB = "8VSB";
public static final String MODULATION_QAM256 = "QAM256";
+ public static final int TUNER_TYPE_BUILT_IN = 1;
+ public static final int TUNER_TYPE_USB = 2;
+
protected static final int PID_PAT = 0;
protected static final int PID_ATSC_SI_BASE = 0x1ffb;
protected static final int DEFAULT_VSB_TUNE_TIMEOUT_MS = 2000;
@@ -66,12 +67,12 @@ public abstract class TunerHal implements AutoCloseable {
* @param context context for creating the TunerHal instance
* @return the TunerHal instance
*/
- public static TunerHal createInstance(Context context) {
- TunerHal tunerHal;
- if (TisConfiguration.isPackagedWithLiveChannels(context)) {
+ public synchronized static TunerHal createInstance(Context context) {
+ TunerHal tunerHal = null;
+ if (getTunerType(context) == TUNER_TYPE_BUILT_IN) {
+ }
+ if (tunerHal == null) {
tunerHal = new UsbTunerHal(context);
- } else {
- tunerHal = new InternalTunerHal(context);
}
if (tunerHal.openFirstAvailable()) {
return tunerHal;
@@ -79,6 +80,22 @@ public abstract class TunerHal implements AutoCloseable {
return null;
}
+ /**
+ * Gets the number of tuner devices currently present.
+ */
+ public static int getTunerCount(Context context) {
+ if (getTunerType(context) == TUNER_TYPE_BUILT_IN) {
+ }
+ return UsbTunerHal.getNumberOfDevices(context);
+ }
+
+ /**
+ * Gets the type of tuner devices currently used.
+ */
+ public static int getTunerType(Context context) {
+ return TUNER_TYPE_USB;
+ }
+
protected TunerHal(Context context) {
mIsStreaming = false;
mFrequency = -1;
@@ -116,7 +133,7 @@ public abstract class TunerHal implements AutoCloseable {
* @param modulation a modulation method of the channel to tune to
* @return {@code true} if the operation was successful, {@code false} otherwise
*/
- public boolean tune(int frequency, @ModulationType String modulation) {
+ public synchronized boolean tune(int frequency, @ModulationType String modulation) {
if (!isDeviceOpen()) {
Log.e(TAG, "There's no available device");
return false;
@@ -157,7 +174,7 @@ public abstract class TunerHal implements AutoCloseable {
* @param filterType a type of pid. Must be one of (FILTER_TYPE_XXX)
* @return {@code true} if the operation was successful, {@code false} otherwise
*/
- public boolean addPidFilter(int pid, @FilterType int filterType) {
+ public synchronized boolean addPidFilter(int pid, @FilterType int filterType) {
if (!isDeviceOpen()) {
Log.e(TAG, "There's no available device");
return false;
@@ -171,12 +188,13 @@ public abstract class TunerHal implements AutoCloseable {
protected native void nativeAddPidFilter(long deviceId, int pid, @FilterType int filterType);
protected native void nativeCloseAllPidFilters(long deviceId);
+ protected native void nativeSetHasPendingTune(long deviceId, boolean hasPendingTune);
/**
* Stops current tuning. The tuner device and pid filters will be reset by this call and make
* the tuner ready to accept another tune request.
*/
- public void stopTune() {
+ public synchronized void stopTune() {
if (isDeviceOpen()) {
if (mIsStreaming) {
nativeCloseAllPidFilters(getDeviceId());
@@ -188,11 +206,15 @@ public abstract class TunerHal implements AutoCloseable {
mModulation = null;
}
+ public void setHasPendingTune(boolean hasPendingTune) {
+ nativeSetHasPendingTune(getDeviceId(), hasPendingTune);
+ }
+
protected native void nativeStopTune(long deviceId);
/**
* This method must be called after {@link TunerHal#tune} and before
- * {@link TunerHal#stopStreaming}. Writes at most maxSize TS frames in a buffer
+ * {@link TunerHal#stopTune}. Writes at most maxSize TS frames in a buffer
* provided by the user. The frames employ MPEG encoding.
*
* @param javaBuffer a buffer to write the video data in
@@ -201,7 +223,7 @@ public abstract class TunerHal implements AutoCloseable {
* @return the amount of bytes written in the buffer. Note that this value could be 0 if no new
* frames have been obtained since the last call.
*/
- public int readTsStream(byte[] javaBuffer, int javaBufferSize) {
+ public synchronized int readTsStream(byte[] javaBuffer, int javaBufferSize) {
if (isDeviceOpen()) {
return nativeWriteInBuffer(getDeviceId(), javaBuffer, javaBufferSize);
} else {
diff --git a/src/com/android/usbtuner/UsbInputController.java b/src/com/android/tv/tuner/TunerInputController.java
index f0982eb5..d89b6a0c 100644
--- a/src/com/android/usbtuner/UsbInputController.java
+++ b/src/com/android/tv/tuner/TunerInputController.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -25,39 +25,38 @@ import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
-import android.media.tv.TvInputService;
-import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.support.v4.os.BuildCompat;
import android.util.Log;
+import android.widget.Toast;
import com.android.tv.Features;
import com.android.tv.TvApplication;
-import com.android.usbtuner.setup.TunerSetupActivity;
-import com.android.usbtuner.tvinput.UsbTunerTvInputService;
+import com.android.tv.tuner.R;
+import com.android.tv.tuner.setup.TunerSetupActivity;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
+import com.android.tv.tuner.util.TunerInputInfoUtils;
import java.util.Map;
/**
- * Controls the package visibility of {@link UsbTunerTvInputService}.
+ * 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 UsbInputController extends BroadcastReceiver {
+public class TunerInputController extends BroadcastReceiver {
private static final boolean DEBUG = true;
- private static final String TAG = "UsbInputController";
+ private static final String TAG = "TunerInputController";
private static final TunerDevice[] TUNER_DEVICES = {
new TunerDevice(0x2040, 0xb123), // WinTV-HVR-955Q
new TunerDevice(0x07ca, 0x0837) // AverTV Volar Hybrid Q
};
- private static final boolean IS_MNC_OR_LATER = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
-
private static final int MSG_ENABLE_INPUT_SERVICE = 1000;
private static final long DVB_DRIVER_CHECK_DELAY_MS = 300;
@@ -71,8 +70,7 @@ public class UsbInputController extends BroadcastReceiver {
if (mDvbDeviceAccessor == null) {
mDvbDeviceAccessor = new DvbDeviceAccessor(context);
}
- enableUsbTunerTvInputService(context,
- mDvbDeviceAccessor.isDvbDeviceAvailable());
+ enableTunerTvInputService(context, mDvbDeviceAccessor.isDvbDeviceAvailable());
break;
}
}
@@ -99,18 +97,23 @@ public class UsbInputController extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "Broadcast intent received:" + intent);
-
- if (!Features.USB_TUNER.isEnabled(context)) {
- enableUsbTunerTvInputService(context, false);
+ TvApplication.setCurrentRunningProcess(context, true);
+ if (!Features.TUNER.isEnabled(context)) {
+ enableTunerTvInputService(context, false);
return;
}
switch (intent.getAction()) {
case Intent.ACTION_BOOT_COMPLETED:
+ case TvApplication.ACTION_APPLICATION_FIRST_LAUNCHED:
case UsbManager.ACTION_USB_DEVICE_ATTACHED:
case UsbManager.ACTION_USB_DEVICE_DETACHED:
- // Tuner is supported on MNC and later version only.
- boolean enabled = IS_MNC_OR_LATER && isTunerConnected(context);
+ if (TunerInputInfoUtils.isBuiltInTuner(context)) {
+ enableTunerTvInputService(context, true);
+ break;
+ }
+ // Falls back to the below to check USB tuner devices.
+ boolean enabled = isUsbTunerConnected(context);
mHandler.removeMessages(MSG_ENABLE_INPUT_SERVICE);
if (enabled) {
// Need to check if DVB driver is accessible. Since the driver creation
@@ -120,7 +123,7 @@ public class UsbInputController extends BroadcastReceiver {
mHandler.obtainMessage(MSG_ENABLE_INPUT_SERVICE, context),
DVB_DRIVER_CHECK_DELAY_MS);
} else {
- enableUsbTunerTvInputService(context, false);
+ enableTunerTvInputService(context, false);
}
break;
}
@@ -132,7 +135,7 @@ public class UsbInputController extends BroadcastReceiver {
* @param context {@link Context} instance
* @return {@code true} if any tuner device we support is plugged in
*/
- private boolean isTunerConnected(Context context) {
+ private boolean isUsbTunerConnected(Context context) {
UsbManager manager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
Map<String, UsbDevice> deviceList = manager.getDeviceList();
for (UsbDevice device : deviceList.values()) {
@@ -150,14 +153,15 @@ public class UsbInputController extends BroadcastReceiver {
}
/**
- * Enable/disable the component {@link UsbTunerTvInputService}.
+ * Enable/disable the component {@link TunerTvInputService}.
*
* @param context {@link Context} instance
* @param enabled {@code true} to enable the service; otherwise {@code false}
*/
- private void enableUsbTunerTvInputService(Context context, boolean enabled) {
+ private void enableTunerTvInputService(Context context, boolean enabled) {
+ if (DEBUG) Log.d(TAG, "enableTunerTvInputService: " + enabled);
PackageManager pm = context.getPackageManager();
- ComponentName USBTUNER = new ComponentName(context, UsbTunerTvInputService.class);
+ 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.
@@ -170,20 +174,19 @@ public class UsbInputController extends BroadcastReceiver {
? PackageManager.DONT_KILL_APP : 0;
int newState = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
: PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- if (newState != pm.getComponentEnabledSetting(USBTUNER)) {
+ if (newState != pm.getComponentEnabledSetting(componentName)) {
// Send/cancel the USB tuner TV input setup recommendation card.
TunerSetupActivity.onTvInputEnabled(context, enabled);
// Enable/disable the USB tuner TV input.
- pm.setComponentEnabledSetting(USBTUNER, newState, flags);
- if (DEBUG) Log.d(TAG, "Status updated:" + enabled);
- }
- if (enabled && BuildCompat.isAtLeastN()) {
- TvInputInfo info = mDvbDeviceAccessor.buildTvInputInfo(context);
- if (info != null) {
- Log.i(TAG, "TvInputInfo updated: " + info.toString());
- ((TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE))
- .updateTvInputInfo(info);
+ pm.setComponentEnabledSetting(componentName, newState, flags);
+ if (!enabled) {
+ Toast.makeText(
+ context, R.string.msg_usb_device_detached, Toast.LENGTH_SHORT).show();
}
+ if (DEBUG) Log.d(TAG, "Status updated:" + enabled);
+ } else if (enabled) {
+ // When # of USB tuners is changed or the device just boots.
+ TunerInputInfoUtils.updateTunerInputInfo(context);
}
}
}
diff --git a/usbtuner/src/com/android/usbtuner/UsbTunerPreferenceProvider.java b/src/com/android/tv/tuner/TunerPreferenceProvider.java
index 1697e363..3a3561b6 100644
--- a/usbtuner/src/com/android/usbtuner/UsbTunerPreferenceProvider.java
+++ b/src/com/android/tv/tuner/TunerPreferenceProvider.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
import android.content.ContentProvider;
import android.content.ContentValues;
@@ -29,22 +29,20 @@ import android.net.Uri;
/**
* A content provider for storing the preferences. It's used across TV app and USB tuner TV input.
*/
-public class UsbTunerPreferenceProvider extends ContentProvider {
+public class TunerPreferenceProvider extends ContentProvider {
/** The authority of the provider */
- public static final String AUTHORITY = "com.android.usbtuner.preferences";
+ public static final String AUTHORITY = "com.android.tv.tuner.preferences";
private static final String PATH_PREFERENCES = "preferences";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "usbtuner_preferences.db";
private static final String PREFERENCES_TABLE = "preferences";
- private static final String PREFERENCES_TABLE_ID_INDEX = "preferences_id_index";
- private static final String PREFERENCES_TABLE_KEY_INDEX = "preferences_key_index";
private static final int MATCH_PREFERENCE = 1;
private static final int MATCH_PREFERENCE_KEY = 2;
- private static UriMatcher sUriMatcher;
+ private static final UriMatcher sUriMatcher;
private DatabaseOpenHelper mDatabaseOpenHelper;
@@ -119,13 +117,7 @@ public class UsbTunerPreferenceProvider extends ContentProvider {
db.execSQL("CREATE TABLE " + PREFERENCES_TABLE + " ("
+ Preferences._ID + " INTEGER PRIMARY KEY AUTOINCREMENT,"
+ Preferences.COLUMN_KEY + " TEXT NOT NULL,"
- + Preferences.COLUMN_VALUE + " TEXT,"
- + "UNIQUE(" + Preferences._ID + "," + Preferences.COLUMN_KEY + ")"
- + ");");
- db.execSQL("CREATE INDEX " + PREFERENCES_TABLE_ID_INDEX + " ON " + PREFERENCES_TABLE
- + "(" + Preferences.COLUMN_KEY + ");");
- db.execSQL("CREATE INDEX " + PREFERENCES_TABLE_KEY_INDEX + " ON " + PREFERENCES_TABLE
- + "(" + Preferences.COLUMN_KEY + ");");
+ + Preferences.COLUMN_VALUE + " TEXT);");
}
@Override
@@ -143,7 +135,8 @@ public class UsbTunerPreferenceProvider extends ContentProvider {
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
- if (sUriMatcher.match(uri) != MATCH_PREFERENCE_KEY) {
+ int match = sUriMatcher.match(uri);
+ if (match != MATCH_PREFERENCE && match != MATCH_PREFERENCE_KEY) {
throw new UnsupportedOperationException();
}
SQLiteDatabase db = mDatabaseOpenHelper.getReadableDatabase();
diff --git a/src/com/android/tv/tuner/TunerPreferences.java b/src/com/android/tv/tuner/TunerPreferences.java
new file mode 100644
index 00000000..1547e3ae
--- /dev/null
+++ b/src/com/android/tv/tuner/TunerPreferences.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.tuner;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.database.ContentObserver;
+import android.database.Cursor;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.MainThread;
+
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.TunerPreferenceProvider.Preferences;
+import com.android.tv.tuner.util.TisConfiguration;
+
+/**
+ * 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_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 SHARED_PREFS_NAME = "com.android.tv.tuner.preferences";
+
+ public static final int CHANNEL_DATA_VERSION_NOT_SET = -1;
+
+ private static final Bundle sPreferenceValues = new Bundle();
+ private static LoadPreferencesTask sLoadPreferencesTask;
+ private static ContentObserver sContentObserver;
+
+ private static boolean sInitialized;
+
+ /**
+ * Initializes the USB tuner preferences.
+ */
+ @MainThread
+ public static void initialize(final Context context) {
+ if (sInitialized) {
+ return;
+ }
+ sInitialized = true;
+ if (useContentProvider(context)) {
+ loadPreferences(context);
+ sContentObserver = new ContentObserver(new Handler()) {
+ @Override
+ public void onChange(boolean selfChange) {
+ loadPreferences(context);
+ }
+ };
+ context.getContentResolver().registerContentObserver(
+ TunerPreferenceProvider.Preferences.CONTENT_URI, true, sContentObserver);
+ } else {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ getSharedPreferences(context);
+ return null;
+ }
+ }.execute();
+ }
+ }
+
+ /**
+ * Releases the resources.
+ */
+ @MainThread
+ public static void release(Context context) {
+ if (useContentProvider(context) && sContentObserver != null) {
+ context.getContentResolver().unregisterContentObserver(sContentObserver);
+ }
+ }
+
+ /**
+ * Loads the preferences from database.
+ * <p>
+ * This preferences is used across processes, so the preferences should be loaded again when the
+ * databases changes.
+ */
+ public static synchronized void loadPreferences(Context context) {
+ if (sLoadPreferencesTask != null
+ && sLoadPreferencesTask.getStatus() != AsyncTask.Status.FINISHED) {
+ sLoadPreferencesTask.cancel(true);
+ }
+ sLoadPreferencesTask = new LoadPreferencesTask(context);
+ sLoadPreferencesTask.execute();
+ }
+
+ private static boolean useContentProvider(Context context) {
+ // If TIS is a part of LC, it should use ContentProvider to resolve multiple process access.
+ return TisConfiguration.isPackagedWithLiveChannels(context);
+ }
+
+ @MainThread
+ public static 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);
+ }
+ }
+
+ @MainThread
+ public static 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();
+ }
+ }
+
+ @MainThread
+ public static 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);
+ }
+ }
+
+ @MainThread
+ public static 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();
+ }
+ }
+
+ @MainThread
+ public static 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);
+ }
+ }
+
+ @MainThread
+ public static 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();
+ }
+ }
+
+ @MainThread
+ public static boolean shouldShowSetupActivity(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getBoolean(PREFS_KEY_LAUNCH_SETUP);
+ } else {
+ return getSharedPreferences(context)
+ .getBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, false);
+ }
+ }
+
+ @MainThread
+ public static void setShouldShowSetupActivity(Context context, boolean need) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_LAUNCH_SETUP, need);
+ } else {
+ getSharedPreferences(context).edit()
+ .putBoolean(TunerPreferences.PREFS_KEY_LAUNCH_SETUP, need)
+ .apply();
+ }
+ }
+
+ @MainThread
+ public static boolean getStoreTsStream(Context context) {
+ SoftPreconditions.checkState(sInitialized);
+ if (useContentProvider(context)) {
+ return sPreferenceValues.getBoolean(PREFS_KEY_STORE_TS_STREAM, false);
+ } else {
+ return getSharedPreferences(context)
+ .getBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, false);
+ }
+ }
+
+ @MainThread
+ public static void setStoreTsStream(Context context, boolean shouldStore) {
+ if (useContentProvider(context)) {
+ setPreference(context, PREFS_KEY_STORE_TS_STREAM, shouldStore);
+ } else {
+ getSharedPreferences(context).edit()
+ .putBoolean(TunerPreferences.PREFS_KEY_STORE_TS_STREAM, shouldStore)
+ .apply();
+ }
+ }
+
+ private static SharedPreferences getSharedPreferences(Context context) {
+ return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
+ }
+
+ @MainThread
+ private static void setPreference(final Context context, final String key, final String value) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ ContentResolver resolver = context.getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put(Preferences.COLUMN_KEY, key);
+ values.put(Preferences.COLUMN_VALUE, value);
+ try {
+ resolver.insert(Preferences.CONTENT_URI, values);
+ } catch (Exception e) {
+ SoftPreconditions.warn(TAG, "setPreference", "Error writing preference values",
+ e);
+ }
+ return null;
+ }
+ }.execute();
+ }
+
+ @MainThread
+ private static void setPreference(Context context, String key, int value) {
+ sPreferenceValues.putInt(key, value);
+ setPreference(context, key, Integer.toString(value));
+ }
+
+ @MainThread
+ private static void setPreference(Context context, String key, boolean value) {
+ sPreferenceValues.putBoolean(key, value);
+ setPreference(context, key, Boolean.toString(value));
+ }
+
+ private static class LoadPreferencesTask extends AsyncTask<Void, Void, Bundle> {
+ private final Context mContext;
+ private LoadPreferencesTask(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ protected Bundle doInBackground(Void... params) {
+ Bundle bundle = new Bundle();
+ ContentResolver resolver = mContext.getContentResolver();
+ String[] projection = new String[] { Preferences.COLUMN_KEY, Preferences.COLUMN_VALUE };
+ try (Cursor cursor = resolver.query(Preferences.CONTENT_URI, projection, null, null,
+ null)) {
+ if (cursor != null) {
+ while (!isCancelled() && cursor.moveToNext()) {
+ String key = cursor.getString(0);
+ String value = cursor.getString(1);
+ switch (key) {
+ case PREFS_KEY_CHANNEL_DATA_VERSION:
+ case PREFS_KEY_SCANNED_CHANNEL_COUNT:
+ 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;
+ }
+ }
+ }
+ } catch (Exception e) {
+ SoftPreconditions.warn(TAG, "getPreference", "Error querying preference values", e);
+ return null;
+ }
+ return bundle;
+ }
+
+ @Override
+ protected void onPostExecute(Bundle bundle) {
+ sPreferenceValues.putAll(bundle);
+ }
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/UsbTunerHal.java b/src/com/android/tv/tuner/UsbTunerHal.java
index 28ab4ef5..22e35ea1 100644
--- a/usbtuner/src/com/android/usbtuner/UsbTunerHal.java
+++ b/src/com/android/tv/tuner/UsbTunerHal.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner;
import android.content.Context;
import android.os.ParcelFileDescriptor;
-import android.support.annotation.IntDef;
import android.util.Log;
-import com.android.usbtuner.DvbDeviceAccessor.DvbDeviceInfoWrapper;
+import com.android.tv.tuner.DvbDeviceAccessor.DvbDeviceInfoWrapper;
import java.util.List;
import java.util.SortedSet;
@@ -165,4 +164,11 @@ public class UsbTunerHal extends TunerHal {
}
return -1;
}
+
+ /**
+ * Gets the number of USB tuner devices currently present.
+ */
+ public static int getNumberOfDevices(Context context) {
+ return (new DvbDeviceAccessor(context)).getNumOfDvbDevices();
+ }
}
diff --git a/usbtuner/src/com/android/usbtuner/cc/CaptionLayout.java b/src/com/android/tv/tuner/cc/CaptionLayout.java
index 856819a4..c41f1014 100644
--- a/usbtuner/src/com/android/usbtuner/cc/CaptionLayout.java
+++ b/src/com/android/tv/tuner/cc/CaptionLayout.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package com.android.usbtuner.cc;
+package com.android.tv.tuner.cc;
import android.content.Context;
import android.util.AttributeSet;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.layout.ScaledLayout;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.layout.ScaledLayout;
/**
* Layout containing the safe title area that helps the closed captions look more prominent.
diff --git a/usbtuner/src/com/android/usbtuner/cc/CaptionTrackRenderer.java b/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
index 413405f0..3aa40982 100644
--- a/usbtuner/src/com/android/usbtuner/cc/CaptionTrackRenderer.java
+++ b/src/com/android/tv/tuner/cc/CaptionTrackRenderer.java
@@ -14,20 +14,20 @@
* limitations under the License.
*/
-package com.android.usbtuner.cc;
+package com.android.tv.tuner.cc;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
-import com.android.usbtuner.data.Cea708Data.CaptionEvent;
-import com.android.usbtuner.data.Cea708Data.CaptionPenAttr;
-import com.android.usbtuner.data.Cea708Data.CaptionPenColor;
-import com.android.usbtuner.data.Cea708Data.CaptionPenLocation;
-import com.android.usbtuner.data.Cea708Data.CaptionWindow;
-import com.android.usbtuner.data.Cea708Data.CaptionWindowAttr;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenAttr;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenColor;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenLocation;
+import com.android.tv.tuner.data.Cea708Data.CaptionWindow;
+import com.android.tv.tuner.data.Cea708Data.CaptionWindowAttr;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
diff --git a/usbtuner/src/com/android/usbtuner/cc/CaptionWindowLayout.java b/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
index 26b92493..6f42b506 100644
--- a/usbtuner/src/com/android/usbtuner/cc/CaptionWindowLayout.java
+++ b/src/com/android/tv/tuner/cc/CaptionWindowLayout.java
@@ -14,10 +14,11 @@
* limitations under the License.
*/
-package com.android.usbtuner.cc;
+package com.android.tv.tuner.cc;
import android.content.Context;
import android.graphics.Paint;
+import android.graphics.Rect;
import android.graphics.Typeface;
import android.text.Layout.Alignment;
import android.text.SpannableStringBuilder;
@@ -41,11 +42,11 @@ import android.widget.RelativeLayout;
import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.text.SubtitleView;
-import com.android.usbtuner.data.Cea708Data.CaptionPenAttr;
-import com.android.usbtuner.data.Cea708Data.CaptionPenColor;
-import com.android.usbtuner.data.Cea708Data.CaptionWindow;
-import com.android.usbtuner.data.Cea708Data.CaptionWindowAttr;
-import com.android.usbtuner.layout.ScaledLayout;
+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.layout.ScaledLayout;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@@ -83,6 +84,7 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
private static final int US_MAX_COLUMN_COUNT_4_3 = 32;
private static final int KR_MAX_COLUMN_COUNT_16_9 = 52;
private static final int KR_MAX_COLUMN_COUNT_4_3 = 40;
+ private static final int MAX_ROW_COUNT = 15;
private static final String KOR_ALPHABET =
new String("\uAC00".getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
@@ -97,12 +99,14 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
private final SpannableStringBuilder mBuilder = new SpannableStringBuilder();
private final List<CharacterStyle> mCharacterStyles = new ArrayList<>();
private int mCaptionWindowId;
- private int mRow = -1;
+ private int mCurrentTextRow = -1;
private float mFontScale;
private float mTextSize;
private String mWidestChar;
private int mLastCaptionLayoutWidth;
private int mLastCaptionLayoutHeight;
+ private int mWindowJustify;
+ private int mPrintDirection;
private class SystemWideCaptioningChangeListener extends CaptioningChangeListener {
@Override
@@ -202,17 +206,29 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
}
public void setPenLocation(int row, int column) {
- // TODO: change the location of pen based on row and column both.
- if (mRow >= 0) {
- for (int r = mRow; r < row; ++r) {
- appendText("\n");
+ // TODO: change the location of pen when window's justify isn't left.
+ // According to the CEA708B spec 8.7, setPenLocation means set the pen cursor within
+ // window's text buffer. When row > mCurrentTextRow, we add "\n" to make the cursor locate
+ // at row. Adding white space to make cursor locate at column.
+ if (mWindowJustify == CaptionWindowAttr.JUSTIFY_LEFT) {
+ if (mCurrentTextRow >= 0) {
+ for (int r = mCurrentTextRow; r < row; ++r) {
+ appendText("\n");
+ }
+ if (mCurrentTextRow <= row) {
+ for (int i = 0; i < column; ++i) {
+ appendText(" ");
+ }
+ }
}
}
- mRow = row;
+ mCurrentTextRow = row;
}
public void setWindowAttr(CaptionWindowAttr windowAttr) {
// TODO: apply window attrs or skip this and use the style of system wide cc style as is.
+ mWindowJustify = windowAttr.justify;
+ mPrintDirection = windowAttr.printDirection;
}
public void sendBuffer(String buffer) {
@@ -392,6 +408,10 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
setCaptionWindowId(captionWindow.id);
setRowLimit(captionWindow.rowCount);
setGravity(gravity);
+ setWindowStyle(captionWindow.windowStyle);
+ if (mWindowJustify == CaptionWindowAttr.JUSTIFY_CENTER) {
+ mSubtitleView.setTextAlignment(Alignment.ALIGN_CENTER);
+ }
if (captionWindow.visible) {
show();
} else {
@@ -456,24 +476,34 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
paint.setTypeface(mCaptionStyleCompat.typeface);
float startFontSize = 0f;
float endFontSize = 255f;
+ Rect boundRect = new Rect();
while (startFontSize < endFontSize) {
float testTextSize = (startFontSize + endFontSize) / 2f;
paint.setTextSize(testTextSize);
float width = paint.measureText(widestText);
- if (mCaptionLayout.getWidth() * 0.8f > width) {
+ paint.getTextBounds(widestText, 0, widestText.length(), boundRect);
+ float height = boundRect.height() + width - boundRect.width();
+ // According to CEA-708B Section 9.13, the height of standard font size shouldn't taller
+ // than 1/15 of the height of the safe-title area, and the width shouldn't wider than
+ // 1/{@code getScreenColumnCount()} of the width of the safe-title area.
+ if (mCaptionLayout.getWidth() * 0.8f > width
+ && mCaptionLayout.getHeight() * 0.8f / MAX_ROW_COUNT > height) {
startFontSize = testTextSize + 0.01f;
} else {
endFontSize = testTextSize - 0.01f;
}
}
mTextSize = endFontSize * mFontScale;
+ paint.setTextSize(mTextSize);
+ float whiteSpaceWidth = paint.measureText(" ");
+ mSubtitleView.setWhiteSpaceWidth(whiteSpaceWidth);
mSubtitleView.setTextSize(mTextSize);
}
private int getScreenColumnCount() {
float screenAspectRatio = (float) mCaptionLayout.getWidth() / mCaptionLayout.getHeight();
boolean isWideAspectRationScreen = screenAspectRatio > WIDE_SCREEN_ASPECT_RATIO_THRESHOLD;
- if (isKoreanLanguageTrack()) {
+ if (isKoreanLanguageTrack()) {
// Each korean character consumes two slots.
if (isWideAspectRationScreen || isWideAspectRatio()) {
return KR_MAX_COLUMN_COUNT_16_9 / 2;
@@ -526,9 +556,11 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
// Truncate text not to exceed the row limit.
// Plus one here since the range of the rows is [0, mRowLimit].
+ int startRow = Math.max(0, lines.length - (mRowLimit + 1));
String truncatedText = TextUtils.join("\n", Arrays.copyOfRange(
- lines, Math.max(0, lines.length - (mRowLimit + 1)), lines.length));
+ lines, startRow, lines.length));
mBuilder.delete(0, mBuilder.length() - truncatedText.length());
+ mCurrentTextRow = lines.length - startRow - 1;
// Trim the buffer first then set text to {@link SubtitleView}.
int start = 0, last = mBuilder.length() - 1;
@@ -536,10 +568,14 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
while ((start <= end) && (mBuilder.charAt(start) <= ' ')) {
++start;
}
+ while (start - 1 >= 0 && start <= end && mBuilder.charAt(start - 1) != '\n') {
+ --start;
+ }
while ((end >= start) && (mBuilder.charAt(end) <= ' ')) {
--end;
}
if (start == 0 && end == last) {
+ mSubtitleView.setPrefixSpaces(getPrefixSpaces(mBuilder));
mSubtitleView.setText(mBuilder);
} else {
SpannableStringBuilder trim = new SpannableStringBuilder();
@@ -550,14 +586,65 @@ public class CaptionWindowLayout extends RelativeLayout implements View.OnLayout
if (start > 0) {
trim.delete(0, start);
}
+ mSubtitleView.setPrefixSpaces(getPrefixSpaces(trim));
mSubtitleView.setText(trim);
}
}
+ private static ArrayList<Integer> getPrefixSpaces(SpannableStringBuilder builder) {
+ ArrayList<Integer> prefixSpaces = new ArrayList<>();
+ String[] lines = TextUtils.split(builder.toString(), "\n");
+ for (String line : lines) {
+ int start = 0;
+ while (start < line.length() && line.charAt(start) <= ' ') {
+ start++;
+ }
+ prefixSpaces.add(start);
+ }
+ return prefixSpaces;
+ }
+
public void setRowLimit(int rowLimit) {
if (rowLimit < 0) {
throw new IllegalArgumentException("A rowLimit should have a positive number");
}
mRowLimit = rowLimit;
}
+
+ private void setWindowStyle(int windowStyle) {
+ // TODO: Set other attributes of window style. Like fill opacity and fill color.
+ switch (windowStyle) {
+ case 2:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_LEFT;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ case 3:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_CENTER;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ case 4:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_LEFT;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ case 5:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_LEFT;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ case 6:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_CENTER;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ case 7:
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_LEFT;
+ mPrintDirection = CaptionWindowAttr.PRINT_TOP_TO_BOTTOM;
+ break;
+ default:
+ if (windowStyle != 0 && windowStyle != 1) {
+ Log.e(TAG, "Error predefined window style:" + windowStyle);
+ }
+ mWindowJustify = CaptionWindowAttr.JUSTIFY_LEFT;
+ mPrintDirection = CaptionWindowAttr.PRINT_LEFT_TO_RIGHT;
+ break;
+ }
+ }
}
diff --git a/usbtuner/src/com/android/usbtuner/cc/Cea708Parser.java b/src/com/android/tv/tuner/cc/Cea708Parser.java
index 86dd9bfb..92ab0620 100644
--- a/usbtuner/src/com/android/usbtuner/cc/Cea708Parser.java
+++ b/src/com/android/tv/tuner/cc/Cea708Parser.java
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-package com.android.usbtuner.cc;
+package com.android.tv.tuner.cc;
import android.os.SystemClock;
import android.support.annotation.IntDef;
import android.util.Log;
import android.util.SparseIntArray;
-import com.android.usbtuner.data.Cea708Data;
-import com.android.usbtuner.data.Cea708Data.CaptionColor;
-import com.android.usbtuner.data.Cea708Data.CaptionEvent;
-import com.android.usbtuner.data.Cea708Data.CaptionPenAttr;
-import com.android.usbtuner.data.Cea708Data.CaptionPenColor;
-import com.android.usbtuner.data.Cea708Data.CaptionPenLocation;
-import com.android.usbtuner.data.Cea708Data.CaptionWindow;
-import com.android.usbtuner.data.Cea708Data.CaptionWindowAttr;
-import com.android.usbtuner.data.Cea708Data.CcPacket;
-import com.android.usbtuner.util.ByteArrayBuffer;
+import com.android.tv.tuner.data.Cea708Data;
+import com.android.tv.tuner.data.Cea708Data.CaptionColor;
+import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenAttr;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenColor;
+import com.android.tv.tuner.data.Cea708Data.CaptionPenLocation;
+import com.android.tv.tuner.data.Cea708Data.CaptionWindow;
+import com.android.tv.tuner.data.Cea708Data.CaptionWindowAttr;
+import com.android.tv.tuner.data.Cea708Data.CcPacket;
+import com.android.tv.tuner.util.ByteArrayBuffer;
import java.io.UnsupportedEncodingException;
import java.lang.annotation.Retention;
diff --git a/usbtuner/src/com/android/usbtuner/data/Cea708Data.java b/src/com/android/tv/tuner/data/Cea708Data.java
index d286b974..6350d63c 100644
--- a/usbtuner/src/com/android/usbtuner/data/Cea708Data.java
+++ b/src/com/android/tv/tuner/data/Cea708Data.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
-import com.android.usbtuner.cc.Cea708Parser;
+import com.android.tv.tuner.cc.Cea708Parser;
import android.graphics.Color;
import android.support.annotation.NonNull;
@@ -245,6 +245,13 @@ public class Cea708Data {
* Attributes of a caption window, which is defined in CEA-708B.
*/
public static class CaptionWindowAttr {
+ public static final int JUSTIFY_LEFT = 0;
+ public static final int JUSTIFY_CENTER = 2;
+ public static final int PRINT_LEFT_TO_RIGHT = 0;
+ public static final int PRINT_RIGHT_TO_LEFT = 1;
+ public static final int PRINT_TOP_TO_BOTTOM = 2;
+ public static final int PRINT_BOTTOM_TO_TOP = 3;
+
public final CaptionColor fillColor;
public final CaptionColor borderColor;
public final int borderType;
diff --git a/usbtuner/src/com/android/usbtuner/data/PsiData.java b/src/com/android/tv/tuner/data/PsiData.java
index 61521a0f..2c8a52db 100644
--- a/usbtuner/src/com/android/usbtuner/data/PsiData.java
+++ b/src/com/android/tv/tuner/data/PsiData.java
@@ -15,10 +15,10 @@
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
import java.util.List;
diff --git a/usbtuner/src/com/android/usbtuner/data/PsipData.java b/src/com/android/tv/tuner/data/PsipData.java
index b8cf6f0a..e3cdb3a9 100644
--- a/usbtuner/src/com/android/usbtuner/data/PsipData.java
+++ b/src/com/android/tv/tuner/data/PsipData.java
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.format.DateUtils;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.ts.SectionParser;
-import com.android.usbtuner.util.ConvertUtils;
-import com.android.usbtuner.util.IsoUtils;
-import com.android.usbtuner.util.StringUtils;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.ts.SectionParser;
+import com.android.tv.tuner.util.ConvertUtils;
+import com.android.tv.tuner.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
/**
* Collection of ATSC PSIP table items.
@@ -210,7 +210,8 @@ public class PsipData {
@Override
public String toString() {
- return String.format("ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x "
+ return String
+ .format(Locale.US, "ShortName: %s LongName: %s ServiceType: %d ChannelTsid: %x "
+ "ProgramNumber:%d %d-%d SourceId: %x",
mShortName, mLongName, mServiceType, mChannelTsid,
mProgramNumber, mMajorChannelNumber, mMinorChannelNumber, mSourceId);
@@ -429,7 +430,8 @@ public class PsipData {
@Override
public String toString() {
- return String.format("AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, "
+ return String.format(Locale.US,
+ "AC3 audio stream sampleRateCode: %d, bsid: %d, bitRateCode: %d, "
+ "surroundMode: %d, bsmod: %d, numChannels: %d, fullSvc: %s, langCod: %d, "
+ "langCod2: %d, mainId: %d, priority: %d, avcflags: %d, text: %s, language: %s"
+ ", language2: %s", mSampleRateCode, mBsid, mBitRateCode, mSurroundMode,
@@ -485,8 +487,8 @@ public class PsipData {
}
public static class RegionalRating {
- private int mDimension;
- private int mRating;
+ private final int mDimension;
+ private final int mRating;
public RegionalRating(int dimension, int rating) {
mDimension = dimension;
@@ -503,7 +505,7 @@ public class PsipData {
}
public static class EitItem implements Comparable<EitItem>, TvTracksInterface {
- public static long INVALID_PROGRAM_ID = -1;
+ public static final long INVALID_PROGRAM_ID = -1;
// A program id is a primary key of TvContract.Programs table. So it must be positive.
private final long mProgramId;
@@ -657,16 +659,15 @@ public class PsipData {
}
ArrayList<String> languages = new ArrayList<>();
for (AtscAudioTrack audioTrack : mAudioTracks) {
- if (IsoUtils.isValidIso3Language(audioTrack.language)) {
- languages.add(audioTrack.language);
- }
+ languages.add(audioTrack.language);
}
return TextUtils.join(",", languages);
}
@Override
public String toString() {
- return String.format("EitItem programId: %d, eventId: %d, title: %s, startTime: %10d"
+ return String.format(Locale.US,
+ "EitItem programId: %d, eventId: %d, title: %s, startTime: %10d, "
+ "length: %6d, rating: %s, audio tracks: %d, caption tracks: %d, "
+ "genres (broadcast: %s, canonical: %s), description: %s",
mProgramId, mEventId, mTitleText, mStartTime, mLengthInSecond, mContentRating,
diff --git a/usbtuner/src/com/android/usbtuner/data/TunerChannel.java b/src/com/android/tv/tuner/data/TunerChannel.java
index 688faf7a..22cf2aa6 100644
--- a/usbtuner/src/com/android/usbtuner/data/TunerChannel.java
+++ b/src/com/android/tv/tuner/data/TunerChannel.java
@@ -14,20 +14,17 @@
* limitations under the License.
*/
-package com.android.usbtuner.data;
+package com.android.tv.tuner.data;
import android.support.annotation.NonNull;
import android.util.Log;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.Channel.TunerChannelProto;
-import com.android.usbtuner.data.PsiData.PmtItem;
-import com.android.usbtuner.data.PsipData.TvTracksInterface;
-import com.android.usbtuner.data.PsipData.VctItem;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.util.Ints;
-import com.android.usbtuner.util.StringUtils;
+import com.android.tv.tuner.data.Channel;
+import com.android.tv.tuner.data.Channel.TunerChannelProto;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.util.Ints;
+import com.android.tv.tuner.util.StringUtils;
import com.google.protobuf.nano.MessageNano;
import java.io.IOException;
@@ -35,11 +32,12 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Objects;
/**
* A class that represents a single channel accessible through a tuner.
*/
-public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface {
+public class TunerChannel implements Comparable<TunerChannel>, PsipData.TvTracksInterface {
private static final String TAG = "TunerChannel";
// See ATSC Code Points Registry.
@@ -56,8 +54,6 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
"Extended Parameterized Service" };
private static final String ATSC_SERVICE_TYPE_NAME_RESERVED =
ATSC_SERVICE_TYPE_NAMES[Channel.SERVICE_TYPE_ATSC_RESERVED];
- private static final String ATSC_SERVICE_TYPE_NAME_DIGITAL_TELEVISION =
- ATSC_SERVICE_TYPE_NAMES[Channel.SERVICE_TYPE_ATSC_DIGITAL_TELEVISION];
public static final int INVALID_FREQUENCY = -1;
@@ -69,7 +65,8 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
private final TunerChannelProto mProto;
- private TunerChannel(VctItem channel, int programNumber, List<PmtItem> pmtItems, int type) {
+ private TunerChannel(PsipData.VctItem channel, int programNumber,
+ List<PsiData.PmtItem> pmtItems, int type) {
mProto = new TunerChannelProto();
if (channel == null) {
mProto.shortName = "";
@@ -132,11 +129,11 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
mProto.audioTrackIndex = (audioPids.size() > 0) ? 0 : -1;
}
- public TunerChannel(VctItem channel, List<PmtItem> pmtItems) {
+ public TunerChannel(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) {
this(channel, 0, pmtItems, Channel.TYPE_TUNER);
}
- public TunerChannel(int programNumber, List<PmtItem> pmtItems) {
+ public TunerChannel(int programNumber, List<PsiData.PmtItem> pmtItems) {
this(null, programNumber, pmtItems, Channel.TYPE_TUNER);
}
@@ -144,12 +141,12 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
mProto = tunerChannelProto;
}
- public static TunerChannel forFile(VctItem channel, List<PmtItem> pmtItems) {
+ public static TunerChannel forFile(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) {
return new TunerChannel(channel, 0, pmtItems, Channel.TYPE_FILE);
}
public String getName() {
- return (mProto.longName.isEmpty()) ? mProto.shortName : mProto.longName;
+ return (!mProto.shortName.isEmpty()) ? mProto.shortName : mProto.longName;
}
public String getShortName() {
@@ -250,6 +247,18 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
return mProto.filepath;
}
+ public void setVirtualMajor(int virtualMajor) {
+ mProto.virtualMajor = virtualMajor;
+ }
+
+ public void setVirtualMinor(int virtualMinor) {
+ mProto.virtualMinor = virtualMinor;
+ }
+
+ public void setShortName(String shortName) {
+ mProto.shortName = shortName;
+ }
+
public void setFrequency(int frequency) {
mProto.frequency = frequency;
}
@@ -351,10 +360,23 @@ public class TunerChannel implements Comparable<TunerChannel>, TvTracksInterface
return ret;
}
- // For FileDataSource, file paths should be compared.
+ // For FileTsStreamer, file paths should be compared.
return StringUtils.compare(getFilepath(), channel.getFilepath());
}
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof TunerChannel)) {
+ return false;
+ }
+ return compareTo((TunerChannel) o) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getFrequency(), getProgramNumber(), getFilepath());
+ }
+
// Serialization
public byte[] toByteArray() {
return MessageNano.toByteArray(mProto);
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/Cea708TextTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java
index a391db50..5e839223 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/Cea708TextTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/Cea708TextTrackRenderer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
import android.util.Log;
@@ -26,16 +26,16 @@ 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.usbtuner.cc.Cea708Parser;
-import com.android.usbtuner.cc.Cea708Parser.OnCea708ParserListener;
-import com.android.usbtuner.data.Cea708Data.CaptionEvent;
+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.
*/
-public class Cea708TextTrackRenderer extends TrackRenderer implements OnCea708ParserListener {
+public class Cea708TextTrackRenderer extends TrackRenderer implements
+ Cea708Parser.OnCea708ParserListener {
private static final String TAG = "Cea708TextTrackRenderer";
private static final boolean DEBUG = false;
@@ -44,9 +44,9 @@ public class Cea708TextTrackRenderer extends TrackRenderer implements OnCea708Pa
// According to CEA-708B, the maximum value of closed caption bandwidth is 9600bps.
private static final int DEFAULT_INPUT_BUFFER_SIZE = 9600 / 8;
- private SampleSource.SampleSourceReader mSource;
- private SampleHolder mSampleHolder;
- private MediaFormatHolder mFormatHolder;
+ private final SampleSource.SampleSourceReader mSource;
+ private final SampleHolder mSampleHolder;
+ private final MediaFormatHolder mFormatHolder;
private int mServiceNumber;
private boolean mInputStreamEnded;
private long mCurrentPositionUs;
@@ -74,7 +74,7 @@ public class Cea708TextTrackRenderer extends TrackRenderer implements OnCea708Pa
}
private boolean handlesMimeType(String mimeType) {
- return mimeType.equals(MpegTsSampleSourceExtractor.MIMETYPE_TEXT_CEA_708);
+ return mimeType.equals(MpegTsSampleExtractor.MIMETYPE_TEXT_CEA_708);
}
@Override
@@ -162,10 +162,8 @@ public class Cea708TextTrackRenderer extends TrackRenderer implements OnCea708Pa
}
private boolean processOutput() {
- if (mInputStreamEnded) {
- return false;
- }
- return mCea708Parser != null && mCea708Parser.processClosedCaptions(mPresentationTimeUs);
+ return !mInputStreamEnded && mCea708Parser != null &&
+ mCea708Parser.processClosedCaptions(mPresentationTimeUs);
}
private boolean feedInputBuffer() throws IOException, ExoPlaybackException {
diff --git a/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java b/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
new file mode 100644
index 00000000..c105e222
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/ExoPlayerSampleExtractor.java
@@ -0,0 +1,398 @@
+/*
+ * 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;
+
+import android.net.Uri;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.SystemClock;
+
+import com.google.android.exoplayer.C;
+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.extractor.ExtractorSampleSource;
+import com.google.android.exoplayer.extractor.ExtractorSampleSource.EventListener;
+import com.google.android.exoplayer.upstream.Allocator;
+import com.google.android.exoplayer.upstream.DataSource;
+import com.google.android.exoplayer.upstream.DefaultAllocator;
+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.List;
+import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A class that extracts samples from a live broadcast stream while storing the sample on the disk.
+ * For demux, this class relies on {@link com.google.android.exoplayer.extractor.ts.TsExtractor}.
+ */
+public class ExoPlayerSampleExtractor implements SampleExtractor {
+ private static final String TAG = "ExoPlayerSampleExtracto";
+
+ // Buffer segment size for memory allocator. Copied from demo implementation of ExoPlayer.
+ private static final int BUFFER_SEGMENT_SIZE_IN_BYTES = 64 * 1024;
+ // Buffer segment count for sample source. Copied from demo implementation of ExoPlayer.
+ private static final int BUFFER_SEGMENT_COUNT = 256;
+
+ private final HandlerThread mSourceReaderThread;
+ private final long mId;
+
+ private final Handler.Callback mSourceReaderWorker;
+
+ private BufferManager.SampleBuffer mSampleBuffer;
+ private Handler mSourceReaderHandler;
+ private volatile boolean mPrepared;
+ private AtomicBoolean mOnCompletionCalled = new AtomicBoolean();
+ private IOException mExceptionOnPrepare;
+ private List<MediaFormat> mTrackFormats;
+ private HashMap<Integer, Long> mLastExtractedPositionUsMap = new HashMap<>();
+ private OnCompletionListener mOnCompletionListener;
+ private Handler mOnCompletionListenerHandler;
+ private IOException mError;
+
+ public ExoPlayerSampleExtractor(Uri uri, DataSource source, BufferManager bufferManager,
+ PlaybackBufferListener bufferListener, boolean isRecording) {
+ // It'll be used as a timeshift file chunk name's prefix.
+ mId = System.currentTimeMillis();
+ Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE_IN_BYTES);
+
+ EventListener eventListener = new EventListener() {
+
+ @Override
+ public void onLoadError(int sourceId, IOException e) {
+ mError = e;
+ }
+ };
+
+ mSourceReaderThread = new HandlerThread("SourceReaderThread");
+ mSourceReaderWorker = new SourceReaderWorker(new ExtractorSampleSource(uri, source,
+ allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE_IN_BYTES,
+ // Do not create a handler if we not on a looper. e.g. test.
+ Looper.myLooper() != null ? new Handler() : null,
+ eventListener, 0));
+ if (isRecording) {
+ mSampleBuffer = new RecordingSampleBuffer(bufferManager, bufferListener, false,
+ RecordingSampleBuffer.BUFFER_REASON_RECORDING);
+ } else {
+ if (bufferManager == null || bufferManager.isDisabled()) {
+ mSampleBuffer = new SimpleSampleBuffer(bufferListener);
+ } else {
+ mSampleBuffer = new RecordingSampleBuffer(bufferManager, bufferListener, true,
+ RecordingSampleBuffer.BUFFER_REASON_LIVE_PLAYBACK);
+ }
+ }
+ }
+
+ @Override
+ public void setOnCompletionListener(OnCompletionListener listener, Handler handler) {
+ mOnCompletionListener = listener;
+ mOnCompletionListenerHandler = handler;
+ }
+
+ private class SourceReaderWorker implements Handler.Callback {
+ public static final int MSG_PREPARE = 1;
+ public static final int MSG_FETCH_SAMPLES = 2;
+ public static final int MSG_RELEASE = 3;
+ private static final int RETRY_INTERVAL_MS = 50;
+
+ private final SampleSource mSampleSource;
+ private SampleSource.SampleSourceReader mSampleSourceReader;
+ private boolean[] mTrackMetEos;
+ private boolean mMetEos = false;
+ private long mCurrentPosition;
+
+ public SourceReaderWorker(SampleSource sampleSource) {
+ mSampleSource = sampleSource;
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ switch (message.what) {
+ case MSG_PREPARE:
+ mPrepared = prepare();
+ if (!mPrepared && mExceptionOnPrepare == null) {
+ mSourceReaderHandler
+ .sendEmptyMessageDelayed(MSG_PREPARE, RETRY_INTERVAL_MS);
+ } else{
+ mSourceReaderHandler.sendEmptyMessage(MSG_FETCH_SAMPLES);
+ }
+ return true;
+ case MSG_FETCH_SAMPLES:
+ boolean didSomething = false;
+ SampleHolder sample = new SampleHolder(
+ SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
+ ConditionVariable conditionVariable = new ConditionVariable();
+ int trackCount = mSampleSourceReader.getTrackCount();
+ for (int i = 0; i < trackCount; ++i) {
+ if (!mTrackMetEos[i] && SampleSource.NOTHING_READ
+ != fetchSample(i, sample, conditionVariable)) {
+ if (mMetEos) {
+ // If mMetEos was on during fetchSample() due to an error,
+ // fetching from other tracks is not necessary.
+ break;
+ }
+ didSomething = true;
+ }
+ }
+ if (!mMetEos) {
+ if (didSomething) {
+ mSourceReaderHandler.sendEmptyMessage(MSG_FETCH_SAMPLES);
+ } else {
+ mSourceReaderHandler.sendEmptyMessageDelayed(MSG_FETCH_SAMPLES,
+ RETRY_INTERVAL_MS);
+ }
+ } else {
+ notifyCompletionIfNeeded(false);
+ }
+ return true;
+ case MSG_RELEASE:
+ if (mSampleSourceReader != null) {
+ if (mPrepared) {
+ // ExtractorSampleSource expects all the tracks should be disabled
+ // before releasing.
+ int count = mSampleSourceReader.getTrackCount();
+ for (int i = 0; i < count; ++i) {
+ mSampleSourceReader.disable(i);
+ }
+ }
+ mSampleSourceReader.release();
+ mSampleSourceReader = null;
+ }
+ cleanUp();
+ mSourceReaderHandler.removeCallbacksAndMessages(null);
+ return true;
+ }
+ return false;
+ }
+
+ private boolean prepare() {
+ if (mSampleSourceReader == null) {
+ mSampleSourceReader = mSampleSource.register();
+ }
+ if(!mSampleSourceReader.prepare(0)) {
+ return false;
+ }
+ if (mTrackFormats == null) {
+ int trackCount = mSampleSourceReader.getTrackCount();
+ mTrackMetEos = new boolean[trackCount];
+ List<MediaFormat> trackFormats = new ArrayList<>();
+ for (int i = 0; i < trackCount; i++) {
+ trackFormats.add(mSampleSourceReader.getFormat(i));
+ mSampleSourceReader.enable(i, 0);
+
+ }
+ mTrackFormats = trackFormats;
+ List<String> ids = new ArrayList<>();
+ for (int i = 0; i < mTrackFormats.size(); i++) {
+ ids.add(String.format(Locale.ENGLISH, "%s_%x", Long.toHexString(mId), i));
+ }
+ try {
+ mSampleBuffer.init(ids, mTrackFormats);
+ } catch (IOException e) {
+ // In this case, we will not schedule any further operation.
+ // mExceptionOnPrepare will be notified to ExoPlayer, and ExoPlayer will
+ // call release() eventually.
+ mExceptionOnPrepare = e;
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private int fetchSample(int track, SampleHolder sample,
+ ConditionVariable conditionVariable) {
+ mSampleSourceReader.continueBuffering(track, mCurrentPosition);
+
+ MediaFormatHolder formatHolder = new MediaFormatHolder();
+ sample.clearData();
+ int ret = mSampleSourceReader.readData(track, mCurrentPosition, formatHolder, sample);
+ if (ret == SampleSource.SAMPLE_READ) {
+ if (mCurrentPosition < sample.timeUs) {
+ mCurrentPosition = sample.timeUs;
+ }
+ try {
+ Long lastExtractedPositionUs = mLastExtractedPositionUsMap.get(track);
+ if (lastExtractedPositionUs == null) {
+ mLastExtractedPositionUsMap.put(track, sample.timeUs);
+ } else {
+ mLastExtractedPositionUsMap.put(track,
+ Math.max(lastExtractedPositionUs, sample.timeUs));
+ }
+ queueSample(track, sample, conditionVariable);
+ } catch (IOException e) {
+ mLastExtractedPositionUsMap.clear();
+ mMetEos = true;
+ mSampleBuffer.setEos();
+ }
+ } else if (ret == SampleSource.END_OF_STREAM) {
+ mTrackMetEos[track] = true;
+ for (int i = 0; i < mTrackMetEos.length; ++i) {
+ if (!mTrackMetEos[i]) {
+ break;
+ }
+ if (i == mTrackMetEos.length -1) {
+ mMetEos = true;
+ mSampleBuffer.setEos();
+ }
+ }
+ }
+ // TODO: Handle SampleSource.FORMAT_READ for dynamic resolution change. b/28169263
+ return ret;
+ }
+ }
+
+ private void queueSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
+ throws IOException {
+ long writeStartTimeNs = SystemClock.elapsedRealtimeNanos();
+ mSampleBuffer.writeSample(index, sample, conditionVariable);
+
+ // Checks whether the storage has enough bandwidth for recording samples.
+ if (mSampleBuffer.isWriteSpeedSlow(sample.size,
+ SystemClock.elapsedRealtimeNanos() - writeStartTimeNs)) {
+ mSampleBuffer.handleWriteSpeedSlow();
+ }
+ }
+
+ @Override
+ public void maybeThrowError() throws IOException {
+ if (mError != null) {
+ IOException e = mError;
+ mError = null;
+ throw e;
+ }
+ }
+
+ @Override
+ public boolean prepare() throws IOException {
+ if (!mSourceReaderThread.isAlive()) {
+ mSourceReaderThread.start();
+ mSourceReaderHandler = new Handler(mSourceReaderThread.getLooper(),
+ mSourceReaderWorker);
+ mSourceReaderHandler.sendEmptyMessage(SourceReaderWorker.MSG_PREPARE);
+ }
+ if (mExceptionOnPrepare != null) {
+ throw mExceptionOnPrepare;
+ }
+ return mPrepared;
+ }
+
+ @Override
+ public List<MediaFormat> getTrackFormats() {
+ return mTrackFormats;
+ }
+
+ @Override
+ public void getTrackMediaFormat(int track, MediaFormatHolder outMediaFormatHolder) {
+ outMediaFormatHolder.format = mTrackFormats.get(track);
+ outMediaFormatHolder.drmInitData = null;
+ }
+
+ @Override
+ public void selectTrack(int index) {
+ mSampleBuffer.selectTrack(index);
+ }
+
+ @Override
+ public void deselectTrack(int index) {
+ mSampleBuffer.deselectTrack(index);
+ }
+
+ @Override
+ public long getBufferedPositionUs() {
+ return mSampleBuffer.getBufferedPositionUs();
+ }
+
+ @Override
+ public boolean continueBuffering(long positionUs) {
+ return mSampleBuffer.continueBuffering(positionUs);
+ }
+
+ @Override
+ public void seekTo(long positionUs) {
+ mSampleBuffer.seekTo(positionUs);
+ }
+
+ @Override
+ public int readSample(int track, SampleHolder sampleHolder) {
+ return mSampleBuffer.readSample(track, sampleHolder);
+ }
+
+ @Override
+ public void release() {
+ if (mSourceReaderThread.isAlive()) {
+ mSourceReaderHandler.removeCallbacksAndMessages(null);
+ mSourceReaderHandler.sendEmptyMessage(SourceReaderWorker.MSG_RELEASE);
+ mSourceReaderThread.quitSafely();
+ // Return early in this case so that session worker can start working on the next
+ // request as early as it can. The clean up will be done in the reader thread while
+ // handling MSG_RELEASE.
+ } else {
+ cleanUp();
+ }
+ }
+
+ private void cleanUp() {
+ boolean result = true;
+ try {
+ if (mSampleBuffer != null) {
+ mSampleBuffer.release();
+ mSampleBuffer = null;
+ }
+ } catch (IOException e) {
+ result = false;
+ }
+ notifyCompletionIfNeeded(result);
+ setOnCompletionListener(null, null);
+ }
+
+ private void notifyCompletionIfNeeded(final boolean result) {
+ if (!mOnCompletionCalled.getAndSet(true)) {
+ final OnCompletionListener listener = mOnCompletionListener;
+ final long lastExtractedPositionUs = getLastExtractedPositionUs();
+ if (mOnCompletionListenerHandler != null && mOnCompletionListener != null) {
+ mOnCompletionListenerHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onCompletion(result, lastExtractedPositionUs);
+ }
+ });
+ }
+ }
+ }
+
+ private long getLastExtractedPositionUs() {
+ long lastExtractedPositionUs = Long.MAX_VALUE;
+ for (long value : mLastExtractedPositionUsMap.values()) {
+ lastExtractedPositionUs = Math.min(lastExtractedPositionUs, value);
+ }
+ if (lastExtractedPositionUs == Long.MAX_VALUE) {
+ lastExtractedPositionUs = C.UNKNOWN_TIME_US;
+ }
+ return lastExtractedPositionUs;
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ReplaySampleSourceExtractor.java b/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
index bbde8863..ec7b4b16 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ReplaySampleSourceExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/FileSampleExtractor.java
@@ -14,16 +14,17 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
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.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.RecordingSampleBuffer;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.exoplayer.buffer.RecordingSampleBuffer;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
+import android.os.Handler;
import android.util.Pair;
import java.io.IOException;
@@ -31,69 +32,75 @@ import java.util.ArrayList;
import java.util.List;
/**
- * A class that plays a recorded stream without using {@link MediaExtractor},
+ * A class that plays a recorded stream without using {@link android.media.MediaExtractor},
* since all samples are extracted and stored to the permanent storage already.
*/
-public class ReplaySampleSourceExtractor implements SampleExtractor{
- private static final String TAG = "ReplaySampleSourceExt";
+public class FileSampleExtractor implements SampleExtractor{
+ private static final String TAG = "FileSampleExtractor";
private static final boolean DEBUG = false;
private int mTrackCount;
- private android.media.MediaFormat[] mMediaFormats;
- private MediaFormat[] mTrackFormats;
-
private boolean mReleased;
+ private final List<MediaFormat> mTrackFormats = new ArrayList<>();
+ private final BufferManager mBufferManager;
+ private final PlaybackBufferListener mBufferListener;
+ private BufferManager.SampleBuffer mSampleBuffer;
- private final CacheManager mCacheManager;
- private final PlaybackCacheListener mCacheListener;
- private CacheManager.SampleBuffer mSampleBuffer;
-
- public ReplaySampleSourceExtractor(
- CacheManager cacheManager, PlaybackCacheListener cacheListener) {
- mCacheManager = cacheManager;
- mCacheListener = cacheListener;
+ public FileSampleExtractor(
+ BufferManager bufferManager, PlaybackBufferListener bufferListener) {
+ mBufferManager = bufferManager;
+ mBufferListener = bufferListener;
mTrackCount = -1;
}
@Override
+ public void maybeThrowError() throws IOException {
+ // Do nothing.
+ }
+
+ @Override
public boolean prepare() throws IOException {
ArrayList<Pair<String, android.media.MediaFormat>> trackInfos =
- mCacheManager.readTrackInfoFiles();
- if (trackInfos == null || trackInfos.size() <= 0) {
- return false;
+ mBufferManager.readTrackInfoFiles();
+ if (trackInfos == null || trackInfos.isEmpty()) {
+ throw new IOException("Cannot find meta files for the recording.");
}
mTrackCount = trackInfos.size();
List<String> ids = new ArrayList<>();
- mMediaFormats = new android.media.MediaFormat[mTrackCount];
- mTrackFormats = new MediaFormat[mTrackCount];
+ mTrackFormats.clear();
for (int i = 0; i < mTrackCount; ++i) {
Pair<String, android.media.MediaFormat> pair = trackInfos.get(i);
ids.add(pair.first);
- mMediaFormats[i] = pair.second;
- mTrackFormats[i] = MediaFormatUtil.createMediaFormat(mMediaFormats[i]);
+ mTrackFormats.add(MediaFormatUtil.createMediaFormat(pair.second));
}
- mSampleBuffer = new RecordingSampleBuffer(mCacheManager, mCacheListener, true,
- RecordingSampleBuffer.CACHE_REASON_RECORDED_PLAYBACK);
- mSampleBuffer.init(ids, null);
+ mSampleBuffer = new RecordingSampleBuffer(mBufferManager, mBufferListener, true,
+ RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK);
+ mSampleBuffer.init(ids, mTrackFormats);
return true;
}
@Override
- public MediaFormat[] getTrackFormats() {
+ public List<MediaFormat> getTrackFormats() {
return mTrackFormats;
}
@Override
public void getTrackMediaFormat(int track, MediaFormatHolder outMediaFormatHolder) {
- outMediaFormatHolder.format = mTrackFormats[track];
+ outMediaFormatHolder.format = mTrackFormats.get(track);
outMediaFormatHolder.drmInitData = null;
}
@Override
public void release() {
if (!mReleased) {
- mSampleBuffer.release();
+ if (mSampleBuffer != null) {
+ try {
+ mSampleBuffer.release();
+ } catch (IOException e) {
+ // Do nothing. Playback ends now.
+ }
+ }
}
mReleased = true;
}
@@ -123,9 +130,11 @@ public class ReplaySampleSourceExtractor implements SampleExtractor{
return mSampleBuffer.readSample(track, sampleHolder);
}
-
@Override
public boolean continueBuffering(long positionUs) {
return mSampleBuffer.continueBuffering(positionUs);
}
+
+ @Override
+ public void setOnCompletionListener(OnCompletionListener listener, Handler handler) { }
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPlayer.java b/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
index 34d83875..381b22e9 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPlayer.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsPlayer.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
+import android.content.Context;
import android.media.AudioFormat;
import android.media.MediaCodec.CryptoException;
-import android.media.MediaDataSource;
+import android.media.PlaybackParams;
import android.os.Handler;
-import android.os.Looper;
import android.support.annotation.IntDef;
import android.view.Surface;
@@ -30,13 +30,20 @@ import com.google.android.exoplayer.ExoPlayer;
import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.MediaCodecVideoTrackRenderer;
+import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.TrackRenderer;
import com.google.android.exoplayer.audio.AudioCapabilities;
import com.google.android.exoplayer.audio.AudioTrack;
-import com.android.usbtuner.data.Cea708Data;
-import com.android.usbtuner.data.Cea708Data.CaptionEvent;
-import com.android.usbtuner.exoplayer.Cea708TextTrackRenderer.CcListener;
-import com.android.usbtuner.exoplayer.ac3.Ac3TrackRenderer;
+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.ac3.Ac3PassthroughTrackRenderer;
+import com.android.tv.tuner.exoplayer.ac3.Ac3TrackRenderer;
+import com.android.tv.tuner.source.TsDataSource;
+import com.android.tv.tuner.source.TsDataSourceManager;
+import com.android.tv.tuner.tvinput.EventDetector;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -44,15 +51,15 @@ import java.lang.annotation.RetentionPolicy;
/**
* MPEG-2 TS stream player implementation using ExoPlayer.
*/
-public class MpegTsPlayer implements ExoPlayer.Listener,
- MediaCodecVideoTrackRenderer.EventListener, Ac3TrackRenderer.EventListener {
+public class MpegTsPlayer implements ExoPlayer.Listener, MediaCodecVideoTrackRenderer.EventListener,
+ Ac3PassthroughTrackRenderer.EventListener, Ac3TrackRenderer.Ac3EventListener {
private int mCaptionServiceNumber = Cea708Data.EMPTY_SERVICE_NUMBER;
/**
* Interface definition for building specific track renderers.
*/
public interface RendererBuilder {
- void buildRenderers(MpegTsPlayer mpegTsPlayer, MediaDataSource dataSource,
+ void buildRenderers(MpegTsPlayer mpegTsPlayer, DataSource dataSource,
RendererBuilderCallback callback);
}
@@ -68,12 +75,13 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
* Interface definition for a callback to be notified of changes in player state.
*/
public interface Listener {
- void onStateChanged(int generation, boolean playWhenReady, int playbackState);
- void onError(int generation, Exception e);
- void onVideoSizeChanged(int generation, int width, int height,
+ void onStateChanged(boolean playWhenReady, int playbackState);
+ void onError(Exception e);
+ void onVideoSizeChanged(int width, int height,
float pixelWidthHeightRatio);
void onDrawnToSurface(MpegTsPlayer player, Surface surface);
- void onAudioUnplayable(int generation);
+ void onAudioUnplayable();
+ void onSmoothTrickplayForceStopped();
}
/**
@@ -91,18 +99,8 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
void onDiscoverCaptionServiceNumber(int serviceNumber);
}
- // Constants pulled into this class for convenience.
- @IntDef({STATE_IDLE, STATE_PREPARING, STATE_BUFFERING, STATE_READY, STATE_ENDED})
- @Retention(RetentionPolicy.SOURCE)
- public @interface PlaybackState {}
- public static final int STATE_IDLE = ExoPlayer.STATE_IDLE;
- public static final int STATE_PREPARING = ExoPlayer.STATE_PREPARING;
- public static final int STATE_BUFFERING = ExoPlayer.STATE_BUFFERING;
- public static final int STATE_READY = ExoPlayer.STATE_READY;
- public static final int STATE_ENDED = ExoPlayer.STATE_ENDED;
-
public static final int RENDERER_COUNT = 3;
- public static final int MIN_BUFFER_MS = 200;
+ public static final int MIN_BUFFER_MS = 0;
public static final int MIN_REBUFFER_MS = 500;
@IntDef({TRACK_TYPE_VIDEO, TRACK_TYPE_AUDIO, TRACK_TYPE_TEXT})
@@ -120,48 +118,66 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
private static final int RENDERER_BUILDING_STATE_BUILDING = 2;
private static final int RENDERER_BUILDING_STATE_BUILT = 3;
+ private static final float MAX_SMOOTH_TRICKPLAY_SPEED = 9.0f;
+ private static final float MIN_SMOOTH_TRICKPLAY_SPEED = 0.1f;
+
private final RendererBuilder mRendererBuilder;
private final ExoPlayer mPlayer;
private final Handler mMainHandler;
- private final int mPlayerGeneration;
private final AudioCapabilities mAudioCapabilities;
+ private final TsDataSourceManager mSourceManager;
private Listener mListener;
@RendererBuildingState private int mRendererBuildingState;
- @PlaybackState private int mLastReportedPlaybackState;
- private boolean mLastReportedPlayWhenReady;
private Surface mSurface;
+ private TsDataSource mDataSource;
private InternalRendererBuilderCallback mBuilderCallback;
private TrackRenderer mVideoRenderer;
private TrackRenderer mAudioRenderer;
-
- private String[][] mTrackNames;
- private int[] mSelectedTracks;
-
private Cea708TextTrackRenderer mTextRenderer;
- private CcListener mCcListener;
+ private final Cea708TextTrackRenderer.CcListener mCcListener;
private VideoEventListener mVideoEventListener;
+ private boolean mTrickplayRunning;
+ private float mVolume;
- public MpegTsPlayer(int playerGeneration, RendererBuilder rendererBuilder, Handler handler,
- AudioCapabilities capabilities, Listener listener) {
+ /**
+ * Creates MPEG2-TS stream player.
+ *
+ * @param rendererBuilder the builder of track renderers
+ * @param handler the handler for the playback events in track renderers
+ * @param sourceManager the manager for {@link DataSource}
+ * @param capabilities the {@link AudioCapabilities} of the current device
+ * @param listener the listener for playback state changes
+ */
+ public MpegTsPlayer(RendererBuilder rendererBuilder, Handler handler,
+ TsDataSourceManager sourceManager, AudioCapabilities capabilities,
+ Listener listener) {
mRendererBuilder = rendererBuilder;
mPlayer = ExoPlayer.Factory.newInstance(RENDERER_COUNT, MIN_BUFFER_MS, MIN_REBUFFER_MS);
mPlayer.addListener(this);
mMainHandler = handler;
- mPlayerGeneration = playerGeneration;
mAudioCapabilities = capabilities;
- mLastReportedPlaybackState = STATE_IDLE;
mRendererBuildingState = RENDERER_BUILDING_STATE_IDLE;
- mSelectedTracks = new int[RENDERER_COUNT];
mCcListener = new MpegTsCcListener();
+ mSourceManager = sourceManager;
mListener = listener;
}
+ /**
+ * Sets the video event listener.
+ *
+ * @param videoEventListener the listener for video events
+ */
public void setVideoEventListener(VideoEventListener videoEventListener) {
mVideoEventListener = videoEventListener;
}
+ /**
+ * Sets the closed caption service number.
+ *
+ * @param captionServiceNumber the service number of CEA-708 closed caption
+ */
public void setCaptionServiceNumber(int captionServiceNumber) {
mCaptionServiceNumber = captionServiceNumber;
if (mTextRenderer != null) {
@@ -170,37 +186,48 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
}
}
+ /**
+ * Sets the surface for the player.
+ *
+ * @param surface the {@link Surface} to render video
+ */
public void setSurface(Surface surface) {
mSurface = surface;
pushSurface(false);
}
+ /**
+ * Returns the current surface of the player.
+ */
public Surface getSurface() {
return mSurface;
}
+ /**
+ * Clears the surface and waits until the surface is being cleaned.
+ */
public void blockingClearSurface() {
mSurface = null;
pushSurface(true);
}
- public String[] getTracks(int type) {
- return mTrackNames == null ? null : mTrackNames[type];
- }
-
- public int getSelectedTrackIndex(int type) {
- return mSelectedTracks[type];
- }
-
- public void selectTrack(int type, int index) {
- if (mSelectedTracks[type] == index) {
- return;
+ /**
+ * Creates renderers and {@link DataSource} and initializes player.
+ * @param context a {@link Context} instance
+ * @param channel to play
+ * @param eventListener for program information which will be scanned from MPEG2-TS stream
+ * @return true when everything is created and initialized well, false otherwise
+ */
+ public boolean prepare(Context context, TunerChannel channel,
+ EventDetector.EventListener eventListener) {
+ TsDataSource source = null;
+ if (channel != null) {
+ source = mSourceManager.createDataSource(context, channel, eventListener);
+ if (source == null) {
+ return false;
+ }
}
- mSelectedTracks[type] = index;
- pushTrackSelection(type, true);
- }
-
- public void prepare(MediaDataSource source) {
+ mDataSource = source;
if (mRendererBuildingState == RENDERER_BUILDING_STATE_BUILT) {
mPlayer.stop();
}
@@ -208,18 +235,20 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
mBuilderCallback.cancel();
}
mRendererBuildingState = RENDERER_BUILDING_STATE_BUILDING;
- maybeReportPlayerState();
mBuilderCallback = new InternalRendererBuilderCallback();
mRendererBuilder.buildRenderers(this, source, mBuilderCallback);
+ return true;
}
- /* package */ void onRenderers(String[][] trackNames, TrackRenderer[] renderers) {
- mBuilderCallback = null;
+ /**
+ * Returns {@link TsDataSource} which provides MPEG2-TS stream.
+ */
+ public TsDataSource getDataSource() {
+ return mDataSource;
+ }
- // Normalize the results.
- if (trackNames == null) {
- trackNames = new String[RENDERER_COUNT][];
- }
+ private void onRenderers(TrackRenderer[] renderers) {
+ mBuilderCallback = null;
for (int i = 0; i < RENDERER_COUNT; i++) {
if (renderers[i] == null) {
// Convert a null renderer to a dummy renderer.
@@ -232,7 +261,6 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
mTextRenderer.setCcListener(mCcListener);
mPlayer.sendMessage(
mTextRenderer, Cea708TextTrackRenderer.MSG_SERVICE_NUMBER, mCaptionServiceNumber);
- mTrackNames = trackNames;
mRendererBuildingState = RENDERER_BUILDING_STATE_BUILT;
pushSurface(false);
mPlayer.prepare(renderers);
@@ -241,24 +269,87 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
pushTrackSelection(TRACK_TYPE_TEXT, true);
}
- /* package */ void onRenderersError(Exception e) {
+ private void onRenderersError(Exception e) {
mBuilderCallback = null;
+ mRendererBuildingState = RENDERER_BUILDING_STATE_IDLE;
if (mListener != null) {
- mListener.onError(mPlayerGeneration, e);
+ mListener.onError(e);
}
- mRendererBuildingState = RENDERER_BUILDING_STATE_IDLE;
- maybeReportPlayerState();
}
+ /**
+ * Sets the player state to pause or play.
+ *
+ * @param playWhenReady sets the player state to being ready to play when {@code true},
+ * sets the player state to being paused when {@code false}
+ *
+ */
public void setPlayWhenReady(boolean playWhenReady) {
mPlayer.setPlayWhenReady(playWhenReady);
+ stopSmoothTrickplay(false);
+ }
+
+ /**
+ * Returns true, if trickplay is supported.
+ */
+ public boolean supportSmoothTrickPlay(float playbackSpeed) {
+ return playbackSpeed > MIN_SMOOTH_TRICKPLAY_SPEED
+ && playbackSpeed < MAX_SMOOTH_TRICKPLAY_SPEED;
+ }
+
+ /**
+ * Starts trickplay. It'll be reset, if {@link #seekTo} or {@link #setPlayWhenReady} is called.
+ */
+ public void startSmoothTrickplay(PlaybackParams playbackParams) {
+ SoftPreconditions.checkState(supportSmoothTrickPlay(playbackParams.getSpeed()));
+ mPlayer.setPlayWhenReady(true);
+ mTrickplayRunning = true;
+ if (mAudioRenderer instanceof Ac3PassthroughTrackRenderer) {
+ mPlayer.sendMessage(mAudioRenderer, Ac3PassthroughTrackRenderer.MSG_SET_PLAYBACK_SPEED,
+ playbackParams.getSpeed());
+ } else {
+ mPlayer.sendMessage(mAudioRenderer,
+ MediaCodecAudioTrackRenderer.MSG_SET_PLAYBACK_PARAMS,
+ playbackParams);
+ }
+ }
+
+ private void stopSmoothTrickplay(boolean calledBySeek) {
+ if (mTrickplayRunning) {
+ mTrickplayRunning = false;
+ if (mAudioRenderer instanceof Ac3PassthroughTrackRenderer) {
+ mPlayer.sendMessage(mAudioRenderer,
+ Ac3PassthroughTrackRenderer.MSG_SET_PLAYBACK_SPEED,
+ 1.0f);
+ } else {
+ mPlayer.sendMessage(mAudioRenderer,
+ MediaCodecAudioTrackRenderer.MSG_SET_PLAYBACK_PARAMS,
+ new PlaybackParams().setSpeed(1.0f));
+ }
+ if (!calledBySeek) {
+ mPlayer.seekTo(mPlayer.getCurrentPosition());
+ }
+ }
}
+ /**
+ * Seeks to the specified position of the current playback.
+ *
+ * @param positionMs the specified position in milli seconds.
+ */
public void seekTo(long positionMs) {
mPlayer.seekTo(positionMs);
+ stopSmoothTrickplay(true);
}
+ /**
+ * Releases the player.
+ */
public void release() {
+ if (mDataSource != null) {
+ mSourceManager.releaseDataSource(mDataSource);
+ mDataSource = null;
+ }
if (mBuilderCallback != null) {
mBuilderCallback.cancel();
mBuilderCallback = null;
@@ -269,76 +360,166 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
mPlayer.release();
}
- @PlaybackState public int getPlaybackState() {
+ /**
+ * Returns the current status of the player.
+ */
+ public int getPlaybackState() {
if (mRendererBuildingState == RENDERER_BUILDING_STATE_BUILDING) {
- return STATE_PREPARING;
+ return ExoPlayer.STATE_PREPARING;
}
return mPlayer.getPlaybackState();
}
+ /**
+ * Returns {@code true} when the player is prepared to play, {@code false} otherwise.
+ */
+ public boolean isPrepared() {
+ int state = getPlaybackState();
+ return state == ExoPlayer.STATE_READY || state == ExoPlayer.STATE_BUFFERING;
+ }
+
+ /**
+ * Returns {@code true} when the player is being ready to play, {@code false} otherwise.
+ */
public boolean isPlaying() {
- @PlaybackState int state = getPlaybackState();
- return (state == STATE_READY || state == STATE_BUFFERING)
+ int state = getPlaybackState();
+ return (state == ExoPlayer.STATE_READY || state == ExoPlayer.STATE_BUFFERING)
&& mPlayer.getPlayWhenReady();
}
+ /**
+ * Returns {@code true} when the player is buffering, {@code false} otherwise.
+ */
public boolean isBuffering() {
- return getPlaybackState() == STATE_BUFFERING;
+ return getPlaybackState() == ExoPlayer.STATE_BUFFERING;
}
+ /**
+ * Returns the current position of the playback in milli seconds.
+ */
public long getCurrentPosition() {
return mPlayer.getCurrentPosition();
}
+ /**
+ * Returns the total duration of the playback.
+ */
public long getDuration() {
return mPlayer.getDuration();
}
- public int getBufferedPercentage() {
- return mPlayer.getBufferedPercentage();
- }
-
+ /**
+ * Returns {@code true} when the player is being ready to play,
+ * {@code false} when the player is paused.
+ */
public boolean getPlayWhenReady() {
return mPlayer.getPlayWhenReady();
}
+ /**
+ * Sets the volume of the audio.
+ *
+ * @param volume see also {@link AudioTrack#setVolume(float)}
+ */
public void setVolume(float volume) {
- mPlayer.sendMessage(mAudioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME, volume);
+ mVolume = volume;
+ if (mAudioRenderer instanceof Ac3PassthroughTrackRenderer) {
+ mPlayer.sendMessage(mAudioRenderer, Ac3PassthroughTrackRenderer.MSG_SET_VOLUME, volume);
+ } else {
+ mPlayer.sendMessage(mAudioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+ volume);
+ }
}
+ /**
+ * Enables or disables audio.
+ *
+ * @param enable enables the audio when {@code true}, disables otherwise.
+ */
public void setAudioTrack(boolean enable) {
- mPlayer.sendMessage(mAudioRenderer, Ac3TrackRenderer.MSG_SET_AUDIO_TRACK, enable ? 1 : 0);
+ if (mAudioRenderer instanceof Ac3PassthroughTrackRenderer) {
+ mPlayer.sendMessage(mAudioRenderer, Ac3PassthroughTrackRenderer.MSG_SET_AUDIO_TRACK,
+ enable ? 1 : 0);
+ } else {
+ mPlayer.sendMessage(mAudioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME,
+ enable ? mVolume : 0.0f);
+ }
}
+ /**
+ * Returns {@code true} when AC3 audio can be played, {@code false} otherwise.
+ */
public boolean isAc3Playable() {
return mAudioCapabilities != null
&& mAudioCapabilities.supportsEncoding(AudioFormat.ENCODING_AC3);
}
+ /**
+ * Notifies when the audio cannot be played by the current device.
+ */
public void onAudioUnplayable() {
if (mListener != null) {
- mListener.onAudioUnplayable(mPlayerGeneration);
+ mListener.onAudioUnplayable();
}
}
- /* package */ Looper getPlaybackLooper() {
- return mPlayer.getPlaybackLooper();
+ /**
+ * Returns {@code true} if the player has any video track, {@code false} otherwise.
+ */
+ public boolean hasVideo() {
+ return mPlayer.getTrackCount(TRACK_TYPE_VIDEO) > 0;
}
+ /**
+ * Returns {@code true} if the player has any audio trock, {@code false} otherwise.
+ */
+ public boolean hasAudio() {
+ return mPlayer.getTrackCount(TRACK_TYPE_AUDIO) > 0;
+ }
+
+ /**
+ * Returns the number of tracks exposed by the specified renderer.
+ */
+ public int getTrackCount(int rendererIndex) {
+ return mPlayer.getTrackCount(rendererIndex);
+ }
+
+ /**
+ * Selects a track for the specified renderer.
+ */
+ public void setSelectedTrack(int rendererIndex, int trackIndex) {
+ if (trackIndex >= getTrackCount(rendererIndex)) {
+ return;
+ }
+ mPlayer.setSelectedTrack(rendererIndex, trackIndex);
+ }
+
+ /**
+ * Gets the main handler of the player.
+ */
/* package */ Handler getMainHandler() {
return mMainHandler;
}
@Override
public void onPlayerStateChanged(boolean playWhenReady, int state) {
- maybeReportPlayerState();
+ if (mListener == null) {
+ return;
+ }
+ mListener.onStateChanged(playWhenReady, state);
+ if (state == ExoPlayer.STATE_READY && mPlayer.getTrackCount(TRACK_TYPE_VIDEO) > 0
+ && playWhenReady) {
+ MediaFormat format = mPlayer.getTrackFormat(TRACK_TYPE_VIDEO, 0);
+ mListener.onVideoSizeChanged(format.width,
+ format.height, format.pixelWidthHeightRatio);
+ }
}
@Override
public void onPlayerError(ExoPlaybackException exception) {
mRendererBuildingState = RENDERER_BUILDING_STATE_IDLE;
if (mListener != null) {
- mListener.onError(mPlayerGeneration, exception);
+ mListener.onError(exception);
}
}
@@ -346,14 +527,14 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees,
float pixelWidthHeightRatio) {
if (mListener != null) {
- mListener.onVideoSizeChanged(mPlayerGeneration, width, height, pixelWidthHeightRatio);
+ mListener.onVideoSizeChanged(width, height, pixelWidthHeightRatio);
}
}
@Override
public void onDecoderInitialized(String decoderName, long elapsedRealtimeMs,
long initializationDurationMs) {
- // TODO
+ // Do nothing.
}
@Override
@@ -363,7 +544,9 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
@Override
public void onAudioTrackInitializationError(AudioTrack.InitializationException e) {
- onAudioUnplayable();
+ if (mListener != null) {
+ mListener.onAudioUnplayable();
+ }
}
@Override
@@ -372,6 +555,12 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
}
@Override
+ public void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs,
+ long elapsedSinceLastFeedMs) {
+ // Do nothing.
+ }
+
+ @Override
public void onCryptoError(CryptoException e) {
// Do nothing.
}
@@ -390,24 +579,15 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
@Override
public void onDroppedFrames(int count, long elapsed) {
- // Do nothing.
+ if (mTrickplayRunning && mListener != null) {
+ mListener.onSmoothTrickplayForceStopped();
+ }
}
- private void maybeReportPlayerState() {
- boolean playWhenReady = mPlayer.getPlayWhenReady();
- @PlaybackState int playbackState = getPlaybackState();
- if (mLastReportedPlayWhenReady != playWhenReady
- || mLastReportedPlaybackState != playbackState) {
- if (mListener != null) {
- if (playbackState == STATE_ENDED) {
- mListener.onStateChanged(mPlayerGeneration, playWhenReady, STATE_ENDED);
- }
- else if (playbackState == STATE_READY) {
- mListener.onStateChanged(mPlayerGeneration, playWhenReady, STATE_READY);
- }
- }
- mLastReportedPlayWhenReady = playWhenReady;
- mLastReportedPlaybackState = playbackState;
+ @Override
+ public void onAudioTrackSetPlaybackParamsError(IllegalArgumentException e) {
+ if (mTrickplayRunning && mListener != null) {
+ mListener.onSmoothTrickplayForceStopped();
}
}
@@ -432,7 +612,7 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
mPlayer.setSelectedTrack(type, allowRendererEnable ? 0 : -1);
}
- private class MpegTsCcListener implements CcListener {
+ private class MpegTsCcListener implements Cea708TextTrackRenderer.CcListener {
@Override
public void emitEvent(CaptionEvent captionEvent) {
@@ -459,7 +639,7 @@ public class MpegTsPlayer implements ExoPlayer.Listener,
@Override
public void onRenderers(String[][] trackNames, TrackRenderer[] renderers) {
if (!canceled) {
- MpegTsPlayer.this.onRenderers(trackNames, renderers);
+ MpegTsPlayer.this.onRenderers(renderers);
}
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPassthroughAc3RendererBuilder.java b/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
index 70f266d6..0e46c9cf 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsPassthroughAc3RendererBuilder.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsRendererBuilder.java
@@ -14,46 +14,48 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
import android.content.Context;
-import android.media.MediaDataSource;
import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
-import com.android.usbtuner.exoplayer.MpegTsPlayer.RendererBuilder;
-import com.android.usbtuner.exoplayer.MpegTsPlayer.RendererBuilderCallback;
-import com.android.usbtuner.exoplayer.ac3.Ac3TrackRenderer;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
+import com.google.android.exoplayer.upstream.DataSource;
+import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilder;
+import com.android.tv.tuner.exoplayer.MpegTsPlayer.RendererBuilderCallback;
+import com.android.tv.tuner.exoplayer.ac3.Ac3PassthroughTrackRenderer;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
/**
- * Builder class for AC3 Passthrough track renderer objects.
+ * Builder for renderer objects for {@link MpegTsPlayer}.
*/
-public class MpegTsPassthroughAc3RendererBuilder implements RendererBuilder {
+public class MpegTsRendererBuilder implements RendererBuilder {
private final Context mContext;
- private final CacheManager mCacheManager;
- private final PlaybackCacheListener mCacheListener;
+ private final BufferManager mBufferManager;
+ private final PlaybackBufferListener mBufferListener;
- public MpegTsPassthroughAc3RendererBuilder(Context context, CacheManager cacheManager,
- PlaybackCacheListener cacheListener) {
+ public MpegTsRendererBuilder(Context context, BufferManager bufferManager,
+ PlaybackBufferListener bufferListener) {
mContext = context;
- mCacheManager = cacheManager;
- mCacheListener = cacheListener;
+ mBufferManager = bufferManager;
+ mBufferListener = bufferListener;
}
@Override
- public void buildRenderers(MpegTsPlayer mpegTsPlayer, MediaDataSource dataSource,
+ public void buildRenderers(MpegTsPlayer mpegTsPlayer, DataSource dataSource,
RendererBuilderCallback callback) {
// Build the video and audio renderers.
SampleExtractor extractor = dataSource == null ?
- new MpegTsSampleSourceExtractor(mCacheManager, mCacheListener) :
- new MpegTsSampleSourceExtractor(dataSource, mCacheManager, mCacheListener);
+ new MpegTsSampleExtractor(mBufferManager, mBufferListener) :
+ new MpegTsSampleExtractor(dataSource, mBufferManager, mBufferListener);
SampleSource sampleSource = new MpegTsSampleSource(extractor);
MpegTsVideoTrackRenderer videoRenderer = new MpegTsVideoTrackRenderer(mContext,
sampleSource, mpegTsPlayer.getMainHandler(), mpegTsPlayer);
- Ac3TrackRenderer audioRenderer = new Ac3TrackRenderer(sampleSource,
- mpegTsPlayer.getMainHandler(), mpegTsPlayer, false);
+ // TODO: Only using Ac3PassthroughTrackRenderer for A/V sync issue. We will use
+ // {@link Ac3TrackRenderer} when we use ExoPlayer's extractor.
+ TrackRenderer audioRenderer = new Ac3PassthroughTrackRenderer(sampleSource,
+ mpegTsPlayer.getMainHandler(), mpegTsPlayer);
Cea708TextTrackRenderer textRenderer = new Cea708TextTrackRenderer(sampleSource);
TrackRenderer[] renderers = new TrackRenderer[MpegTsPlayer.RENDERER_COUNT];
diff --git a/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java b/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
new file mode 100644
index 00000000..7bf116c8
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsSampleExtractor.java
@@ -0,0 +1,335 @@
+/*
+ * 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;
+
+import android.net.Uri;
+import android.os.Handler;
+
+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;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Extracts samples from {@link DataSource} for MPEG-TS streams.
+ */
+public final class MpegTsSampleExtractor implements SampleExtractor {
+ public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
+
+ private static final int CC_BUFFER_SIZE_IN_BYTES = 9600 / 8;
+
+ private final SampleExtractor mSampleExtractor;
+ private final List<MediaFormat> mTrackFormats = new ArrayList<>();
+ private final List<Boolean> mReachedEos = new ArrayList<>();
+ private int mVideoTrackIndex;
+ private final SamplePool mCcSamplePool = new SamplePool();
+ private final List<SampleHolder> mPendingCcSamples = new LinkedList<>();
+
+ private int mCea708TextTrackIndex;
+ private boolean mCea708TextTrackSelected;
+
+ private CcParser mCcParser;
+
+ private void init() {
+ mVideoTrackIndex = -1;
+ mCea708TextTrackIndex = -1;
+ mCea708TextTrackSelected = false;
+ }
+
+ /**
+ * Creates MpegTsSampleExtractor for {@link DataSource}.
+ *
+ * @param source the {@link DataSource} to extract from
+ * @param bufferManager the manager for reading & writing samples backed by physical storage
+ * @param bufferListener the {@link PlaybackBufferListener}
+ * to notify buffer storage status change
+ */
+ public MpegTsSampleExtractor(DataSource source, BufferManager bufferManager,
+ PlaybackBufferListener bufferListener) {
+ mSampleExtractor = new ExoPlayerSampleExtractor(Uri.EMPTY, source, bufferManager,
+ bufferListener, false);
+ init();
+ }
+
+ /**
+ * Creates MpegTsSampleExtractor for a recorded program.
+ *
+ * @param bufferManager the samples provider which is stored in physical storage
+ * @param bufferListener the {@link PlaybackBufferListener}
+ * to notify buffer storage status change
+ */
+ public MpegTsSampleExtractor(BufferManager bufferManager,
+ PlaybackBufferListener bufferListener) {
+ mSampleExtractor = new FileSampleExtractor(bufferManager, bufferListener);
+ init();
+ }
+
+ @Override
+ public void maybeThrowError() throws IOException {
+ if (mSampleExtractor != null) {
+ mSampleExtractor.maybeThrowError();
+ }
+ }
+
+ @Override
+ public boolean prepare() throws IOException {
+ if(!mSampleExtractor.prepare()) {
+ return false;
+ }
+ List<MediaFormat> formats = mSampleExtractor.getTrackFormats();
+ int trackCount = formats.size();
+ mTrackFormats.clear();
+ mReachedEos.clear();
+
+ for (int i = 0; i < trackCount; ++i) {
+ mTrackFormats.add(formats.get(i));
+ mReachedEos.add(false);
+ String mime = formats.get(i).mimeType;
+ if (MimeTypes.isVideo(mime) && mVideoTrackIndex == -1) {
+ mVideoTrackIndex = i;
+ if (android.media.MediaFormat.MIMETYPE_VIDEO_MPEG2.equals(mime)) {
+ mCcParser = new Mpeg2CcParser();
+ } else if (android.media.MediaFormat.MIMETYPE_VIDEO_AVC.equals(mime)) {
+ mCcParser = new H264CcParser();
+ }
+ }
+ }
+
+ if (mVideoTrackIndex != -1) {
+ mCea708TextTrackIndex = trackCount;
+ }
+ if (mCea708TextTrackIndex >= 0) {
+ mTrackFormats.add(MediaFormat.createTextFormat(null, MIMETYPE_TEXT_CEA_708, 0,
+ mTrackFormats.get(0).durationUs, ""));
+ }
+ return true;
+ }
+
+ @Override
+ public List<MediaFormat> getTrackFormats() {
+ return mTrackFormats;
+ }
+
+ @Override
+ public void selectTrack(int index) {
+ if (index == mCea708TextTrackIndex) {
+ mCea708TextTrackSelected = true;
+ return;
+ }
+ mSampleExtractor.selectTrack(index);
+ }
+
+ @Override
+ public void deselectTrack(int index) {
+ if (index == mCea708TextTrackIndex) {
+ mCea708TextTrackSelected = false;
+ return;
+ }
+ mSampleExtractor.deselectTrack(index);
+ }
+
+ @Override
+ public long getBufferedPositionUs() {
+ return mSampleExtractor.getBufferedPositionUs();
+ }
+
+ @Override
+ public void seekTo(long positionUs) {
+ mSampleExtractor.seekTo(positionUs);
+ for (SampleHolder holder : mPendingCcSamples) {
+ mCcSamplePool.releaseSample(holder);
+ }
+ mPendingCcSamples.clear();
+ }
+
+ @Override
+ public void getTrackMediaFormat(int track, MediaFormatHolder outMediaFormatHolder) {
+ if (track != mCea708TextTrackIndex) {
+ mSampleExtractor.getTrackMediaFormat(track, outMediaFormatHolder);
+ }
+ }
+
+ @Override
+ public int readSample(int track, SampleHolder sampleHolder) {
+ if (track == mCea708TextTrackIndex) {
+ if (mCea708TextTrackSelected && !mPendingCcSamples.isEmpty()) {
+ SampleHolder holder = mPendingCcSamples.remove(0);
+ holder.data.flip();
+ sampleHolder.timeUs = holder.timeUs;
+ sampleHolder.data.put(holder.data);
+ mCcSamplePool.releaseSample(holder);
+ return SampleSource.SAMPLE_READ;
+ } else {
+ return mVideoTrackIndex < 0 || mReachedEos.get(mVideoTrackIndex)
+ ? SampleSource.END_OF_STREAM : SampleSource.NOTHING_READ;
+ }
+ }
+
+ int result = mSampleExtractor.readSample(track, sampleHolder);
+ switch (result) {
+ case SampleSource.END_OF_STREAM: {
+ mReachedEos.set(track, true);
+ break;
+ }
+ case SampleSource.SAMPLE_READ: {
+ if (mCea708TextTrackSelected && track == mVideoTrackIndex
+ && sampleHolder.data != null) {
+ mCcParser.mayParseClosedCaption(sampleHolder.data, sampleHolder.timeUs);
+ }
+ break;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public void release() {
+ mSampleExtractor.release();
+ mVideoTrackIndex = -1;
+ mCea708TextTrackIndex = -1;
+ mCea708TextTrackSelected = false;
+ }
+
+ @Override
+ public boolean continueBuffering(long positionUs) {
+ return mSampleExtractor.continueBuffering(positionUs);
+ }
+
+ @Override
+ public void setOnCompletionListener(OnCompletionListener listener, Handler handler) { }
+
+ private abstract class CcParser {
+ // Interim buffer for reduce direct access to ByteBuffer which is expensive. Using
+ // relatively small buffer size in order to minimize memory footprint increase.
+ protected final byte[] mBuffer = new byte[1024];
+
+ abstract void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs);
+
+ protected int parseClosedCaption(ByteBuffer buffer, int offset, long presentationTimeUs) {
+ // For the details of user_data_type_structure, see ATSC A/53 Part 4 - Table 6.9.
+ int pos = offset;
+ if (pos + 2 >= buffer.position()) {
+ return offset;
+ }
+ boolean processCcDataFlag = (buffer.get(pos) & 64) != 0;
+ int ccCount = buffer.get(pos) & 0x1f;
+ pos += 2;
+ if (!processCcDataFlag || pos + 3 * ccCount >= buffer.position() || ccCount == 0) {
+ return offset;
+ }
+ SampleHolder holder = mCcSamplePool.acquireSample(CC_BUFFER_SIZE_IN_BYTES);
+ for (int i = 0; i < 3 * ccCount; i++) {
+ holder.data.put(buffer.get(pos++));
+ }
+ holder.timeUs = presentationTimeUs;
+ mPendingCcSamples.add(holder);
+ return pos;
+ }
+ }
+
+ private class Mpeg2CcParser extends CcParser {
+ private static final int PATTERN_LENGTH = 9;
+
+ @Override
+ public void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs) {
+ int totalSize = buffer.position();
+ // Reading the frame in bulk to reduce the overhead from ByteBuffer.get() with
+ // overlapping to handle the case that the pattern exists in the boundary.
+ for (int i = 0; i < totalSize; i += mBuffer.length - PATTERN_LENGTH) {
+ buffer.position(i);
+ int size = Math.min(totalSize - i, mBuffer.length);
+ buffer.get(mBuffer, 0, size);
+ int j = 0;
+ while (j < size - PATTERN_LENGTH) {
+ // Find the start prefix code of private user data.
+ if (mBuffer[j] == 0
+ && mBuffer[j + 1] == 0
+ && mBuffer[j + 2] == 1
+ && (mBuffer[j + 3] & 0xff) == 0xb2) {
+ // ATSC closed caption data embedded in MPEG2VIDEO stream has 'GA94' user
+ // identifier and user data type code 3.
+ if (mBuffer[j + 4] == 'G'
+ && mBuffer[j + 5] == 'A'
+ && mBuffer[j + 6] == '9'
+ && mBuffer[j + 7] == '4'
+ && mBuffer[j + 8] == 3) {
+ j = parseClosedCaption(buffer, i + j + PATTERN_LENGTH,
+ presentationTimeUs) - i;
+ } else {
+ j += PATTERN_LENGTH;
+ }
+ } else {
+ ++j;
+ }
+ }
+ }
+ buffer.position(totalSize);
+ }
+ }
+
+ private class H264CcParser extends CcParser {
+ private static final int PATTERN_LENGTH = 14;
+
+ @Override
+ public void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs) {
+ int totalSize = buffer.position();
+ // Reading the frame in bulk to reduce the overhead from ByteBuffer.get() with
+ // overlapping to handle the case that the pattern exists in the boundary.
+ for (int i = 0; i < totalSize; i += mBuffer.length - PATTERN_LENGTH) {
+ buffer.position(i);
+ int size = Math.min(totalSize - i, mBuffer.length);
+ buffer.get(mBuffer, 0, size);
+ int j = 0;
+ while (j < size - PATTERN_LENGTH) {
+ // Find the start prefix code of a NAL Unit.
+ if (mBuffer[j] == 0
+ && mBuffer[j + 1] == 0
+ && mBuffer[j + 2] == 1) {
+ int nalType = mBuffer[j + 3] & 0x1f;
+ int payloadType = mBuffer[j + 4] & 0xff;
+
+ // ATSC closed caption data embedded in H264 private user data has NAL type
+ // 6, payload type 4, and 'GA94' user identifier for ATSC.
+ if (nalType == 6 && payloadType == 4 && mBuffer[j + 9] == 'G'
+ && mBuffer[j + 10] == 'A'
+ && mBuffer[j + 11] == '9'
+ && mBuffer[j + 12] == '4') {
+ j = parseClosedCaption(buffer, i + j + PATTERN_LENGTH,
+ presentationTimeUs) - i;
+ } else {
+ j += 7;
+ }
+ } else {
+ ++j;
+ }
+ }
+ }
+ buffer.position(totalSize);
+ }
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSource.java b/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java
index a799c9a4..6007b0be 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSource.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsSampleSource.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.MediaFormat;
@@ -24,6 +24,8 @@ import com.google.android.exoplayer.SampleSource.SampleSourceReader;
import com.google.android.exoplayer.util.Assertions;
import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
/** {@link SampleSource} that extracts sample data using a {@link SampleExtractor}. */
public final class MpegTsSampleSource implements SampleSource, SampleSourceReader {
@@ -33,13 +35,12 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
private static final int TRACK_STATE_FORMAT_SENT = 2;
private final SampleExtractor mSampleExtractor;
+ private final List<Integer> mTrackStates = new ArrayList<>();
+ private final List<Boolean> mPendingDiscontinuities = new ArrayList<>();
- private MediaFormat[] mTrackFormats;
private boolean mPrepared;
private IOException mPreparationError;
private int mRemainingReleaseCount;
- private int[] mTrackStates;
- private boolean[] mPendingDiscontinuities;
private long mLastSeekPositionUs;
private long mPendingSeekPositionUs;
@@ -67,10 +68,16 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
}
try {
if (mSampleExtractor.prepare()) {
- mTrackFormats = mSampleExtractor.getTrackFormats();
- mTrackStates = new int[mTrackFormats.length];
- mPendingDiscontinuities = new boolean[mTrackStates.length];
+ int trackCount = mSampleExtractor.getTrackFormats().size();
+ mTrackStates.clear();
+ mPendingDiscontinuities.clear();
+ for (int i = 0; i < trackCount; ++i) {
+ mTrackStates.add(i, TRACK_STATE_DISABLED);
+ mPendingDiscontinuities.add(i, false);
+ }
mPrepared = true;
+ } else {
+ return false;
}
} catch (IOException e) {
mPreparationError = e;
@@ -83,20 +90,20 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
@Override
public int getTrackCount() {
Assertions.checkState(mPrepared);
- return mTrackFormats.length;
+ return mSampleExtractor.getTrackFormats().size();
}
@Override
public MediaFormat getFormat(int track) {
Assertions.checkState(mPrepared);
- return mTrackFormats[track];
+ return mSampleExtractor.getTrackFormats().get(track);
}
@Override
public void enable(int track, long positionUs) {
Assertions.checkState(mPrepared);
- Assertions.checkState(mTrackStates[track] == TRACK_STATE_DISABLED);
- mTrackStates[track] = TRACK_STATE_ENABLED;
+ Assertions.checkState(mTrackStates.get(track) == TRACK_STATE_DISABLED);
+ mTrackStates.set(track, TRACK_STATE_ENABLED);
mSampleExtractor.selectTrack(track);
seekToUsInternal(positionUs, positionUs != 0);
}
@@ -104,10 +111,10 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
@Override
public void disable(int track) {
Assertions.checkState(mPrepared);
- Assertions.checkState(mTrackStates[track] != TRACK_STATE_DISABLED);
+ Assertions.checkState(mTrackStates.get(track) != TRACK_STATE_DISABLED);
mSampleExtractor.deselectTrack(track);
- mPendingDiscontinuities[track] = false;
- mTrackStates[track] = TRACK_STATE_DISABLED;
+ mPendingDiscontinuities.set(track, false);
+ mTrackStates.set(track, TRACK_STATE_DISABLED);
}
@Override
@@ -117,8 +124,8 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
@Override
public long readDiscontinuity(int track) {
- if (mPendingDiscontinuities[track]) {
- mPendingDiscontinuities[track] = false;
+ if (mPendingDiscontinuities.get(track)) {
+ mPendingDiscontinuities.set(track, false);
return mLastSeekPositionUs;
}
return NO_DISCONTINUITY;
@@ -128,13 +135,13 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
public int readData(int track, long positionUs, MediaFormatHolder formatHolder,
SampleHolder sampleHolder) {
Assertions.checkState(mPrepared);
- Assertions.checkState(mTrackStates[track] != TRACK_STATE_DISABLED);
- if (mPendingDiscontinuities[track]) {
+ Assertions.checkState(mTrackStates.get(track) != TRACK_STATE_DISABLED);
+ if (mPendingDiscontinuities.get(track)) {
return NOTHING_READ;
}
- if (mTrackStates[track] != TRACK_STATE_FORMAT_SENT) {
+ if (mTrackStates.get(track) != TRACK_STATE_FORMAT_SENT) {
mSampleExtractor.getTrackMediaFormat(track, formatHolder);
- mTrackStates[track] = TRACK_STATE_FORMAT_SENT;
+ mTrackStates.set(track, TRACK_STATE_FORMAT_SENT);
return FORMAT_READ;
}
@@ -147,6 +154,9 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
if (mPreparationError != null) {
throw mPreparationError;
}
+ if (mSampleExtractor != null) {
+ mSampleExtractor.maybeThrowError();
+ }
}
@Override
@@ -176,9 +186,9 @@ public final class MpegTsSampleSource implements SampleSource, SampleSourceReade
mLastSeekPositionUs = positionUs;
mPendingSeekPositionUs = positionUs;
mSampleExtractor.seekTo(positionUs);
- for (int i = 0; i < mTrackStates.length; ++i) {
- if (mTrackStates[i] != TRACK_STATE_DISABLED) {
- mPendingDiscontinuities[i] = true;
+ for (int i = 0; i < mTrackStates.size(); ++i) {
+ if (mTrackStates.get(i) != TRACK_STATE_DISABLED) {
+ mPendingDiscontinuities.set(i, true);
}
}
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsVideoTrackRenderer.java b/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java
index d2caeaa4..19360c69 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsVideoTrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/MpegTsVideoTrackRenderer.java
@@ -1,8 +1,9 @@
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
import android.content.Context;
import android.media.MediaCodec;
import android.os.Handler;
+import android.util.Log;
import com.google.android.exoplayer.DecoderInfo;
import com.google.android.exoplayer.ExoPlaybackException;
@@ -14,18 +15,35 @@ import com.google.android.exoplayer.MediaSoftwareCodecUtil;
import com.google.android.exoplayer.SampleSource;
import com.android.tv.common.feature.CommonFeatures;
+import java.lang.reflect.Field;
+
/**
* MPEG-2 TS video track renderer
*/
public class MpegTsVideoTrackRenderer extends MediaCodecVideoTrackRenderer {
+ private static final String TAG = "MpegTsVideoTrackRender";
private static final int VIDEO_PLAYBACK_DEADLINE_IN_MS = 5000;
- private static final int DROPPED_FRAMES_NOTIFICATION_THRESHOLD = 50;
+ // If DROPPED_FRAMES_NOTIFICATION_THRESHOLD frames are consecutively dropped, it'll be notified.
+ private static final int DROPPED_FRAMES_NOTIFICATION_THRESHOLD = 10;
private static final int MIN_HD_HEIGHT = 720;
private static final String MIMETYPE_MPEG2 = "video/mpeg2";
+ private static Field sRenderedFirstFrameField;
private final boolean mIsSwCodecEnabled;
private boolean mCodecIsSwPreferred;
+ private boolean mSetRenderedFirstFrame;
+
+ static {
+ // Remove the reflection below once b/31223646 is resolved.
+ try {
+ sRenderedFirstFrameField = MediaCodecVideoTrackRenderer.class.getDeclaredField(
+ "renderedFirstFrame");
+ sRenderedFirstFrameField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ // Null-checking for {@code sRenderedFirstFrameField} will do the error handling.
+ }
+ }
public MpegTsVideoTrackRenderer(Context context, SampleSource source, Handler handler,
MediaCodecVideoTrackRenderer.EventListener listener) {
@@ -57,4 +75,27 @@ public class MpegTsVideoTrackRenderer extends MediaCodecVideoTrackRenderer {
&& holder.format.height < MIN_HD_HEIGHT;
super.onInputFormatChanged(holder);
}
+
+ @Override
+ protected void onDiscontinuity(long positionUs) throws ExoPlaybackException {
+ super.onDiscontinuity(positionUs);
+ // Disabling pre-rendering of the first frame in order to avoid a frozen picture when
+ // starting the playback. We do this only once, when the renderer is enabled at first, since
+ // we need to pre-render the frame in advance when we do trickplay backed by seeking.
+ if (!mSetRenderedFirstFrame) {
+ setRenderedFirstFrame(true);
+ mSetRenderedFirstFrame = true;
+ }
+ }
+
+ private void setRenderedFirstFrame(boolean renderedFirstFrame) {
+ if (sRenderedFirstFrameField != null) {
+ try {
+ sRenderedFirstFrameField.setBoolean(this, renderedFirstFrame);
+ } catch (IllegalAccessException e) {
+ Log.w(TAG, "renderedFirstFrame is not accessible. Playback may start with a frozen"
+ +" picture.");
+ }
+ }
+ }
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/SampleExtractor.java b/src/com/android/tv/tuner/exoplayer/SampleExtractor.java
index 1a2e55d4..543588c7 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/SampleExtractor.java
+++ b/src/com/android/tv/tuner/exoplayer/SampleExtractor.java
@@ -13,7 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer;
+package com.android.tv.tuner.exoplayer;
+
+import android.os.Handler;
import com.google.android.exoplayer.MediaFormat;
import com.google.android.exoplayer.MediaFormatHolder;
@@ -22,6 +24,7 @@ import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.TrackRenderer;
import java.io.IOException;
+import java.util.List;
/**
* Extractor for reading track metadata and samples stored in tracks.
@@ -38,16 +41,23 @@ import java.io.IOException;
public interface SampleExtractor {
/**
+ * If the extractor is currently having difficulty preparing or loading samples, then this
+ * method throws the underlying error. Otherwise does nothing.
+ *
+ * @throws IOException The underlying error.
+ */
+ void maybeThrowError() throws IOException;
+
+ /**
* Prepares the extractor for reading track metadata and samples.
*
- * @return whether the source is ready; if {@code false}, {@link #prepare()} must be called
- * again
- * @throws {@link IOException} thrown if the source can't be read
+ * @return whether the source is ready; if {@code false}, this method must be called again.
+ * @throws IOException thrown if the source can't be read
*/
boolean prepare() throws IOException;
/** Returns track information about all tracks that can be selected. */
- MediaFormat[] getTrackFormats();
+ List<MediaFormat> getTrackFormats();
/** Selects the track at {@code index} for reading sample data. */
void selectTrack(int index);
@@ -99,4 +109,28 @@ public interface SampleExtractor {
/** Indicates to the source that it should still be buffering data. */
boolean continueBuffering(long positionUs);
+
+ /**
+ * Sets OnCompletionListener for notifying the completion of SampleExtractor.
+ *
+ * @param listener the OnCompletionListener
+ * @param handler the {@link Handler} for {@link Handler#post(Runnable)} of OnCompletionListener
+ */
+ void setOnCompletionListener(OnCompletionListener listener, Handler handler);
+
+ /**
+ * The listener for SampleExtractor being completed.
+ */
+ interface OnCompletionListener {
+
+ /**
+ * Called when sample extraction is completed.
+ *
+ * @param result {@code true} when the extractor is finished without an error,
+ * {@code false} otherwise (storage error, weak signal, being reached at EoS
+ * prematurely, etc.)
+ * @param lastExtractedPositionUs the last extracted position when extractor is completed
+ */
+ void onCompletion(boolean result, long lastExtractedPositionUs);
+ }
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3TrackRenderer.java b/src/com/android/tv/tuner/exoplayer/ac3/Ac3PassthroughTrackRenderer.java
index 05327dba..9dae2e34 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3TrackRenderer.java
+++ b/src/com/android/tv/tuner/exoplayer/ac3/Ac3PassthroughTrackRenderer.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.ac3;
+package com.android.tv.tuner.exoplayer.ac3;
import android.os.Handler;
import android.os.SystemClock;
@@ -33,24 +33,25 @@ 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.usbtuner.tvinput.UsbTunerDebug;
+import com.android.tv.tuner.tvinput.TunerDebug;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayList;
/**
* Decodes and renders AC3 audio.
*/
-public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.DecodeListener,
- MediaClock {
- public static final int MSG_SET_VOLUME = MediaCodecAudioTrackRenderer.MSG_SET_VOLUME;
+public class Ac3PassthroughTrackRenderer extends TrackRenderer implements MediaClock {
+ public static final int MSG_SET_VOLUME = 10000;
public static final int MSG_SET_AUDIO_TRACK = MSG_SET_VOLUME + 1;
+ public static final int MSG_SET_PLAYBACK_SPEED = MSG_SET_VOLUME + 2;
// ATSC/53 allows sample rate to be only 48Khz.
// One AC3 sample has 1536 frames, and its duration is 32ms.
public static final long AC3_SAMPLE_DURATION_US = 32000;
- private static final String TAG = "Ac3TrackRenderer";
+ private static final String TAG = "Ac3PassthroughTrackRenderer";
private static final boolean DEBUG = false;
/**
@@ -88,13 +89,11 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
private final MediaFormatHolder mFormatHolder;
private final EventListener mEventListener;
private final Handler mEventHandler;
- private final boolean mIsSoftware;
private final AudioTrackMonitor mMonitor;
private final AudioClock mAudioClock;
private MediaFormat mFormat;
- private Ac3Decoder mDecoder;
- private ByteBuffer mOutputBuffer;
+ private final ByteBuffer mOutputBuffer;
private boolean mOutputReady;
private int mTrackIndex;
private boolean mSourceStateReady;
@@ -106,14 +105,14 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
private long mPresentationTimeUs;
private long mInterpolatedTimeUs;
private long mPreviousPositionUs;
+ private boolean mIsStopped;
+ private ArrayList<Integer> mTracksIndex;
- public Ac3TrackRenderer(SampleSource source, Handler eventHandler,
- EventListener listener, boolean isSoftware) {
+ public Ac3PassthroughTrackRenderer(SampleSource source, Handler eventHandler,
+ EventListener listener) {
mSource = source.register();
mEventHandler = eventHandler;
mEventListener = listener;
- mDecoder = Ac3Decoder.createAc3Decoder(isSoftware);
- mIsSoftware = isSoftware;
mTrackIndex = -1;
mSampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DIRECT);
mSampleHolder.ensureSpaceForWrite(DEFAULT_INPUT_BUFFER_SIZE);
@@ -123,6 +122,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
mCodecCounters = new CodecCounters();
mMonitor = new AudioTrackMonitor();
mAudioClock = new AudioClock();
+ mTracksIndex = new ArrayList<>();
}
@Override
@@ -142,8 +142,10 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
}
for (int i = 0; i < mSource.getTrackCount(); i++) {
if (handlesMimeType(mSource.getFormat(i).mimeType)) {
- mTrackIndex = i;
- return true;
+ if (mTrackIndex < 0) {
+ mTrackIndex = i;
+ }
+ mTracksIndex.add(i);
}
}
@@ -153,20 +155,20 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
@Override
protected int getTrackCount() {
- return mTrackIndex < 0 ? 0 : 1;
+ return mTracksIndex.size();
}
@Override
protected MediaFormat getFormat(int track) {
- Assertions.checkArgument(mTrackIndex != -1 && track == 0);
- return mSource.getFormat(mTrackIndex);
+ Assertions.checkArgument(track >= 0 && track < mTracksIndex.size());
+ return mSource.getFormat(mTracksIndex.get(track));
}
@Override
protected void onEnabled(int track, long positionUs, boolean joining) {
- Assertions.checkArgument(mTrackIndex != -1 && track == 0);
+ Assertions.checkArgument(track >= 0 && track < mTracksIndex.size());
+ mTrackIndex = mTracksIndex.get(track);
mSource.enable(mTrackIndex, positionUs);
- mDecoder.startDecoder(this);
seekToInternal(positionUs);
}
@@ -212,9 +214,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
mSource.seekToUs(positionUs);
AUDIO_TRACK.reset();
// resetSessionId() will create a new framework AudioTrack instead of reusing old one.
- if (!mIsSoftware) {
- AUDIO_TRACK.resetSessionId();
- }
+ AUDIO_TRACK.resetSessionId();
seekToInternal(positionUs);
}
@@ -222,12 +222,14 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
protected void onStarted() {
AUDIO_TRACK.play();
mAudioClock.start();
+ mIsStopped = false;
}
@Override
protected void onStopped() {
AUDIO_TRACK.pause();
mAudioClock.stop();
+ mIsStopped = true;
}
@Override
@@ -248,7 +250,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
// Sometimes MediaCodecTrackRenderer does not fetch EoS timely
// after EoS was notified here long before.
long diff = SystemClock.elapsedRealtime() - mEndOfStreamMs;
- if (diff >= KEEP_ALIVE_AFTER_EOS_DURATION_MS) {
+ if (diff >= KEEP_ALIVE_AFTER_EOS_DURATION_MS && !mIsStopped) {
throw new ExoPlaybackException("Much time has elapsed after EoS");
}
}
@@ -259,6 +261,14 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
Log.d(TAG, "mSourceStateReady: " + String.valueOf(mSourceStateReady));
}
}
+ long discontinuity = mSource.readDiscontinuity(mTrackIndex);
+ if (discontinuity != SampleSource.NO_DISCONTINUITY) {
+ AUDIO_TRACK.handleDiscontinuity();
+ mPresentationTimeUs = discontinuity;
+ mPresentationCount = 0;
+ clearDecodeState();
+ return;
+ }
if (mFormat == null) {
readFormat();
return;
@@ -303,7 +313,6 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
}
private void clearDecodeState() {
- mDecoder.startDecoder(this);
mOutputReady = false;
AUDIO_TRACK.reset();
}
@@ -318,13 +327,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
private void onInputFormatChanged(MediaFormatHolder formatHolder)
throws ExoPlaybackException {
- MediaFormat format = formatHolder.format;
- if (mIsSoftware) {
- mFormat = MediaFormatUtil.createAudioMediaFormat(MimeTypes.AUDIO_RAW, format.durationUs,
- format.channelCount, format.sampleRate);
- } else {
- mFormat = format;
- }
+ mFormat = formatHolder.format;
if (DEBUG) {
Log.d(TAG, "AudioTrack was configured to FORMAT: " + mFormat.toString());
}
@@ -337,17 +340,6 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
return false;
}
- long discontinuity = mSource.readDiscontinuity(mTrackIndex);
- if (discontinuity != SampleSource.NO_DISCONTINUITY) {
- // TODO: handle input discontinuity for trickplay.
- Log.i(TAG, "Read discontinuity happened");
- AUDIO_TRACK.handleDiscontinuity();
- mPresentationTimeUs = discontinuity;
- mPresentationCount = 0;
- clearDecodeState();
- return false;
- }
-
mSampleHolder.data.clear();
mSampleHolder.size = 0;
int result = mSource.readData(mTrackIndex, mPresentationTimeUs, mFormatHolder,
@@ -368,7 +360,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
}
default: {
mSampleHolder.data.flip();
- mDecoder.decode(mSampleHolder.data, mSampleHolder.timeUs);
+ decodeDone(mSampleHolder.data, mSampleHolder.timeUs);
return true;
}
}
@@ -428,7 +420,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
public long getPositionUs() {
if (!AUDIO_TRACK.isInitialized()) {
return mAudioClock.getPositionUs();
- } if (!AUDIO_TRACK.isEnabled()) {
+ } else if (!AUDIO_TRACK.isEnabled()) {
if (mInterpolatedTimeUs > 0) {
return mInterpolatedTimeUs - ESTIMATED_TRACK_RENDERING_DELAY_US;
}
@@ -445,8 +437,8 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
}
mCurrentPositionUs = Math.max(mPresentationTimeUs, mCurrentPositionUs);
} else {
- if (!mIsSoftware && mPreviousPositionUs >
- audioTrackCurrentPositionUs + BACKWARD_AUDIO_TRACK_MOVE_THRESHOLD_US) {
+ if (mPreviousPositionUs
+ > audioTrackCurrentPositionUs + BACKWARD_AUDIO_TRACK_MOVE_THRESHOLD_US) {
Log.e(TAG, "audio_position BACK JUMP: "
+ (mPreviousPositionUs - audioTrackCurrentPositionUs));
mCurrentPositionUs = audioTrackCurrentPositionUs;
@@ -462,8 +454,7 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
return mCurrentPositionUs;
}
- @Override
- public void decodeDone(ByteBuffer outputBuffer, long presentationTimeUs) {
+ private void decodeDone(ByteBuffer outputBuffer, long presentationTimeUs) {
if (outputBuffer == null || mOutputBuffer == null) {
return;
}
@@ -472,8 +463,8 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
return;
}
- if (UsbTunerDebug.ENABLED) {
- UsbTunerDebug.setAudioPtsUs(presentationTimeUs);
+ if (TunerDebug.ENABLED) {
+ TunerDebug.setAudioPtsUs(presentationTimeUs);
}
mOutputBuffer.clear();
@@ -523,9 +514,25 @@ public class Ac3TrackRenderer extends TrackRenderer implements Ac3Decoder.Decode
AUDIO_TRACK.setVolume((Float) message);
break;
case MSG_SET_AUDIO_TRACK:
- AUDIO_TRACK.setStatus((Integer) message == 1);
+ boolean enabled = (Integer) message == 1;
+ if (enabled == AUDIO_TRACK.isEnabled()) {
+ return;
+ }
+ if (!enabled) {
+ // mAudioClock can be different from getPositionUs. In order to sync them,
+ // we set mAudioClock.
+ mAudioClock.setPositionUs(getPositionUs());
+ }
+ AUDIO_TRACK.setStatus(enabled);
+ if (enabled) {
+ // When AUDIO_TRACK is enabled, we need to clear AUDIO_TRACK and seek to
+ // the current position. If not, AUDIO_TRACK has the obsolete data.
+ seekTo(mAudioClock.getPositionUs());
+ }
+ break;
+ case MSG_SET_PLAYBACK_SPEED:
+ mAudioClock.setPlaybackSpeed((Float) message);
break;
-
default:
super.handleMessage(messageType, message);
}
diff --git a/src/com/android/tv/tuner/exoplayer/ac3/Ac3TrackRenderer.java b/src/com/android/tv/tuner/exoplayer/ac3/Ac3TrackRenderer.java
new file mode 100644
index 00000000..2bf86b5a
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/ac3/Ac3TrackRenderer.java
@@ -0,0 +1,94 @@
+/*
+ * 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.ac3;
+
+import android.os.Handler;
+
+import com.google.android.exoplayer.ExoPlaybackException;
+import com.google.android.exoplayer.MediaCodecAudioTrackRenderer;
+import com.google.android.exoplayer.MediaCodecSelector;
+import com.google.android.exoplayer.SampleSource;
+
+/**
+ * MPEG-2 TS audio track renderer.
+ * <p>Since the audio output from {@link android.media.MediaExtractor} contains extra samples at
+ * the beginning, using original {@link MediaCodecAudioTrackRenderer} as audio renderer causes
+ * asynchronous Audio/Video outputs.
+ * This class calculates the offset of audio data and adjust the presentation times to avoid the
+ * asynchronous Audio/Video problem.
+ */
+public class Ac3TrackRenderer extends MediaCodecAudioTrackRenderer {
+ private final String TAG = "Ac3TrackRenderer";
+ private final boolean DEBUG = false;
+
+ private final Ac3EventListener mListener;
+
+ public interface Ac3EventListener extends EventListener {
+ /**
+ * Invoked when a {@link android.media.PlaybackParams} set to an
+ * {@link android.media.AudioTrack} is not valid.
+ *
+ * @param e The corresponding exception.
+ */
+ void onAudioTrackSetPlaybackParamsError(IllegalArgumentException e);
+ }
+
+ public Ac3TrackRenderer(SampleSource source, MediaCodecSelector mediaCodecSelector,
+ Handler eventHandler, EventListener eventListener) {
+ super(source, mediaCodecSelector, eventHandler, eventListener);
+ mListener = (Ac3EventListener) eventListener;
+ }
+
+ @Override
+ public void handleMessage(int messageType, Object message) throws ExoPlaybackException {
+ if (messageType == MSG_SET_PLAYBACK_PARAMS) {
+ try {
+ super.handleMessage(messageType, message);
+ } catch (IllegalArgumentException e) {
+ if (isAudioTrackSetPlaybackParamsError(e)) {
+ notifyAudioTrackSetPlaybackParamsError(e);
+ }
+ }
+ return;
+ }
+ super.handleMessage(messageType, message);
+ }
+
+ private void notifyAudioTrackSetPlaybackParamsError(final IllegalArgumentException e) {
+ if (eventHandler != null && mListener != null) {
+ eventHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mListener.onAudioTrackSetPlaybackParamsError(e);
+ }
+ });
+ }
+ }
+
+ static private boolean isAudioTrackSetPlaybackParamsError(IllegalArgumentException e) {
+ if (e.getStackTrace() == null || e.getStackTrace().length < 1) {
+ return false;
+ }
+ for (StackTraceElement element : e.getStackTrace()) {
+ String elementString = element.toString();
+ if (elementString.startsWith("android.media.AudioTrack.setPlaybackParams")) {
+ return true;
+ }
+ }
+ return false;
+ }
+} \ No newline at end of file
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioClock.java b/src/com/android/tv/tuner/exoplayer/ac3/AudioClock.java
index ae6f2e91..600c2c88 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioClock.java
+++ b/src/com/android/tv/tuner/exoplayer/ac3/AudioClock.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.ac3;
+package com.android.tv.tuner.exoplayer.ac3;
+
+import com.android.tv.common.SoftPreconditions;
import android.os.SystemClock;
@@ -39,6 +41,9 @@ import android.os.SystemClock;
*/
private long mDeltaUs;
+ private float mPlaybackSpeed = 1.0f;
+ private long mDeltaUpdatedTimeUs;
+
/**
* Starts the clock. Does nothing if the clock is already started.
*/
@@ -46,6 +51,7 @@ import android.os.SystemClock;
if (!mStarted) {
mStarted = true;
mDeltaUs = elapsedRealtimeMinus(mPositionUs);
+ mDeltaUpdatedTimeUs = SystemClock.elapsedRealtime() * 1000;
}
}
@@ -65,13 +71,34 @@ import android.os.SystemClock;
public void setPositionUs(long timeUs) {
this.mPositionUs = timeUs;
mDeltaUs = elapsedRealtimeMinus(timeUs);
+ mDeltaUpdatedTimeUs = SystemClock.elapsedRealtime() * 1000;
}
/**
* @return The current position in microseconds.
*/
public long getPositionUs() {
- return mStarted ? elapsedRealtimeMinus(mDeltaUs) : mPositionUs;
+ if (!mStarted) {
+ return mPositionUs;
+ }
+ if (mPlaybackSpeed != 1.0f) {
+ long elapsedTimeFromPlaybackSpeedChanged = SystemClock.elapsedRealtime() * 1000
+ - mDeltaUpdatedTimeUs;
+ return elapsedRealtimeMinus(mDeltaUs)
+ + (long) ((mPlaybackSpeed - 1.0f) * elapsedTimeFromPlaybackSpeedChanged);
+ } else {
+ return elapsedRealtimeMinus(mDeltaUs);
+ }
+ }
+
+ /**
+ * Sets playback speed. {@code speed} should be positive.
+ */
+ public void setPlaybackSpeed(float speed) {
+ SoftPreconditions.checkState(speed > 0);
+ mDeltaUs = elapsedRealtimeMinus(getPositionUs());
+ mDeltaUpdatedTimeUs = SystemClock.elapsedRealtime() * 1000;
+ mPlaybackSpeed = speed;
}
private long elapsedRealtimeMinus(long toSubtractUs) {
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackMonitor.java b/src/com/android/tv/tuner/exoplayer/ac3/AudioTrackMonitor.java
index fa2250d2..bfdf08ac 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackMonitor.java
+++ b/src/com/android/tv/tuner/exoplayer/ac3/AudioTrackMonitor.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.ac3;
+package com.android.tv.tuner.exoplayer.ac3;
import android.os.SystemClock;
import android.util.Log;
@@ -98,8 +98,8 @@ public class AudioTrackMonitor {
long now = SystemClock.elapsedRealtime();
if (mExpireMs != 0 && now >= mExpireMs) {
if (DEBUG) {
- long sampleDuration = (mTotalCount - 1) * Ac3TrackRenderer.AC3_SAMPLE_DURATION_US
- / 1000;
+ long sampleDuration = (mTotalCount - 1) *
+ Ac3PassthroughTrackRenderer.AC3_SAMPLE_DURATION_US / 1000;
long totalDuration = now - mStartMs;
StringBuilder ptsBuilder = new StringBuilder();
ptsBuilder.append("PTS received ").append(mSampleCount).append(", ")
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackWrapper.java b/src/com/android/tv/tuner/exoplayer/ac3/AudioTrackWrapper.java
index eb5efcb9..bc3c5d00 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/AudioTrackWrapper.java
+++ b/src/com/android/tv/tuner/exoplayer/ac3/AudioTrackWrapper.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.ac3;
+package com.android.tv.tuner.exoplayer.ac3;
import android.media.MediaFormat;
@@ -41,10 +41,7 @@ public class AudioTrackWrapper {
}
public boolean isInitialized() {
- if (!mIsEnabled) {
- return false;
- }
- return mAudioTrack.isInitialized();
+ return mIsEnabled && mAudioTrack.isInitialized();
}
public void restart() {
@@ -80,10 +77,7 @@ public class AudioTrackWrapper {
}
public boolean isEnded() {
- if (!mIsEnabled) {
- return true;
- }
- return !mAudioTrack.hasPendingData();
+ return !mIsEnabled || !mAudioTrack.hasPendingData();
}
public boolean isReady() {
@@ -113,18 +107,27 @@ public class AudioTrackWrapper {
}
public void reconfigure(MediaFormat format) {
- if (!mIsEnabled) {
+ if (!mIsEnabled || format == null) {
return;
}
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+ int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+ int pcmEncoding;
+ try {
+ pcmEncoding = format.getInteger(MediaFormat.KEY_PCM_ENCODING);
+ } catch (Exception e) {
+ pcmEncoding = com.google.android.exoplayer.MediaFormat.NO_VALUE;
+ }
// TODO: Handle non-AC3 or non-passthrough audio.
- if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(format.getString(MediaFormat.KEY_MIME))
- && format.getInteger(MediaFormat.KEY_CHANNEL_COUNT) == 1) {
- // Workarounds b/25955476 .
- // Since all devices and platforms does not support AC3 mono passthrough,
- // It is safe to fake AC3 mono as AC3 stereo which is default passthrough mode.
- format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 2);
+ if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(mimeType) && channelCount != 2) {
+ // Workarounds b/25955476.
+ // Since all devices and platforms does not support passthrough for non-stereo AC3,
+ // It is safe to fake non-stereo AC3 as AC3 stereo which is default passthrough mode.
+ // In other words, the channel count should be always 2.
+ channelCount = 2;
}
- mAudioTrack.configure(format, true);
+ mAudioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding);
}
public void handleDiscontinuity() {
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/CacheManager.java b/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
index 0441f288..eb596e93 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/CacheManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/BufferManager.java
@@ -14,43 +14,40 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
import android.media.MediaFormat;
import android.os.ConditionVariable;
-import android.os.HandlerThread;
-import android.support.annotation.VisibleForTesting;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.util.ArrayMap;
-import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
import com.google.android.exoplayer.SampleHolder;
+import com.android.tv.tuner.exoplayer.SampleExtractor;
+import com.android.tv.util.Utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Date;
+import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
/**
- * Manages {@link SampleCache} objects.
+ * Manages {@link SampleChunk} objects.
* <p>
- * The cache manager can be disabled, while running, if the write throughput to the associated
+ * The buffer manager can be disabled, while running, if the write throughput to the associated
* external storage is detected to be lower than a threshold {@code MINIMUM_DISK_WRITE_SPEED_MBPS}".
* This leads to restarting playback flow.
*/
-public class CacheManager {
- private static final String TAG = "CacheManager";
+public class BufferManager {
+ private static final String TAG = "BufferManager";
private static final boolean DEBUG = false;
// Constants for the disk write speed checking
@@ -60,23 +57,23 @@ public class CacheManager {
private static final int MAXIMUM_SPEED_CHECK_COUNT = 5; // Checks only 5 times
private static final int MINIMUM_DISK_WRITE_SPEED_MBPS = 3; // 3 Megabytes per second
- private final SampleCache.SampleCacheFactory mSampleCacheFactory;
- private final Map<String, SortedMap<Long, SampleCache>> mCacheMap = new ArrayMap<>();
- private final Map<String, EvictListener> mEvictListeners = new ArrayMap<>();
+ private final SampleChunk.SampleChunkCreator mSampleChunkCreator;
+ // Maps from track name to a map which maps from starting position to {@link SampleChunk}.
+ private final Map<String, SortedMap<Long, SampleChunk>> mChunkMap = new ArrayMap<>();
+ private final Map<String, Long> mStartPositionMap = new ArrayMap<>();
+ private final Map<String, ChunkEvictedListener> mEvictListeners = new ArrayMap<>();
private final StorageManager mStorageManager;
- private final HandlerThread mIoHandlerThread = new HandlerThread(TAG);
- private long mCacheSize = 0;
- private final CacheSet mPendingDelete = new CacheSet();
- private final CacheListener mCacheListener = new CacheListener() {
+ private long mBufferSize = 0;
+ private final EvictChunkQueueMap mPendingDelete = new EvictChunkQueueMap();
+ private final SampleChunk.ChunkCallback mChunkCallback = new SampleChunk.ChunkCallback() {
@Override
- public void onWrite(SampleCache cache) {
- mCacheSize += cache.getSize();
+ public void onChunkWrite(SampleChunk chunk) {
+ mBufferSize += chunk.getSize();
}
@Override
- public void onDelete(SampleCache cache) {
- mPendingDelete.remove(cache);
- mCacheSize -= cache.getSize();
+ public void onChunkDelete(SampleChunk chunk) {
+ mBufferSize -= chunk.getSize();
}
};
@@ -84,31 +81,27 @@ public class CacheManager {
private int mMinSampleSizeForSpeedCheck = MINIMUM_SAMPLE_SIZE_FOR_SPEED_CHECK;
private long mTotalWriteSize;
private long mTotalWriteTimeNs;
+ private float mWriteBandwidth = 0.0f;
private volatile int mSpeedCheckCount;
private boolean mDisabled = false;
- public interface CacheListener {
- void onWrite(SampleCache cache);
- void onDelete(SampleCache cache);
- }
-
- public interface EvictListener {
- void onCacheEvicted(String id, long createdTimeMs);
+ public interface ChunkEvictedListener {
+ void onChunkEvicted(String id, long createdTimeMs);
}
-
/**
* Handles I/O
- * between CacheManager and {@link com.android.usbtuner.exoplayer.SampleExtractor}.
+ * between BufferManager and {@link SampleExtractor}.
*/
public interface SampleBuffer {
/**
* Initializes SampleBuffer.
* @param Ids track identifiers for storage read/write.
- * @param mediaFormats meta-data for each track, this will be saved to storage in recording.
+ * @param mediaFormats meta-data for each track.
* @throws IOException
*/
- void init(@NonNull List<String> Ids, @Nullable List<MediaFormat> mediaFormats)
+ void init(@NonNull List<String> Ids,
+ @NonNull List<com.google.android.exoplayer.MediaFormat> mediaFormats)
throws IOException;
/**
@@ -140,11 +133,12 @@ public class CacheManager {
/**
* Handles when write speed is slow.
+ * @throws IOException
*/
- void handleWriteSpeedSlow();
+ void handleWriteSpeedSlow() throws IOException;
/**
- * Sets the flag when EoS was met.
+ * Sets the flag when EoS was reached.
*/
void setEos();
@@ -174,21 +168,22 @@ public class CacheManager {
/**
* Cleans up and releases everything.
+ * @throws IOException
*/
- void release();
+ void release() throws IOException;
}
/**
- * Storage configuration and policy manager for {@link CacheManager}
+ * Storage configuration and policy manager for {@link BufferManager}
*/
public interface StorageManager {
/**
- * Provides eligible storage directory for {@link CacheManager}.
+ * Provides eligible storage directory for {@link BufferManager}.
*
- * @return a directory to save cache chunks and meta files
+ * @return a directory to save buffer(chunks) and meta files
*/
- File getCacheDir();
+ File getBufferDir();
/**
* Cleans up storage.
@@ -205,12 +200,12 @@ public class CacheManager {
/**
* Informs whether the storage usage exceeds pre-determined size.
*
- * @param cacheSize the current total usage of Storage in bytes.
+ * @param bufferSize the current total usage of Storage in bytes.
* @param pendingDelete the current storage usage which will be deleted in near future by
* bytes
* @return {@code true} if it reached pre-determined max size
*/
- boolean reachedStorageMax(long cacheSize, long pendingDelete);
+ boolean reachedStorageMax(long bufferSize, long pendingDelete);
/**
* Informs whether the storage has enough remained space.
@@ -226,7 +221,7 @@ public class CacheManager {
*
* @param isAudio {@code true} if it is for audio track
* @return {@link Pair} of track name & {@link MediaFormat}
- * @throws {@link java.io.IOException}
+ * @throws IOException
*/
Pair<String, MediaFormat> readTrackInfoFile(boolean isAudio) throws IOException;
@@ -234,8 +229,8 @@ public class CacheManager {
* Reads sample indexes for each written sample from storage.
*
* @param trackId track name
- * @return
- * @throws {@link java.io.IOException}
+ * @return indexes of the specified track
+ * @throws IOException
*/
ArrayList<Long> readIndexFile(String trackId) throws IOException;
@@ -245,7 +240,7 @@ public class CacheManager {
* @param trackId track name
* @param format {@link android.media.MediaFormat} of the track
* @param isAudio {@code true} if it is for audio track
- * @throws {@link java.io.IOException}
+ * @throws IOException
*/
void writeTrackInfoFile(String trackId, MediaFormat format, boolean isAudio)
throws IOException;
@@ -254,189 +249,245 @@ public class CacheManager {
* Writes index file to storage.
*
* @param trackName track name
- * @param index {@link SampleCache} container
- * @throws {@link java.io.IOException}
+ * @param index {@link SampleChunk} container
+ * @throws IOException
*/
- void writeIndexFile(String trackName, SortedMap<Long, SampleCache> index)
+ void writeIndexFile(String trackName, SortedMap<Long, SampleChunk> index)
throws IOException;
}
- private static class CacheSet {
- private final Set<SampleCache> mCaches = new ArraySet<>();
+ private static class EvictChunkQueueMap {
+ private final Map<String, LinkedList<SampleChunk>> mEvictMap = new ArrayMap<>();
+ private long mSize;
- public synchronized void add(SampleCache cache) {
- mCaches.add(cache);
+ private void init(String key) {
+ mEvictMap.put(key, new LinkedList<>());
}
- public synchronized void remove(SampleCache cache) {
- mCaches.remove(cache);
+ private void add(String key, SampleChunk chunk) {
+ LinkedList<SampleChunk> queue = mEvictMap.get(key);
+ if (queue != null) {
+ mSize += chunk.getSize();
+ queue.add(chunk);
+ }
}
- public synchronized long getSize() {
- long size = 0;
- for (SampleCache cache : mCaches) {
- size += cache.getSize();
+ private SampleChunk poll(String key, long startPositionUs) {
+ LinkedList<SampleChunk> queue = mEvictMap.get(key);
+ if (queue != null) {
+ SampleChunk chunk = queue.peek();
+ if (chunk != null && chunk.getStartPositionUs() < startPositionUs) {
+ mSize -= chunk.getSize();
+ return queue.poll();
+ }
}
- return size;
+ return null;
+ }
+
+ private long getSize() {
+ return mSize;
+ }
+
+ private void release() {
+ for (Map.Entry<String, LinkedList<SampleChunk>> entry : mEvictMap.entrySet()) {
+ for (SampleChunk chunk : entry.getValue()) {
+ SampleChunk.IoState.release(chunk, true);
+ }
+ }
+ mEvictMap.clear();
+ mSize = 0;
}
}
- public CacheManager(StorageManager storageManager) {
- this(storageManager, new SampleCache.SampleCacheFactory());
+ public BufferManager(StorageManager storageManager) {
+ this(storageManager, new SampleChunk.SampleChunkCreator());
}
- public CacheManager(StorageManager storageManager,
- SampleCache.SampleCacheFactory sampleCacheFactory) {
+ public BufferManager(StorageManager storageManager,
+ SampleChunk.SampleChunkCreator sampleChunkCreator) {
mStorageManager = storageManager;
- mSampleCacheFactory = sampleCacheFactory;
- clearCache(true);
- mIoHandlerThread.start();
+ mSampleChunkCreator = sampleChunkCreator;
+ clearBuffer(true);
}
- public void registerEvictListener(String id, EvictListener evictListener) {
- mEvictListeners.put(id, evictListener);
+ public void registerChunkEvictedListener(String id, ChunkEvictedListener listener) {
+ mEvictListeners.put(id, listener);
}
- public void unregisterEvictListener(String id) {
+ public void unregisterChunkEvictedListener(String id) {
mEvictListeners.remove(id);
}
- private void clearCache(boolean deleteFiles) {
- mCacheMap.clear();
+ private void clearBuffer(boolean deleteFiles) {
+ mChunkMap.clear();
if (deleteFiles) {
mStorageManager.clearStorage();
}
- mCacheSize = 0;
+ mBufferSize = 0;
}
private static String getFileName(String id, long positionUs) {
- return String.format(Locale.ENGLISH, "%s_%016x.cache", id, positionUs);
+ return String.format(Locale.ENGLISH, "%s_%016x.chunk", id, positionUs);
}
/**
- * Creates a new {@link SampleCache} for caching samples.
+ * Creates a new {@link SampleChunk} for caching samples.
*
* @param id the name of the track
- * @param positionUs starting position of the {@link SampleCache} in micro seconds.
+ * @param positionUs starting position of the {@link SampleChunk} in micro seconds.
* @param samplePool {@link SamplePool} for the fast creation of samples.
- * @return returns the created {@link SampleCache}.
- * @throws {@link java.io.IOException}
+ * @return returns the created {@link SampleChunk}.
+ * @throws IOException
*/
- public SampleCache createNewWriteFile(String id, long positionUs, SamplePool samplePool)
- throws IOException {
- if (!maybeEvictCache()) {
+ public SampleChunk createNewWriteFile(String id, long positionUs,
+ SamplePool samplePool) throws IOException {
+ if (!maybeEvictChunk()) {
throw new IOException("Not enough storage space");
}
- SortedMap<Long, SampleCache> map = mCacheMap.get(id);
+ SortedMap<Long, SampleChunk> map = mChunkMap.get(id);
if (map == null) {
map = new TreeMap<>();
- mCacheMap.put(id, map);
+ mChunkMap.put(id, map);
+ mStartPositionMap.put(id, positionUs);
+ mPendingDelete.init(id);
}
- File file = new File(mStorageManager.getCacheDir(), getFileName(id, positionUs));
- SampleCache sampleCache = mSampleCacheFactory.createSampleCache(samplePool, file,
- positionUs, mCacheListener, mIoHandlerThread.getLooper());
- map.put(positionUs, sampleCache);
- return sampleCache;
+ File file = new File(mStorageManager.getBufferDir(), getFileName(id, positionUs));
+ SampleChunk sampleChunk = mSampleChunkCreator.createSampleChunk(samplePool, file,
+ positionUs, mChunkCallback);
+ map.put(positionUs, sampleChunk);
+ return sampleChunk;
}
/**
- * Loads a track using {@link CacheManager.StorageManager}.
+ * Loads a track using {@link BufferManager.StorageManager}.
*
* @param trackId the name of the track.
* @param samplePool {@link SamplePool} for the fast creation of samples.
- * @throws {@link java.io.IOException}
+ * @throws IOException
*/
- public void loadTrackFormStorage(String trackId, SamplePool samplePool) throws IOException {
+ public void loadTrackFromStorage(String trackId, SamplePool samplePool) throws IOException {
ArrayList<Long> keyPositions = mStorageManager.readIndexFile(trackId);
+ long startPositionUs = keyPositions.size() > 0 ? keyPositions.get(0) : 0;
- // TODO: notify the end position
- SortedMap<Long, SampleCache> map = mCacheMap.get(trackId);
+ SortedMap<Long, SampleChunk> map = mChunkMap.get(trackId);
if (map == null) {
map = new TreeMap<>();
- mCacheMap.put(trackId, map);
+ mChunkMap.put(trackId, map);
+ mStartPositionMap.put(trackId, startPositionUs);
+ mPendingDelete.init(trackId);
}
- SampleCache cache = null;
+ SampleChunk chunk = null;
for (long positionUs: keyPositions) {
- cache = mSampleCacheFactory.createSampleCacheFromFile(samplePool,
- mStorageManager.getCacheDir(), getFileName(trackId, positionUs), positionUs,
- mCacheListener, mIoHandlerThread.getLooper(), cache);
- map.put(positionUs, cache);
+ chunk = mSampleChunkCreator.loadSampleChunkFromFile(samplePool,
+ mStorageManager.getBufferDir(), getFileName(trackId, positionUs), positionUs,
+ mChunkCallback, chunk);
+ map.put(positionUs, chunk);
}
}
/**
- * Finds a {@link SampleCache} for the specified track name and the position.
+ * Finds a {@link SampleChunk} for the specified track name and the position.
*
* @param id the name of the track.
* @param positionUs the position.
- * @return returns the found {@link SampleCache}.
+ * @return returns the found {@link SampleChunk}.
*/
- public SampleCache getReadFile(String id, long positionUs) {
- SortedMap<Long, SampleCache> map = mCacheMap.get(id);
+ public SampleChunk getReadFile(String id, long positionUs) {
+ SortedMap<Long, SampleChunk> map = mChunkMap.get(id);
if (map == null) {
return null;
}
- SampleCache sampleCache;
- SortedMap<Long, SampleCache> headMap = map.headMap(positionUs + 1);
+ SampleChunk sampleChunk;
+ SortedMap<Long, SampleChunk> headMap = map.headMap(positionUs + 1);
if (!headMap.isEmpty()) {
- sampleCache = headMap.get(headMap.lastKey());
+ sampleChunk = headMap.get(headMap.lastKey());
} else {
- sampleCache = map.get(map.firstKey());
+ sampleChunk = map.get(map.firstKey());
}
- return sampleCache;
+ return sampleChunk;
}
- private boolean maybeEvictCache() {
+ /**
+ * Evicts chunks which are ready to be evicted for the specified track
+ *
+ * @param id the specified track
+ * @param earlierThanPositionUs the start position of the {@link SampleChunk}
+ * should be earlier than
+ */
+ public void evictChunks(String id, long earlierThanPositionUs) {
+ SampleChunk chunk = null;
+ while ((chunk = mPendingDelete.poll(id, earlierThanPositionUs)) != null) {
+ SampleChunk.IoState.release(chunk, !mStorageManager.isPersistent()) ;
+ }
+ }
+
+ /**
+ * Returns the start position of the specified track in micro seconds.
+ *
+ * @param id the specified track
+ */
+ public long getStartPositionUs(String id) {
+ Long ret = mStartPositionMap.get(id);
+ return ret == null ? 0 : ret;
+ }
+
+ private boolean maybeEvictChunk() {
long pendingDelete = mPendingDelete.getSize();
- while (mStorageManager.reachedStorageMax(mCacheSize, pendingDelete)
+ while (mStorageManager.reachedStorageMax(mBufferSize, pendingDelete)
|| !mStorageManager.hasEnoughBuffer(pendingDelete)) {
if (mStorageManager.isPersistent()) {
- // Since cache is persistent, we cannot evict caches.
+ // Since chunks are persistent, we cannot evict chunks.
return false;
}
- SortedMap<Long, SampleCache> earliestCacheMap = null;
- SampleCache earliestCache = null;
- String earliestCacheId = null;
- for (Map.Entry<String, SortedMap<Long, SampleCache>> entry : mCacheMap.entrySet()) {
- SortedMap<Long, SampleCache> map = entry.getValue();
+ SortedMap<Long, SampleChunk> earliestChunkMap = null;
+ SampleChunk earliestChunk = null;
+ String earliestChunkId = null;
+ for (Map.Entry<String, SortedMap<Long, SampleChunk>> entry : mChunkMap.entrySet()) {
+ SortedMap<Long, SampleChunk> map = entry.getValue();
if (map.isEmpty()) {
continue;
}
- SampleCache cache = map.get(map.firstKey());
- if (earliestCache == null
- || cache.getCreatedTimeMs() < earliestCache.getCreatedTimeMs()) {
- earliestCacheMap = map;
- earliestCache = cache;
- earliestCacheId = entry.getKey();
+ SampleChunk chunk = map.get(map.firstKey());
+ if (earliestChunk == null
+ || chunk.getCreatedTimeMs() < earliestChunk.getCreatedTimeMs()) {
+ earliestChunkMap = map;
+ earliestChunk = chunk;
+ earliestChunkId = entry.getKey();
}
}
- if (earliestCache == null) {
+ if (earliestChunk == null) {
break;
}
- mPendingDelete.add(earliestCache);
- earliestCache.delete();
- earliestCacheMap.remove(earliestCache.getStartPositionUs());
+ mPendingDelete.add(earliestChunkId, earliestChunk);
+ earliestChunkMap.remove(earliestChunk.getStartPositionUs());
if (DEBUG) {
- Log.d(TAG, String.format("cacheSize = %d; pendingDelete = %b; "
- + "earliestCache size = %d; %s@%d (%s)",
- mCacheSize, pendingDelete, earliestCache.getSize(), earliestCacheId,
- earliestCache.getStartPositionUs(),
- new SimpleDateFormat().format(new Date(earliestCache.getCreatedTimeMs()))));
+ Log.d(TAG, String.format("bufferSize = %d; pendingDelete = %b; "
+ + "earliestChunk size = %d; %s@%d (%s)",
+ mBufferSize, pendingDelete, earliestChunk.getSize(), earliestChunkId,
+ earliestChunk.getStartPositionUs(),
+ Utils.toIsoDateTimeString(earliestChunk.getCreatedTimeMs())));
}
- EvictListener listener = mEvictListeners.get(earliestCacheId);
+ ChunkEvictedListener listener = mEvictListeners.get(earliestChunkId);
if (listener != null) {
- listener.onCacheEvicted(earliestCacheId, earliestCache.getCreatedTimeMs());
+ listener.onChunkEvicted(earliestChunkId, earliestChunk.getCreatedTimeMs());
}
pendingDelete = mPendingDelete.getSize();
}
+ for (Map.Entry<String, SortedMap<Long, SampleChunk>> entry : mChunkMap.entrySet()) {
+ SortedMap<Long, SampleChunk> map = entry.getValue();
+ if (map.isEmpty()) {
+ continue;
+ }
+ mStartPositionMap.put(entry.getKey(), map.firstKey());
+ }
return true;
}
/**
* Reads track information which includes {@link MediaFormat}.
*
- * @return returns all track information which is found by {@link CacheManager.StorageManager}.
- * @throws {@link java.io.IOException}
+ * @return returns all track information which is found by {@link BufferManager.StorageManager}.
+ * @throws IOException
*/
public ArrayList<Pair<String, MediaFormat>> readTrackInfoFiles() throws IOException {
ArrayList<Pair<String, MediaFormat>> trackInfos = new ArrayList<>();
@@ -459,27 +510,25 @@ public class CacheManager {
*
* @param audio audio information.
* @param video video information.
+ * @throws IOException
*/
- public void writeMetaFiles(Pair<String, MediaFormat> audio, Pair<String, MediaFormat> video) {
- try {
- if (audio != null) {
- mStorageManager.writeTrackInfoFile(audio.first, audio.second, true);
- SortedMap<Long, SampleCache> map = mCacheMap.get(audio.first);
- if (map == null) {
- throw new IOException("Audio track index missing");
- }
- mStorageManager.writeIndexFile(audio.first, map);
+ public void writeMetaFiles(Pair<String, MediaFormat> audio, Pair<String, MediaFormat> video)
+ throws IOException {
+ if (audio != null) {
+ mStorageManager.writeTrackInfoFile(audio.first, audio.second, true);
+ SortedMap<Long, SampleChunk> map = mChunkMap.get(audio.first);
+ if (map == null) {
+ throw new IOException("Audio track index missing");
}
- if (video != null) {
- mStorageManager.writeTrackInfoFile(video.first, video.second, false);
- SortedMap<Long, SampleCache> map = mCacheMap.get(video.first);
- if (map == null) {
- throw new IOException("Video track index missing");
- }
- mStorageManager.writeIndexFile(video.first, map);
+ mStorageManager.writeIndexFile(audio.first, map);
+ }
+ if (video != null) {
+ mStorageManager.writeTrackInfoFile(video.first, video.second, false);
+ SortedMap<Long, SampleChunk> map = mChunkMap.get(video.first);
+ if (map == null) {
+ throw new IOException("Video track index missing");
}
- } catch (IOException e) {
- // TODO: throw exception and notify this failure properly.
+ mStorageManager.writeIndexFile(video.first, map);
}
}
@@ -492,31 +541,23 @@ public class CacheManager {
}
/**
- * Cleans up the specified track.
- *
- * @param trackId the name of the track.
+ * Releases all the resources.
*/
- public void clearTrack(String trackId) {
- SortedMap<Long, SampleCache> map = mCacheMap.get(trackId);
- if (map == null) {
- Log.w(TAG, "Cache with specified ID (" + trackId + ") not found");
- return;
- }
- for (SampleCache cache : map.values()) {
- cache.clear();
- cache.close();
- if (!mStorageManager.isPersistent()) {
- cache.delete();
+ public void release() {
+ mPendingDelete.release();
+ for (Map.Entry<String, SortedMap<Long, SampleChunk>> entry : mChunkMap.entrySet()) {
+ for (SampleChunk chunk : entry.getValue().values()) {
+ SampleChunk.IoState.release(chunk, !mStorageManager.isPersistent());
}
}
- mCacheMap.remove(trackId);
- if (mCacheMap.isEmpty() && mClosed) {
- mIoHandlerThread.quitSafely();
- clearCache(!mStorageManager.isPersistent());
+ mChunkMap.clear();
+ if (mClosed) {
+ clearBuffer(!mStorageManager.isPersistent());
}
}
- private void resetWriteStat() {
+ private void resetWriteStat(float writeBandwidth) {
+ mWriteBandwidth = writeBandwidth;
mTotalWriteSize = 0;
mTotalWriteTimeNs = 0;
}
@@ -546,8 +587,8 @@ public class CacheManager {
return false;
}
mSpeedCheckCount++;
- float megabytePerSecond = getWriteBandwidth();
- resetWriteStat();
+ float megabytePerSecond = calculateWriteBandwidth();
+ resetWriteStat(megabytePerSecond);
if (DEBUG) {
Log.d(TAG, "Measured disk write performance: " + megabytePerSecond + "MBps");
}
@@ -555,9 +596,14 @@ public class CacheManager {
}
/**
- * Returns the disk write speed in megabytes per second.
+ * Returns recent write bandwidth in MBps. If recent bandwidth is not available,
+ * returns {float -1.0f}.
*/
- private float getWriteBandwidth() {
+ public float getWriteBandwidth() {
+ return mWriteBandwidth == 0.0f ? -1.0f : mWriteBandwidth;
+ }
+
+ private float calculateWriteBandwidth() {
if (mTotalWriteTimeNs == 0) {
return -1;
}
@@ -565,21 +611,22 @@ public class CacheManager {
}
/**
- * Marks {@link CacheManger} object disabled to prevent it from the future use.
+ * Marks {@link BufferManager} object disabled to prevent it from the future use.
*/
public void disable() {
mDisabled = true;
}
/**
- * Returns if {@link CacheManger} object is disabled.
+ * Returns if {@link BufferManager} object is disabled.
*/
public boolean isDisabled() {
return mDisabled;
}
/**
- * Returns if {@link CacheManager} has checked the write speed, which is suitable for Trickplay.
+ * Returns if {@link BufferManager} has checked the write speed,
+ * which is suitable for Trickplay.
*/
@VisibleForTesting
public boolean hasSpeedCheckDone() {
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/DvrStorageManager.java b/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
index b2b601ff..6a0502a7 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/DvrStorageManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/DvrStorageManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
import android.media.MediaFormat;
import android.util.Pair;
@@ -33,7 +33,7 @@ import java.util.SortedMap;
/**
* Manages DVR storage.
*/
-public class DvrStorageManager implements CacheManager.StorageManager {
+public class DvrStorageManager implements BufferManager.StorageManager {
// TODO: make serializable classes and use protobuf after internal data structure is finalized.
private static final String KEY_PIXEL_WIDTH_HEIGHT_RATIO =
@@ -47,29 +47,32 @@ public class DvrStorageManager implements CacheManager.StorageManager {
private static final int NO_VALUE = -1;
private static final long NO_VALUE_LONG = -1L;
- private final File mCacheDir;
+ private final File mBufferDir;
// {@code true} when this is for recording, {@code false} when this is for replaying.
private final boolean mIsRecording;
public DvrStorageManager(File file, boolean isRecording) {
- mCacheDir = file;
- mCacheDir.mkdirs();
+ mBufferDir = file;
+ mBufferDir.mkdirs();
mIsRecording = isRecording;
}
@Override
public void clearStorage() {
if (mIsRecording) {
- for (File file : mCacheDir.listFiles()) {
- file.delete();
+ File[] files = mBufferDir.listFiles();
+ if (files != null && files.length > 0) {
+ for (File file : files) {
+ file.delete();
+ }
}
}
}
@Override
- public File getCacheDir() {
- return mCacheDir;
+ public File getBufferDir() {
+ return mBufferDir;
}
@Override
@@ -78,13 +81,13 @@ public class DvrStorageManager implements CacheManager.StorageManager {
}
@Override
- public boolean reachedStorageMax(long cacheSize, long pendingDelete) {
+ public boolean reachedStorageMax(long bufferSize, long pendingDelete) {
return false;
}
@Override
public boolean hasEnoughBuffer(long pendingDelete) {
- return !mIsRecording || mCacheDir.getUsableSpace() >= MIN_BUFFER_BYTES;
+ return !mIsRecording || mBufferDir.getUsableSpace() >= MIN_BUFFER_BYTES;
}
private void readFormatInt(DataInputStream in, MediaFormat format, String key)
@@ -153,7 +156,7 @@ public class DvrStorageManager implements CacheManager.StorageManager {
@Override
public Pair<String, MediaFormat> readTrackInfoFile(boolean isAudio) throws IOException {
- File file = new File(getCacheDir(), (isAudio ? "audio" : "video") + META_FILE_SUFFIX);
+ File file = new File(getBufferDir(), (isAudio ? "audio" : "video") + META_FILE_SUFFIX);
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
String name = readString(in);
MediaFormat format = new MediaFormat();
@@ -175,7 +178,7 @@ public class DvrStorageManager implements CacheManager.StorageManager {
@Override
public ArrayList<Long> readIndexFile(String trackId) throws IOException {
ArrayList<Long> indices = new ArrayList<>();
- File file = new File(getCacheDir(), trackId + IDX_FILE_SUFFIX);
+ File file = new File(getBufferDir(), trackId + IDX_FILE_SUFFIX);
try (DataInputStream in = new DataInputStream(new FileInputStream(file))) {
long count = in.readLong();
for (long i = 0; i < count; ++i) {
@@ -253,7 +256,7 @@ public class DvrStorageManager implements CacheManager.StorageManager {
@Override
public void writeTrackInfoFile(String trackId, MediaFormat format, boolean isAudio)
throws IOException {
- File file = new File(getCacheDir(), (isAudio ? "audio" : "video") + META_FILE_SUFFIX);
+ File file = new File(getBufferDir(), (isAudio ? "audio" : "video") + META_FILE_SUFFIX);
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(file))) {
writeString(out, trackId);
writeFormatString(out, format, MediaFormat.KEY_MIME);
@@ -271,9 +274,9 @@ public class DvrStorageManager implements CacheManager.StorageManager {
}
@Override
- public void writeIndexFile(String trackName, SortedMap<Long, SampleCache> index)
+ public void writeIndexFile(String trackName, SortedMap<Long, SampleChunk> index)
throws IOException {
- File indexFile = new File(getCacheDir(), trackName + IDX_FILE_SUFFIX);
+ File indexFile = new File(getBufferDir(), trackName + IDX_FILE_SUFFIX);
try (DataOutputStream out = new DataOutputStream(new FileOutputStream(indexFile))) {
out.writeLong(index.size());
for (Long key : index.keySet()) {
diff --git a/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java b/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
new file mode 100644
index 00000000..4869b49f
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/buffer/RecordingSampleBuffer.java
@@ -0,0 +1,306 @@
+/*
+ * 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.ConditionVariable;
+import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+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.tvinput.PlaybackBufferListener;
+import com.android.tv.tuner.exoplayer.SampleExtractor;
+
+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.concurrent.TimeUnit;
+
+/**
+ * Handles I/O between {@link SampleExtractor} and
+ * {@link BufferManager}.Reads & writes samples from/to {@link SampleChunk} which is backed
+ * by physical storage.
+ */
+public class RecordingSampleBuffer implements BufferManager.SampleBuffer,
+ BufferManager.ChunkEvictedListener {
+ private static final String TAG = "RecordingSampleBuffer";
+
+ @IntDef({BUFFER_REASON_LIVE_PLAYBACK, BUFFER_REASON_RECORDED_PLAYBACK, BUFFER_REASON_RECORDING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface BufferReason {}
+
+ /**
+ * A buffer reason for live-stream playback.
+ */
+ public static final int BUFFER_REASON_LIVE_PLAYBACK = 0;
+
+ /**
+ * A buffer reason for playback of a recorded program.
+ */
+ public static final int BUFFER_REASON_RECORDED_PLAYBACK = 1;
+
+ /**
+ * A buffer reason for recording a program.
+ */
+ public static final int BUFFER_REASON_RECORDING = 2;
+
+ /**
+ * The duration of a chunk of samples, {@link SampleChunk}.
+ */
+ static final long CHUNK_DURATION_US = TimeUnit.MILLISECONDS.toMicros(500);
+ private static final long BUFFER_WRITE_TIMEOUT_MS = 10 * 1000; // 10 seconds
+ private static final long BUFFER_NEEDED_US =
+ 1000L * Math.max(MpegTsPlayer.MIN_BUFFER_MS, MpegTsPlayer.MIN_REBUFFER_MS);
+
+ private final BufferManager mBufferManager;
+ private final PlaybackBufferListener mBufferListener;
+ private final @BufferReason int mBufferReason;
+
+ private int mTrackCount;
+ private boolean[] mTrackSelected;
+ private List<String> mIds;
+ private List<SampleQueue> mReadSampleQueues;
+ private final SamplePool mSamplePool = new SamplePool();
+ private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
+ private long mCurrentPlaybackPositionUs = 0;
+
+ // An error in I/O thread of {@link SampleChunkIoHelper} will be notified.
+ private volatile boolean mError;
+
+ // Eos was reached in I/O thread of {@link SampleChunkIoHelper}.
+ private volatile boolean mEos;
+ private SampleChunkIoHelper mSampleChunkIoHelper;
+ private final SampleChunkIoHelper.IoCallback mIoCallback =
+ new SampleChunkIoHelper.IoCallback() {
+ @Override
+ public void onIoReachedEos() {
+ mEos = true;
+ }
+
+ @Override
+ public void onIoError() {
+ mError = true;
+ }
+ };
+
+ /**
+ * Creates {@link BufferManager.SampleBuffer} with
+ * cached I/O backed by physical storage (e.g. trickplay,recording,recorded-playback).
+ *
+ * @param bufferManager the manager of {@link SampleChunk}
+ * @param bufferListener the listener for buffer I/O event
+ * @param enableTrickplay {@code true} when trickplay should be enabled
+ * @param bufferReason the reason for caching samples {@link RecordingSampleBuffer.BufferReason}
+ */
+ public RecordingSampleBuffer(BufferManager bufferManager, PlaybackBufferListener bufferListener,
+ boolean enableTrickplay, @BufferReason int bufferReason) {
+ mBufferManager = bufferManager;
+ mBufferListener = bufferListener;
+ if (bufferListener != null) {
+ bufferListener.onBufferStateChanged(enableTrickplay);
+ }
+ mBufferReason = bufferReason;
+ }
+
+ @Override
+ public void init(@NonNull List<String> ids, @NonNull List<MediaFormat> mediaFormats)
+ throws IOException {
+ mTrackCount = ids.size();
+ if (mTrackCount <= 0) {
+ throw new IOException("No tracks to initialize");
+ }
+ mIds = ids;
+ mTrackSelected = new boolean[mTrackCount];
+ mReadSampleQueues = new ArrayList<>();
+ mSampleChunkIoHelper = new SampleChunkIoHelper(ids, mediaFormats, mBufferReason,
+ mBufferManager, mSamplePool, mIoCallback);
+ for (int i = 0; i < mTrackCount; ++i) {
+ mReadSampleQueues.add(i, new SampleQueue(mSamplePool));
+ }
+ mSampleChunkIoHelper.init();
+ }
+
+ @Override
+ public void selectTrack(int index) {
+ if (!mTrackSelected[index]) {
+ mTrackSelected[index] = true;
+ mReadSampleQueues.get(index).clear();
+ mBufferManager.registerChunkEvictedListener(mIds.get(index),
+ RecordingSampleBuffer.this);
+ mSampleChunkIoHelper.openRead(index, mCurrentPlaybackPositionUs);
+ }
+ }
+
+ @Override
+ public void deselectTrack(int index) {
+ if (mTrackSelected[index]) {
+ mTrackSelected[index] = false;
+ mReadSampleQueues.get(index).clear();
+ mBufferManager.unregisterChunkEvictedListener(mIds.get(index));
+ }
+ }
+
+ @Override
+ public void writeSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
+ throws IOException {
+ mSampleChunkIoHelper.writeSample(index, sample, conditionVariable);
+
+ if (!conditionVariable.block(BUFFER_WRITE_TIMEOUT_MS)) {
+ Log.e(TAG, "Error: Serious delay on writing buffer");
+ conditionVariable.block();
+ }
+ }
+
+ @Override
+ public boolean isWriteSpeedSlow(int sampleSize, long writeDurationNs) {
+ if (mBufferReason == BUFFER_REASON_RECORDED_PLAYBACK) {
+ return false;
+ }
+ mBufferManager.addWriteStat(sampleSize, writeDurationNs);
+ return mBufferManager.isWriteSlow();
+ }
+
+ @Override
+ public void handleWriteSpeedSlow() throws IOException{
+ if (mBufferReason == BUFFER_REASON_RECORDING) {
+ // Recording does not need to stop because I/O speed is slow temporarily.
+ // If fixed size buffer of TsStreamer overflows, TsDataSource will reach EoS.
+ // Reaching EoS will stop recording eventually.
+ Log.w(TAG, "Disk I/O speed is slow for recording temporarily: "
+ + mBufferManager.getWriteBandwidth() + "MBps");
+ return;
+ }
+ // Disables buffering samples afterwards, and notifies the disk speed is slow.
+ Log.w(TAG, "Disk is too slow for trickplay");
+ mBufferManager.disable();
+ mBufferListener.onDiskTooSlow();
+ }
+
+ @Override
+ public void setEos() {
+ mSampleChunkIoHelper.closeWrite();
+ }
+
+ private boolean maybeReadSample(SampleQueue queue, int index) {
+ if (queue.getLastQueuedPositionUs() != null
+ && queue.getLastQueuedPositionUs() > mCurrentPlaybackPositionUs + BUFFER_NEEDED_US
+ && queue.isDurationGreaterThan(CHUNK_DURATION_US)) {
+ // The speed of queuing samples can be higher than the playback speed.
+ // If the duration of the samples in the queue is not limited,
+ // samples can be accumulated and there can be out-of-memory issues.
+ // But, the throttling should provide enough samples for the player to
+ // finish the buffering state.
+ return false;
+ }
+ SampleHolder sample = mSampleChunkIoHelper.readSample(index);
+ if (sample != null) {
+ queue.queueSample(sample);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public int readSample(int track, SampleHolder outSample) {
+ Assertions.checkState(mTrackSelected[track]);
+ maybeReadSample(mReadSampleQueues.get(track), track);
+ int result = mReadSampleQueues.get(track).dequeueSample(outSample);
+ if ((result != SampleSource.SAMPLE_READ && mEos) || mError) {
+ return SampleSource.END_OF_STREAM;
+ }
+ return result;
+ }
+
+ @Override
+ public void seekTo(long positionUs) {
+ for (int i = 0; i < mTrackCount; ++i) {
+ if (mTrackSelected[i]) {
+ mReadSampleQueues.get(i).clear();
+ mSampleChunkIoHelper.openRead(i, positionUs);
+ }
+ }
+ mLastBufferedPositionUs = positionUs;
+ }
+
+ @Override
+ public long getBufferedPositionUs() {
+ Long result = null;
+ for (int i = 0; i < mTrackCount; ++i) {
+ if (!mTrackSelected[i]) {
+ continue;
+ }
+ Long lastQueuedSamplePositionUs =
+ mReadSampleQueues.get(i).getLastQueuedPositionUs();
+ if (lastQueuedSamplePositionUs == null) {
+ // No sample has been queued.
+ result = mLastBufferedPositionUs;
+ continue;
+ }
+ if (result == null || result > lastQueuedSamplePositionUs) {
+ result = lastQueuedSamplePositionUs;
+ }
+ }
+ if (result == null) {
+ return mLastBufferedPositionUs;
+ }
+ return (mLastBufferedPositionUs = result);
+ }
+
+ @Override
+ public boolean continueBuffering(long positionUs) {
+ mCurrentPlaybackPositionUs = positionUs;
+ for (int i = 0; i < mTrackCount; ++i) {
+ if (!mTrackSelected[i]) {
+ continue;
+ }
+ SampleQueue queue = mReadSampleQueues.get(i);
+ maybeReadSample(queue, i);
+ if (queue.getLastQueuedPositionUs() == null
+ || positionUs > queue.getLastQueuedPositionUs()) {
+ // No more buffered data.
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void release() throws IOException {
+ if (mTrackCount <= 0) {
+ return;
+ }
+ if (mSampleChunkIoHelper != null) {
+ mSampleChunkIoHelper.release();
+ }
+ }
+
+ // onChunkEvictedListener
+ @Override
+ public void onChunkEvicted(String id, long createdTimeMs) {
+ if (mBufferListener != null) {
+ mBufferListener.onBufferStartTimeChanged(
+ createdTimeMs + TimeUnit.MICROSECONDS.toMillis(CHUNK_DURATION_US));
+ }
+ }
+}
diff --git a/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java
new file mode 100644
index 00000000..552caaef
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunk.java
@@ -0,0 +1,419 @@
+/*
+ * 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.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+import com.google.android.exoplayer.SampleHolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+
+/**
+ * {@link SampleChunk} stores samples into file and makes them available for read.
+ * Stored file = { Header, Sample } * N
+ * Header = sample size : int, sample flag : int, sample PTS in micro second : long
+ */
+public class SampleChunk {
+ private static final String TAG = "SampleChunk";
+ private static final boolean DEBUG = false;
+
+ private final long mCreatedTimeMs;
+ private final long mStartPositionUs;
+ private SampleChunk mNextChunk;
+
+ // Header = sample size : int, sample flag : int, sample PTS in micro second : long
+ private static final int SAMPLE_HEADER_LENGTH = 16;
+
+ private final File mFile;
+ private final ChunkCallback mChunkCallback;
+ private final SamplePool mSamplePool;
+ private RandomAccessFile mAccessFile;
+ private long mWriteOffset;
+ private boolean mWriteFinished;
+ private boolean mIsReading;
+ private boolean mIsWriting;
+
+ /**
+ * A callback for chunks being committed to permanent storage.
+ */
+ public static abstract class ChunkCallback {
+
+ /**
+ * Notifies when writing a SampleChunk is completed.
+ *
+ * @param chunk SampleChunk which is written completely
+ */
+ public void onChunkWrite(SampleChunk chunk) {
+
+ }
+
+ /**
+ * Notifies when a SampleChunk is deleted.
+ *
+ * @param chunk SampleChunk which is deleted from storage
+ */
+ public void onChunkDelete(SampleChunk chunk) {
+ }
+ }
+
+ /**
+ * A class for SampleChunk creation.
+ */
+ @VisibleForTesting
+ public static class SampleChunkCreator {
+
+ /**
+ * Returns a newly created SampleChunk to read & write samples.
+ *
+ * @param samplePool sample allocator
+ * @param file filename which will be created newly
+ * @param startPositionUs the start position of the earliest sample to be stored
+ * @param chunkCallback for total storage usage change notification
+ */
+ SampleChunk createSampleChunk(SamplePool samplePool, File file,
+ long startPositionUs, ChunkCallback chunkCallback) {
+ return new SampleChunk(samplePool, file, startPositionUs, System.currentTimeMillis(),
+ chunkCallback);
+ }
+
+ /**
+ * Returns a newly created SampleChunk which is backed by an existing file.
+ * Created SampleChunk is read-only.
+ *
+ * @param samplePool sample allocator
+ * @param bufferDir the directory where the file to read is located
+ * @param filename the filename which will be read afterwards
+ * @param startPositionUs the start position of the earliest sample in the file
+ * @param chunkCallback for total storage usage change notification
+ * @param prev the previous SampleChunk just before the newly created SampleChunk
+ * @throws IOException
+ */
+ SampleChunk loadSampleChunkFromFile(SamplePool samplePool, File bufferDir,
+ String filename, long startPositionUs, ChunkCallback chunkCallback,
+ SampleChunk prev) throws IOException {
+ File file = new File(bufferDir, filename);
+ SampleChunk chunk =
+ new SampleChunk(samplePool, file, startPositionUs, chunkCallback);
+ if (prev != null) {
+ prev.mNextChunk = chunk;
+ }
+ return chunk;
+ }
+ }
+
+ /**
+ * Handles I/O for SampleChunk.
+ * Maintains current SampleChunk and the current offset for next I/O operation.
+ */
+ static class IoState {
+ private SampleChunk mChunk;
+ private long mCurrentOffset;
+
+ private boolean equals(SampleChunk chunk, long offset) {
+ return chunk == mChunk && mCurrentOffset == offset;
+ }
+
+ /**
+ * Returns whether read I/O operation is finished.
+ */
+ boolean isReadFinished() {
+ return mChunk == null;
+ }
+
+ /**
+ * Returns the start position of the current SampleChunk
+ */
+ long getStartPositionUs() {
+ return mChunk == null ? 0 : mChunk.getStartPositionUs();
+ }
+
+ private void reset(@Nullable SampleChunk chunk) {
+ mChunk = chunk;
+ mCurrentOffset = 0;
+ }
+
+ /**
+ * Prepares for read I/O operation from a new SampleChunk.
+ *
+ * @param chunk the new SampleChunk to read from
+ * @throws IOException
+ */
+ void openRead(SampleChunk chunk) throws IOException {
+ if (mChunk != null) {
+ mChunk.closeRead();
+ }
+ chunk.openRead();
+ reset(chunk);
+ }
+
+ /**
+ * Prepares for write I/O operation to a new SampleChunk.
+ *
+ * @param chunk the new SampleChunk to write samples afterwards
+ * @throws IOException
+ */
+ void openWrite(SampleChunk chunk) throws IOException{
+ if (mChunk != null) {
+ mChunk.closeWrite(chunk);
+ }
+ chunk.openWrite();
+ reset(chunk);
+ }
+
+ /**
+ * Reads a sample if it is available.
+ *
+ * @return Returns a sample if it is available, null otherwise.
+ * @throws IOException
+ */
+ SampleHolder read() throws IOException {
+ if (mChunk != null && mChunk.isReadFinished(this)) {
+ SampleChunk next = mChunk.mNextChunk;
+ mChunk.closeRead();
+ if (next != null) {
+ next.openRead();
+ }
+ reset(next);
+ }
+ if (mChunk != null) {
+ try {
+ return mChunk.read(this);
+ } catch (IllegalStateException e) {
+ // Write is finished and there is no additional buffer to read.
+ Log.w(TAG, "Tried to read sample over EOS.");
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Writes a sample.
+ *
+ * @param sample to write
+ * @param nextChunk if this is {@code null} writes at the current SampleChunk,
+ * otherwise close current SampleChunk and writes at this
+ * @throws IOException
+ */
+ void write(SampleHolder sample, SampleChunk nextChunk)
+ throws IOException {
+ if (nextChunk != null) {
+ if (mChunk == null || mChunk.mNextChunk != null) {
+ throw new IllegalStateException("Requested write for wrong SampleChunk");
+ }
+ mChunk.closeWrite(nextChunk);
+ mChunk.mChunkCallback.onChunkWrite(mChunk);
+ nextChunk.openWrite();
+ reset(nextChunk);
+ }
+ mChunk.write(sample, this);
+ }
+
+ /**
+ * Finishes write I/O operation.
+ *
+ * @throws IOException
+ */
+ void closeWrite() throws IOException {
+ if (mChunk != null) {
+ mChunk.closeWrite(null);
+ }
+ }
+
+ /**
+ * Releases SampleChunk. the SampleChunk will not be used anymore.
+ *
+ * @param chunk to release
+ * @param delete {@code true} when the backed file needs to be deleted,
+ * {@code false} otherwise.
+ */
+ static void release(SampleChunk chunk, boolean delete) {
+ chunk.release(delete);
+ }
+ }
+
+ @VisibleForTesting
+ protected SampleChunk(SamplePool samplePool, File file, long startPositionUs,
+ long createdTimeMs, ChunkCallback chunkCallback) {
+ mStartPositionUs = startPositionUs;
+ mCreatedTimeMs = createdTimeMs;
+ mSamplePool = samplePool;
+ mFile = file;
+ mChunkCallback = chunkCallback;
+ }
+
+ // Constructor of SampleChunk which is backed by the given existing file.
+ private SampleChunk(SamplePool samplePool, File file, long startPositionUs,
+ ChunkCallback chunkCallback) throws IOException {
+ mStartPositionUs = startPositionUs;
+ mCreatedTimeMs = mStartPositionUs / 1000;
+ mSamplePool = samplePool;
+ mFile = file;
+ mChunkCallback = chunkCallback;
+ mWriteFinished = true;
+ }
+
+ private void openRead() throws IOException {
+ if (!mIsReading) {
+ if (mAccessFile == null) {
+ mAccessFile = new RandomAccessFile(mFile, "r");
+ }
+ if (mWriteFinished && mWriteOffset == 0) {
+ // Lazy loading of write offset, in order not to load
+ // all SampleChunk's write offset at start time of recorded playback.
+ mWriteOffset = mAccessFile.length();
+ }
+ mIsReading = true;
+ }
+ }
+
+ private void openWrite() throws IOException {
+ if (mWriteFinished) {
+ throw new IllegalStateException("Opened for write though write is already finished");
+ }
+ if (!mIsWriting) {
+ if (mIsReading) {
+ throw new IllegalStateException("Write is requested for "
+ + "an already opened SampleChunk");
+ }
+ mAccessFile = new RandomAccessFile(mFile, "rw");
+ mIsWriting = true;
+ }
+ }
+
+ private void CloseAccessFileIfNeeded() throws IOException {
+ if (!mIsReading && !mIsWriting) {
+ try {
+ if (mAccessFile != null) {
+ mAccessFile.close();
+ }
+ } finally {
+ mAccessFile = null;
+ }
+ }
+ }
+
+ private void closeRead() throws IOException{
+ if (mIsReading) {
+ mIsReading = false;
+ CloseAccessFileIfNeeded();
+ }
+ }
+
+ private void closeWrite(SampleChunk nextChunk)
+ throws IOException {
+ if (mIsWriting) {
+ mNextChunk = nextChunk;
+ mIsWriting = false;
+ mWriteFinished = true;
+ CloseAccessFileIfNeeded();
+ }
+ }
+
+ private boolean isReadFinished(IoState state) {
+ return mWriteFinished && state.equals(this, mWriteOffset);
+ }
+
+ private SampleHolder read(IoState state) throws IOException {
+ if (mAccessFile == null || state.mChunk != this) {
+ throw new IllegalStateException("Requested read for wrong SampleChunk");
+ }
+ long offset = state.mCurrentOffset;
+ if (offset >= mWriteOffset) {
+ if (mWriteFinished) {
+ throw new IllegalStateException("Requested read for wrong range");
+ } else {
+ if (offset != mWriteOffset) {
+ Log.e(TAG, "This should not happen!");
+ }
+ return null;
+ }
+ }
+ mAccessFile.seek(offset);
+ int size = mAccessFile.readInt();
+ SampleHolder sample = mSamplePool.acquireSample(size);
+ sample.size = size;
+ sample.flags = mAccessFile.readInt();
+ sample.timeUs = mAccessFile.readLong();
+ sample.clearData();
+ sample.data.put(mAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY,
+ offset + SAMPLE_HEADER_LENGTH, sample.size));
+ offset += sample.size + SAMPLE_HEADER_LENGTH;
+ state.mCurrentOffset = offset;
+ return sample;
+ }
+
+ @VisibleForTesting
+ protected void write(SampleHolder sample, IoState state)
+ throws IOException {
+ if (mAccessFile == null || mNextChunk != null || !state.equals(this, mWriteOffset)) {
+ throw new IllegalStateException("Requested write for wrong SampleChunk");
+ }
+
+ mAccessFile.seek(mWriteOffset);
+ mAccessFile.writeInt(sample.size);
+ mAccessFile.writeInt(sample.flags);
+ mAccessFile.writeLong(sample.timeUs);
+ sample.data.position(0).limit(sample.size);
+ mAccessFile.getChannel().position(mWriteOffset + SAMPLE_HEADER_LENGTH).write(sample.data);
+ mWriteOffset += sample.size + SAMPLE_HEADER_LENGTH;
+ state.mCurrentOffset = mWriteOffset;
+ }
+
+ private void release(boolean delete) {
+ mWriteFinished = true;
+ mIsReading = mIsWriting = false;
+ try {
+ if (mAccessFile != null) {
+ mAccessFile.close();
+ }
+ } catch (IOException e) {
+ // Since the SampleChunk will not be reused, ignore exception.
+ }
+ if (delete) {
+ mFile.delete();
+ mChunkCallback.onChunkDelete(this);
+ }
+ }
+
+ /**
+ * Returns the start position.
+ */
+ public long getStartPositionUs() {
+ return mStartPositionUs;
+ }
+
+ /**
+ * Returns the creation time.
+ */
+ public long getCreatedTimeMs() {
+ return mCreatedTimeMs;
+ }
+
+ /**
+ * Returns the current size.
+ */
+ public long getSize() {
+ return mWriteOffset;
+ }
+}
diff --git a/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
new file mode 100644
index 00000000..37ae4022
--- /dev/null
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleChunkIoHelper.java
@@ -0,0 +1,406 @@
+/*
+ * 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.media.MediaCodec;
+import android.os.ConditionVariable;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.Log;
+import android.util.Pair;
+
+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.List;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+/**
+ * Handles all {@link SampleChunk} I/O operations.
+ * An I/O dedicated thread handles all I/O operations for synchronization.
+ */
+public class SampleChunkIoHelper implements Handler.Callback {
+ private static final String TAG = "SampleChunkIoHelper";
+
+ private static final int MAX_READ_BUFFER_SAMPLES = 3;
+ private static final int READ_RESCHEDULING_DELAY_MS = 10;
+
+ private static final int MSG_OPEN_READ = 1;
+ private static final int MSG_OPEN_WRITE = 2;
+ private static final int MSG_CLOSE_WRITE = 3;
+ private static final int MSG_READ = 4;
+ private static final int MSG_WRITE = 5;
+ private static final int MSG_RELEASE = 6;
+
+ private final int mTrackCount;
+ private final List<String> mIds;
+ private final List<MediaFormat> mMediaFormats;
+ private final @BufferReason int mBufferReason;
+ private final BufferManager mBufferManager;
+ private final SamplePool mSamplePool;
+ private final IoCallback mIoCallback;
+
+ private Handler mIoHandler;
+ private final ConcurrentLinkedQueue<SampleHolder> mReadSampleBuffers[];
+ private final ConcurrentLinkedQueue<SampleHolder> mHandlerReadSampleBuffers[];
+ private final long[] mWriteEndPositionUs;
+ private final SampleChunk.IoState[] mReadIoStates;
+ private final SampleChunk.IoState[] mWriteIoStates;
+ private long mBufferDurationUs = 0;
+ private boolean mWriteEnded;
+ private boolean mErrorNotified;
+ private boolean mFinished;
+
+ /**
+ * A Callback for I/O events.
+ */
+ public static abstract class IoCallback {
+
+ /**
+ * Called when there is no sample to read.
+ */
+ public void onIoReachedEos() {
+ }
+
+ /**
+ * Called when there is an irrecoverable error during I/O.
+ */
+ public void onIoError() {
+ }
+ }
+
+ private class IoParams {
+ private final int index;
+ private final long positionUs;
+ private final SampleHolder sample;
+ private final ConditionVariable conditionVariable;
+ private final ConcurrentLinkedQueue<SampleHolder> readSampleBuffer;
+
+ private IoParams(int index, long positionUs, SampleHolder sample,
+ ConditionVariable conditionVariable,
+ ConcurrentLinkedQueue<SampleHolder> readSampleBuffer) {
+ this.index = index;
+ this.positionUs = positionUs;
+ this.sample = sample;
+ this.conditionVariable = conditionVariable;
+ this.readSampleBuffer = readSampleBuffer;
+ }
+ }
+
+ /**
+ * Creates {@link SampleChunk} I/O handler.
+ *
+ * @param ids track names
+ * @param mediaFormats {@link android.media.MediaFormat} for each track
+ * @param bufferReason reason to be buffered
+ * @param bufferManager manager of {@link SampleChunk} collections
+ * @param samplePool allocator for a sample
+ * @param ioCallback listeners for I/O events
+ */
+ public SampleChunkIoHelper(List<String> ids, List<MediaFormat> mediaFormats,
+ @BufferReason int bufferReason, BufferManager bufferManager, SamplePool samplePool,
+ IoCallback ioCallback) {
+ mTrackCount = ids.size();
+ mIds = ids;
+ mMediaFormats = mediaFormats;
+ mBufferReason = bufferReason;
+ mBufferManager = bufferManager;
+ mSamplePool = samplePool;
+ mIoCallback = ioCallback;
+
+ mReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount];
+ mHandlerReadSampleBuffers = new ConcurrentLinkedQueue[mTrackCount];
+ mWriteEndPositionUs = new long[mTrackCount];
+ mReadIoStates = new SampleChunk.IoState[mTrackCount];
+ mWriteIoStates = new SampleChunk.IoState[mTrackCount];
+ for (int i = 0; i < mTrackCount; ++i) {
+ mWriteEndPositionUs[i] = RecordingSampleBuffer.CHUNK_DURATION_US;
+ mReadIoStates[i] = new SampleChunk.IoState();
+ mWriteIoStates[i] = new SampleChunk.IoState();
+ }
+ }
+
+ /**
+ * Prepares and initializes for I/O operations.
+ *
+ * @throws IOException
+ */
+ public void init() throws IOException {
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ mIoHandler = new Handler(handlerThread.getLooper(), this);
+ if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDED_PLAYBACK) {
+ for (int i = 0; i < mTrackCount; ++i) {
+ mBufferManager.loadTrackFromStorage(mIds.get(i), mSamplePool);
+ }
+ mWriteEnded = true;
+ } else {
+ for (int i = 0; i < mTrackCount; ++i) {
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_OPEN_WRITE, i));
+ }
+ }
+ }
+
+ /**
+ * Reads a sample if it is available.
+ *
+ * @param index track index
+ * @return {@code null} if a sample is not available, otherwise returns a sample
+ */
+ public SampleHolder readSample(int index) {
+ SampleHolder sample = mReadSampleBuffers[index].poll();
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_READ, index));
+ return sample;
+ }
+
+ /**
+ * Writes a sample.
+ *
+ * @param index track index
+ * @param sample to write
+ * @param conditionVariable which will be wait until the write is finished
+ * @throws IOException
+ */
+ public void writeSample(int index, SampleHolder sample,
+ ConditionVariable conditionVariable) throws IOException {
+ if (mErrorNotified) {
+ throw new IOException("Storage I/O error happened");
+ }
+ conditionVariable.close();
+ IoParams params = new IoParams(index, 0, sample, conditionVariable, null);
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_WRITE, params));
+ }
+
+ /**
+ * Starts read from the specified position.
+ *
+ * @param index track index
+ * @param positionUs the specified position
+ */
+ public void openRead(int index, long positionUs) {
+ // Old mReadSampleBuffers may have a pending read.
+ mReadSampleBuffers[index] = new ConcurrentLinkedQueue<>();
+ IoParams params = new IoParams(index, positionUs, null, null, mReadSampleBuffers[index]);
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_OPEN_READ, params));
+ }
+
+ /**
+ * Notifies writes are finished.
+ */
+ public void closeWrite() {
+ mIoHandler.sendEmptyMessage(MSG_CLOSE_WRITE);
+ }
+
+ /**
+ * Finishes I/O operations and releases all the resources.
+ * @throws IOException
+ */
+ public void release() throws IOException {
+ if (mIoHandler == null) {
+ return;
+ }
+ // Finishes all I/O operations.
+ ConditionVariable conditionVariable = new ConditionVariable();
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_RELEASE, conditionVariable));
+ conditionVariable.block();
+
+ for (int i = 0; i < mTrackCount; ++i) {
+ mBufferManager.unregisterChunkEvictedListener(mIds.get(i));
+ }
+ try {
+ if (mBufferReason == RecordingSampleBuffer.BUFFER_REASON_RECORDING && mTrackCount > 0) {
+ // Saves meta information for recording.
+ Pair<String, android.media.MediaFormat> audio = null, video = null;
+ for (int i = 0; i < mTrackCount; ++i) {
+ android.media.MediaFormat format =
+ mMediaFormats.get(i).getFrameworkMediaFormatV16();
+ format.setLong(android.media.MediaFormat.KEY_DURATION, mBufferDurationUs);
+ if (audio == null && MimeTypes.isAudio(mMediaFormats.get(i).mimeType)) {
+ audio = new Pair<>(mIds.get(i), format);
+ } else if (video == null && MimeTypes.isVideo(mMediaFormats.get(i).mimeType)) {
+ video = new Pair<>(mIds.get(i), format);
+ }
+ if (audio != null && video != null) {
+ break;
+ }
+ }
+ mBufferManager.writeMetaFiles(audio, video);
+ }
+ } finally {
+ mBufferManager.release();
+ mIoHandler.getLooper().quitSafely();
+ }
+ }
+
+ @Override
+ public boolean handleMessage(Message message) {
+ if (mFinished) {
+ return true;
+ }
+ releaseEvictedChunks();
+ try {
+ switch (message.what) {
+ case MSG_OPEN_READ:
+ doOpenRead((IoParams) message.obj);
+ return true;
+ case MSG_OPEN_WRITE:
+ doOpenWrite((int) message.obj);
+ return true;
+ case MSG_CLOSE_WRITE:
+ doCloseWrite();
+ return true;
+ case MSG_READ:
+ doRead((int) message.obj);
+ return true;
+ case MSG_WRITE:
+ doWrite((IoParams) message.obj);
+ // Since only write will increase storage, eviction will be handled here.
+ return true;
+ case MSG_RELEASE:
+ doRelease((ConditionVariable) message.obj);
+ return true;
+ }
+ } catch (IOException e) {
+ mIoCallback.onIoError();
+ mErrorNotified = true;
+ Log.e(TAG, "IoException happened", e);
+ return true;
+ }
+ return false;
+ }
+
+ private void doOpenRead(IoParams params) throws IOException {
+ int index = params.index;
+ mIoHandler.removeMessages(MSG_READ, index);
+ SampleChunk chunk = mBufferManager.getReadFile(mIds.get(index), params.positionUs);
+ if (chunk == null) {
+ String errorMessage = "Chunk ID:" + mIds.get(index) + " pos:" + params.positionUs
+ + "is not found";
+ SoftPreconditions.checkNotNull(chunk, TAG, errorMessage);
+ throw new IOException(errorMessage);
+ }
+ mReadIoStates[index].openRead(chunk);
+ if (mHandlerReadSampleBuffers[index] != null) {
+ SampleHolder sample;
+ while ((sample = mHandlerReadSampleBuffers[index].poll()) != null) {
+ mSamplePool.releaseSample(sample);
+ }
+ }
+ mHandlerReadSampleBuffers[index] = params.readSampleBuffer;
+ mIoHandler.sendMessage(mIoHandler.obtainMessage(MSG_READ, index));
+ }
+
+ private void doOpenWrite(int index) throws IOException {
+ SampleChunk chunk = mBufferManager.createNewWriteFile(mIds.get(index), 0, mSamplePool);
+ mWriteIoStates[index].openWrite(chunk);
+ }
+
+ private void doRead(int index) throws IOException {
+ mIoHandler.removeMessages(MSG_READ, index);
+ if (mHandlerReadSampleBuffers[index].size() >= MAX_READ_BUFFER_SAMPLES) {
+ // If enough samples are buffered, try again few moments later hoping that
+ // buffered samples are consumed.
+ mIoHandler.sendMessageDelayed(
+ mIoHandler.obtainMessage(MSG_READ, index), READ_RESCHEDULING_DELAY_MS);
+ } else {
+ if (mReadIoStates[index].isReadFinished()) {
+ for (int i = 0; i < mTrackCount; ++i) {
+ if (!mReadIoStates[i].isReadFinished()) {
+ return;
+ }
+ }
+ mIoCallback.onIoReachedEos();
+ return;
+ }
+ SampleHolder sample = mReadIoStates[index].read();
+ if (sample != null) {
+ mHandlerReadSampleBuffers[index].offer(sample);
+ } else {
+ // Read reached write but write is not finished yet --- wait a few moments to
+ // see if another sample is written.
+ mIoHandler.sendMessageDelayed(
+ mIoHandler.obtainMessage(MSG_READ, index),
+ READ_RESCHEDULING_DELAY_MS);
+ }
+ }
+ }
+
+ private void doWrite(IoParams params) throws IOException {
+ try {
+ if (mWriteEnded) {
+ SoftPreconditions.checkState(false);
+ return;
+ }
+ int index = params.index;
+ SampleHolder sample = params.sample;
+ SampleChunk nextChunk = null;
+ if ((sample.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
+ if (sample.timeUs > mBufferDurationUs) {
+ mBufferDurationUs = sample.timeUs;
+ }
+
+ if (sample.timeUs >= mWriteEndPositionUs[index]) {
+ nextChunk = mBufferManager.createNewWriteFile(mIds.get(index),
+ mWriteEndPositionUs[index], mSamplePool);
+ mWriteEndPositionUs[index] =
+ ((sample.timeUs / RecordingSampleBuffer.CHUNK_DURATION_US) + 1) *
+ RecordingSampleBuffer.CHUNK_DURATION_US;
+ }
+ }
+ mWriteIoStates[params.index].write(params.sample, nextChunk);
+ } finally {
+ params.conditionVariable.open();
+ }
+ }
+
+ private void doCloseWrite() throws IOException {
+ if (mWriteEnded) {
+ return;
+ }
+ mWriteEnded = true;
+ boolean readFinished = true;
+ for (int i = 0; i < mTrackCount; ++i) {
+ readFinished = readFinished && mReadIoStates[i].isReadFinished();
+ mWriteIoStates[i].closeWrite();
+ }
+ if (readFinished) {
+ mIoCallback.onIoReachedEos();
+ }
+ }
+
+ private void doRelease(ConditionVariable conditionVariable) {
+ mIoHandler.removeCallbacksAndMessages(null);
+ mFinished = true;
+ conditionVariable.open();
+ }
+
+ private void releaseEvictedChunks() {
+ if (mBufferReason != RecordingSampleBuffer.BUFFER_REASON_LIVE_PLAYBACK) {
+ return;
+ }
+ for (int i = 0; i < mTrackCount; ++i) {
+ long evictEndPositionUs = Math.min(mBufferManager.getStartPositionUs(mIds.get(i)),
+ mReadIoStates[i].getStartPositionUs());
+ mBufferManager.evictChunks(mIds.get(i), evictEndPositionUs);
+ }
+ }
+} \ No newline at end of file
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SamplePool.java b/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java
index 2c18283e..bb048e85 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SamplePool.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SamplePool.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
import com.google.android.exoplayer.SampleHolder;
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleQueue.java b/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java
index 2bddd2c0..7b098f40 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleQueue.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SampleQueue.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
import com.google.android.exoplayer.SampleHolder;
import com.google.android.exoplayer.SampleSource;
@@ -22,11 +22,12 @@ import com.google.android.exoplayer.SampleSource;
import java.util.LinkedList;
/**
- * A sample queue which reads from the cache and passes to player pipeline.
+ * A sample queue which reads from the buffer and passes to player pipeline.
*/
public class SampleQueue {
private final LinkedList<SampleHolder> mQueue = new LinkedList<>();
private final SamplePool mSamplePool;
+ private Long mLastQueuedPositionUs = null;
public SampleQueue(SamplePool samplePool) {
mSamplePool = samplePool;
@@ -34,6 +35,7 @@ public class SampleQueue {
public void queueSample(SampleHolder sample) {
mQueue.offer(sample);
+ mLastQueuedPositionUs = sample.timeUs;
}
public int dequeueSample(SampleHolder sample) {
@@ -55,20 +57,15 @@ public class SampleQueue {
while (!mQueue.isEmpty()) {
mSamplePool.releaseSample(mQueue.poll());
}
+ mLastQueuedPositionUs = null;
}
- public Long getEndPositionUs() {
- if (mQueue.isEmpty()) {
- return null;
- }
- return mQueue.getLast().timeUs;
+ public Long getLastQueuedPositionUs() {
+ return mLastQueuedPositionUs;
}
public boolean isDurationGreaterThan(long durationUs) {
- if (mQueue.isEmpty()) {
- return false;
- }
- return mQueue.getLast().timeUs - mQueue.getFirst().timeUs > durationUs;
+ return !mQueue.isEmpty() && mQueue.getLast().timeUs - mQueue.getFirst().timeUs > durationUs;
}
public boolean isEmpty() {
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SimpleSampleBuffer.java b/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java
index 29f06aa4..40c4ef95 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SimpleSampleBuffer.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/SimpleSampleBuffer.java
@@ -14,15 +14,17 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
-import android.media.MediaFormat;
import android.os.ConditionVariable;
+import android.support.annotation.NonNull;
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.usbtuner.tvinput.PlaybackCacheListener;
+import com.android.tv.tuner.tvinput.PlaybackBufferListener;
+import com.android.tv.tuner.exoplayer.SampleExtractor;
import java.io.IOException;
import java.util.List;
@@ -30,25 +32,26 @@ import java.util.List;
import junit.framework.Assert;
/**
- * Handles I/O for {@link com.android.usbtuner.exoplayer.SampleExtractor} when
- * physical storage based cache is not used. Trickplay is disabled.
+ * Handles I/O for {@link SampleExtractor} when
+ * physical storage based buffer is not used. Trickplay is disabled.
*/
-public class SimpleSampleBuffer implements CacheManager.SampleBuffer {
+public class SimpleSampleBuffer implements BufferManager.SampleBuffer {
private final SamplePool mSamplePool = new SamplePool();
private SampleQueue[] mPlayingSampleQueues;
private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
private volatile boolean mEos;
- public SimpleSampleBuffer(PlaybackCacheListener cacheListener) {
- if (cacheListener != null) {
+ public SimpleSampleBuffer(PlaybackBufferListener bufferListener) {
+ if (bufferListener != null) {
// Disables trickplay.
- cacheListener.onCacheStateChanged(false);
+ bufferListener.onBufferStateChanged(false);
}
}
@Override
- public synchronized void init(List<String> ids, List<MediaFormat> mediaFormats) {
+ public synchronized void init(@NonNull List<String> ids,
+ @NonNull List<MediaFormat> mediaFormats) {
int trackCount = ids.size();
mPlayingSampleQueues = new SampleQueue[trackCount];
for (int i = 0; i < trackCount; i++) {
@@ -93,19 +96,20 @@ public class SimpleSampleBuffer implements CacheManager.SampleBuffer {
if (queue == null) {
continue;
}
- Long bufferedPositionUs = queue.getEndPositionUs();
- if (bufferedPositionUs == null) {
+ Long lastQueuedSamplePositionUs = queue.getLastQueuedPositionUs();
+ if (lastQueuedSamplePositionUs == null) {
+ // No sample has been queued.
+ result = mLastBufferedPositionUs;
continue;
}
- if (result == null || result > bufferedPositionUs) {
- result = bufferedPositionUs;
+ if (result == null || result > lastQueuedSamplePositionUs) {
+ result = lastQueuedSamplePositionUs;
}
}
if (result == null) {
return mLastBufferedPositionUs;
- } else {
- return (mLastBufferedPositionUs = result);
}
+ return (mLastBufferedPositionUs = result);
}
@Override
@@ -155,7 +159,9 @@ public class SimpleSampleBuffer implements CacheManager.SampleBuffer {
if (queue == null) {
continue;
}
- if (queue.isEmpty()) {
+ if (queue.getLastQueuedPositionUs() == null
+ || positionUs > queue.getLastQueuedPositionUs()) {
+ // No more buffered data.
return false;
}
}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/TrickplayStorageManager.java b/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java
index 801ae534..258a5cd0 100644
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/TrickplayStorageManager.java
+++ b/src/com/android/tv/tuner/exoplayer/buffer/TrickplayStorageManager.java
@@ -14,10 +14,12 @@
* limitations under the License.
*/
-package com.android.usbtuner.exoplayer.cache;
+package com.android.tv.tuner.exoplayer.buffer;
import android.content.Context;
import android.media.MediaFormat;
+import android.os.AsyncTask;
+import android.os.Looper;
import android.provider.Settings;
import android.util.Pair;
@@ -28,8 +30,8 @@ import java.util.SortedMap;
/**
* Manages Trickplay storage.
*/
-public class TrickplayStorageManager implements CacheManager.StorageManager {
- private static final String CACHE_DIR = "timeshift";
+public class TrickplayStorageManager implements BufferManager.StorageManager {
+ private static final String BUFFER_DIR = "timeshift";
// Copied from android.provider.Settings.Global (hidden fields)
private static final String
@@ -41,8 +43,8 @@ public class TrickplayStorageManager implements CacheManager.StorageManager {
private static final int DEFAULT_THRESHOLD_PERCENTAGE = 10;
private static final long DEFAULT_THRESHOLD_MAX_BYTES = 500L * 1024 * 1024;
- private final File mCacheDir;
- private final long mMaxCacheSize;
+ private final File mBufferDir;
+ private final long mMaxBufferSize;
private final long mStorageBufferBytes;
private static long getStorageBufferBytes(Context context, File path) {
@@ -54,24 +56,40 @@ public class TrickplayStorageManager implements CacheManager.StorageManager {
return Math.min(lowBytes, maxLowBytes);
}
- public TrickplayStorageManager(Context context, File baseDir, long maxCacheSize) {
- mCacheDir = new File(baseDir, CACHE_DIR);
- mCacheDir.mkdirs();
- mMaxCacheSize = maxCacheSize;
+ public TrickplayStorageManager(Context context, File baseDir, long maxBufferSize) {
+ mBufferDir = new File(baseDir, BUFFER_DIR);
+ mBufferDir.mkdirs();
+ mMaxBufferSize = maxBufferSize;
clearStorage();
- mStorageBufferBytes = getStorageBufferBytes(context, mCacheDir);
+ mStorageBufferBytes = getStorageBufferBytes(context, mBufferDir);
}
@Override
public void clearStorage() {
- for (File file : mCacheDir.listFiles()) {
- file.delete();
+ File files[] = mBufferDir.listFiles();
+ if (files == null || files.length == 0) {
+ return;
+ }
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... params) {
+ for (File file : files) {
+ file.delete();
+ }
+ return null;
+ }
+ }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ } else {
+ for (File file : files) {
+ file.delete();
+ }
}
}
@Override
- public File getCacheDir() {
- return mCacheDir;
+ public File getBufferDir() {
+ return mBufferDir;
}
@Override
@@ -80,13 +98,13 @@ public class TrickplayStorageManager implements CacheManager.StorageManager {
}
@Override
- public boolean reachedStorageMax(long cacheSize, long pendingDelete) {
- return cacheSize - pendingDelete > mMaxCacheSize;
+ public boolean reachedStorageMax(long bufferSize, long pendingDelete) {
+ return bufferSize - pendingDelete > mMaxBufferSize;
}
@Override
public boolean hasEnoughBuffer(long pendingDelete) {
- return mCacheDir.getUsableSpace() + pendingDelete >= mStorageBufferBytes;
+ return mBufferDir.getUsableSpace() + pendingDelete >= mStorageBufferBytes;
}
@Override
@@ -104,7 +122,7 @@ public class TrickplayStorageManager implements CacheManager.StorageManager {
}
@Override
- public void writeIndexFile(String trackName, SortedMap<Long, SampleCache> index) {
+ public void writeIndexFile(String trackName, SortedMap<Long, SampleChunk> index) {
}
}
diff --git a/usbtuner/src/com/android/usbtuner/layout/ScaledLayout.java b/src/com/android/tv/tuner/layout/ScaledLayout.java
index 542e3d17..379ea70e 100644
--- a/usbtuner/src/com/android/usbtuner/layout/ScaledLayout.java
+++ b/src/com/android/tv/tuner/layout/ScaledLayout.java
@@ -14,17 +14,20 @@
* limitations under the License.
*/
-package com.android.usbtuner.layout;
+package com.android.tv.tuner.layout;
import android.content.Context;
import android.content.res.TypedArray;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.hardware.display.DisplayManager;
import android.util.AttributeSet;
import android.util.Log;
+import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
-import com.android.usbtuner.R;
+import com.android.tv.tuner.R;
import java.util.Arrays;
import java.util.Comparator;
@@ -47,6 +50,8 @@ public class ScaledLayout extends ViewGroup {
};
private Rect[] mRectArray;
+ private final int mMaxWidth;
+ private final int mMaxHeight;
public ScaledLayout(Context context) {
this(context, null);
@@ -58,6 +63,13 @@ public class ScaledLayout extends ViewGroup {
public ScaledLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
+ Point size = new Point();
+ DisplayManager displayManager = (DisplayManager) getContext()
+ .getSystemService(Context.DISPLAY_SERVICE);
+ Display display = displayManager.getDisplay(Display.DEFAULT_DISPLAY);
+ display.getRealSize(size);
+ mMaxWidth = size.x;
+ mMaxHeight = size.y;
}
/**
@@ -79,10 +91,10 @@ public class ScaledLayout extends ViewGroup {
*/
public static class ScaledLayoutParams extends ViewGroup.LayoutParams {
public static final float SCALE_UNSPECIFIED = -1;
- public float scaleStartRow;
- public float scaleEndRow;
- public float scaleStartCol;
- public float scaleEndCol;
+ public final float scaleStartRow;
+ public final float scaleEndRow;
+ public final float scaleStartCol;
+ public final float scaleEndCol;
public ScaledLayoutParams(float scaleStartRow, float scaleEndRow,
float scaleStartCol, float scaleEndCol) {
@@ -165,8 +177,9 @@ public class ScaledLayout extends ViewGroup {
}
mRectArray[i] = new Rect((int) (scaleStartCol * width), (int) (scaleStartRow * height),
(int) (scaleEndCol * width), (int) (scaleEndRow * height));
+ int scaleWidth = (int) (width * (scaleEndCol - scaleStartCol));
int childWidthSpec = MeasureSpec.makeMeasureSpec(
- (int) (width * (scaleEndCol - scaleStartCol)), MeasureSpec.EXACTLY);
+ scaleWidth > mMaxWidth ? mMaxWidth : scaleWidth, MeasureSpec.EXACTLY);
int childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
child.measure(childWidthSpec, childHeightSpec);
@@ -187,8 +200,9 @@ public class ScaledLayout extends ViewGroup {
mRectArray[i].bottom = height;
}
}
+ int scaleHeight = (int) (height * (scaleEndRow - scaleStartRow));
childHeightSpec = MeasureSpec.makeMeasureSpec(
- (int) (height * (scaleEndRow - scaleStartRow)), MeasureSpec.EXACTLY);
+ scaleHeight > mMaxHeight ? mMaxHeight : scaleHeight, MeasureSpec.EXACTLY);
child.measure(childWidthSpec, childHeightSpec);
}
diff --git a/usbtuner/src/com/android/usbtuner/setup/ConnectionTypeFragment.java b/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
index f5feec2a..97d9ece3 100644
--- a/usbtuner/src/com/android/usbtuner/setup/ConnectionTypeFragment.java
+++ b/src/com/android/tv/tuner/setup/ConnectionTypeFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.setup;
+package com.android.tv.tuner.setup;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -23,7 +23,7 @@ import android.support.v17.leanback.widget.GuidedAction;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.usbtuner.R;
+import com.android.tv.tuner.R;
import java.util.List;
import java.util.TimeZone;
@@ -33,7 +33,7 @@ import java.util.TimeZone;
*/
public class ConnectionTypeFragment extends SetupMultiPaneFragment {
public static final String ACTION_CATEGORY =
- "com.android.usbtuner.setup.ConnectionTypeFragment";
+ "com.android.tv.tuner.setup.ConnectionTypeFragment";
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
diff --git a/usbtuner/src/com/android/usbtuner/setup/ScanFragment.java b/src/com/android/tv/tuner/setup/ScanFragment.java
index f12738d9..4b3ffe40 100644
--- a/usbtuner/src/com/android/usbtuner/setup/ScanFragment.java
+++ b/src/com/android/tv/tuner/setup/ScanFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.setup;
+package com.android.tv.tuner.setup;
import android.animation.LayoutTransition;
import android.app.Activity;
@@ -36,25 +36,30 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.tv.common.AutoCloseableUtils;
+import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.ui.setup.SetupFragment;
-import com.android.usbtuner.ChannelScanFileParser;
-import com.android.usbtuner.ChannelScanFileParser.ScanChannel;
-import com.android.usbtuner.FileDataSource;
-import com.android.usbtuner.InputStreamSource;
-import com.android.usbtuner.R;
-import com.android.usbtuner.UsbTunerPreferences;
-import com.android.usbtuner.UsbTunerTsScannerSource;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.PsiData;
-import com.android.usbtuner.data.PsipData;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.tvinput.ChannelDataManager;
-import com.android.usbtuner.tvinput.EventDetector;
+import com.android.tv.tuner.ChannelScanFileParser;
+import com.android.tv.tuner.TunerHal;
+import com.android.tv.tuner.R;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.data.Channel;
+import com.android.tv.tuner.data.PsipData;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.source.FileTsStreamer;
+import com.android.tv.tuner.source.TsDataSource;
+import com.android.tv.tuner.source.TsStreamer;
+import com.android.tv.tuner.source.TunerTsStreamer;
+import com.android.tv.tuner.tvinput.ChannelDataManager;
+import com.android.tv.tuner.tvinput.EventDetector;
+import com.android.tv.tuner.util.TunerInputInfoUtils;
import junit.framework.Assert;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* A fragment for scanning channels.
@@ -66,7 +71,9 @@ public class ScanFragment extends SetupFragment {
// Instead dummy channels are added.
private static final boolean FAKE_MODE = false;
- public static final String ACTION_CATEGORY = "com.android.usbtuner.setup.ScanFragment";
+ private static final String VCTLESS_CHANNEL_NAME_FORMAT = "RF%d-%d";
+
+ public static final String ACTION_CATEGORY = "com.android.tv.tuner.setup.ScanFragment";
public static final int ACTION_CANCEL = 1;
public static final int ACTION_FINISH = 2;
@@ -113,7 +120,14 @@ public class ScanFragment extends SetupFragment {
}
});
Bundle args = getArguments();
+ // 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);
+ if (TunerInputInfoUtils.isBuiltInTuner(getActivity())){
+ scanTitleView.setText(R.string.bt_channel_scan);
+ } else {
+ scanTitleView.setText(R.string.ut_channel_scan);
+ }
return view;
}
@@ -134,8 +148,10 @@ public class ScanFragment extends SetupFragment {
@Override
public void onDetach() {
- // Ensure scan task will stop.
- mChannelScanTask.stopScan();
+ if (mChannelScanTask != null) {
+ // Ensure scan task will stop.
+ mChannelScanTask.stopScan();
+ }
super.onDetach();
}
@@ -218,27 +234,36 @@ public class ScanFragment extends SetupFragment {
}
private class ChannelScanTask extends AsyncTask<Void, Integer, Void>
- implements EventDetector.EventListener {
+ implements EventDetector.EventListener, ChannelDataManager.ChannelScanListener {
private static final int MAX_PROGRESS = 100;
private final Activity mActivity;
private final int mChannelMapId;
- private final InputStreamSource mTunerSource;
- private final InputStreamSource mFileSource;
+ private final TsStreamer mScanTsStreamer;
+ private final TsStreamer mFileTsStreamer;
private final ConditionVariable mConditionStopped;
- private List<ScanChannel> mScanChannelList;
+ private final List<ChannelScanFileParser.ScanChannel> mScanChannelList = new ArrayList<>();
private boolean mIsCanceled;
private boolean mIsFinished;
private ProgressDialog mFinishingProgressDialog;
+ private CountDownLatch mLatch;
public ChannelScanTask(int channelMapId) {
mActivity = getActivity();
mChannelMapId = channelMapId;
- mTunerSource = FAKE_MODE ? new FakeInputStreamSource(this)
- : new UsbTunerTsScannerSource(mActivity.getApplicationContext(), this);
- mFileSource = SCAN_LOCAL_STREAMS ? new FileDataSource(this) : null;
+ if (FAKE_MODE) {
+ mScanTsStreamer = new FakeTsStreamer(this);
+ } else {
+ TunerHal hal = TunerHal.createInstance(mActivity.getApplicationContext());
+ if (hal == null) {
+ throw new RuntimeException("Failed to open a DVB device");
+ }
+ mScanTsStreamer = new TunerTsStreamer(hal, this);
+ }
+ mFileTsStreamer = SCAN_LOCAL_STREAMS ? new FileTsStreamer(this) : null;
mConditionStopped = new ConditionVariable();
+ mChannelDataManager.setChannelScanListener(this, new Handler());
}
private void maybeSetChannelListVisible() {
@@ -272,43 +297,24 @@ public class ScanFragment extends SetupFragment {
});
}
- private synchronized void finishStanTask() {
- if (!mIsFinished) {
- mIsFinished = true;
- UsbTunerPreferences.setScannedChannelCount(mActivity.getApplicationContext(),
- mChannelDataManager.getScannedChannelCount());
- // Cancel a previously shown recommendation card.
- TunerSetupActivity.cancelRecommendationCard(mActivity.getApplicationContext());
- // Mark scan as done
- UsbTunerPreferences.setScanDone(mActivity.getApplicationContext());
- // finishing will be done manually.
- if (mFinishingProgressDialog != null) {
- mFinishingProgressDialog.dismiss();
- }
- mActivity.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- onActionClick(ACTION_CATEGORY, mIsCanceled ? ACTION_CANCEL : ACTION_FINISH);
- }
- });
- }
- }
-
@Override
protected Void doInBackground(Void... params) {
- mScanChannelList = ChannelScanFileParser.parseScanFile(
- getResources().openRawResource(mChannelMapId));
+ mScanChannelList.clear();
if (SCAN_LOCAL_STREAMS) {
- FileDataSource.addLocalStreamFiles(mScanChannelList);
+ FileTsStreamer.addLocalStreamFiles(mScanChannelList);
}
+ mScanChannelList.addAll(ChannelScanFileParser.parseScanFile(
+ getResources().openRawResource(mChannelMapId)));
scanChannels();
- mChannelDataManager.setCurrentVersion(mActivity);
- mChannelDataManager.release();
- finishStanTask();
return null;
}
@Override
+ protected void onCancelled() {
+ SoftPreconditions.checkState(false, TAG, "call cancelScan instead of cancel");
+ }
+
+ @Override
protected void onProgressUpdate(Integer... values) {
mProgressBar.setProgress(values[0]);
}
@@ -328,18 +334,24 @@ public class ScanFragment extends SetupFragment {
long startMs = System.currentTimeMillis();
int i = 1;
- for (ScanChannel scanChannel : mScanChannelList) {
+ for (ChannelScanFileParser.ScanChannel scanChannel : mScanChannelList) {
int frequency = scanChannel.frequency;
String modulation = scanChannel.modulation;
Log.i(TAG, "Tuning to " + frequency + " " + modulation);
- InputStreamSource source = getDataSource(scanChannel.type);
- Assert.assertNotNull(source);
- if (source.setScanChannel(scanChannel)) {
- source.startStream();
- mConditionStopped.block(CHANNEL_SCAN_PERIOD_MS);
- source.stopStream();
+ TsStreamer streamer = getStreamer(scanChannel.type);
+ Assert.assertNotNull(streamer);
+ if (streamer.startStream(scanChannel)) {
+ mLatch = new CountDownLatch(1);
+ try {
+ mLatch.await(CHANNEL_SCAN_PERIOD_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "The current thread is interrupted during scanChannels(). " +
+ "The TS stream is stopped earlier than expected.", e);
+ }
+ streamer.stopStream();
+ addChannelsWithoutVct(scanChannel);
if (System.currentTimeMillis() > startMs + CHANNEL_SCAN_SHOW_DELAY_MS
&& !mChannelListVisible) {
maybeSetChannelListVisible();
@@ -350,8 +362,10 @@ public class ScanFragment extends SetupFragment {
}
onProgressUpdate(MAX_PROGRESS * i++ / mScanChannelList.size());
}
- AutoCloseableUtils.closeQuietly(mTunerSource);
- AutoCloseableUtils.closeQuietly(mFileSource);
+ if (mScanTsStreamer instanceof TunerTsStreamer) {
+ AutoCloseableUtils.closeQuietly(
+ ((TunerTsStreamer) mScanTsStreamer).getTunerHal());
+ }
mChannelDataManager.notifyScanCompleted();
if (!mConditionStopped.block(-1)) {
publishProgress(MAX_PROGRESS);
@@ -360,12 +374,33 @@ public class ScanFragment extends SetupFragment {
}
- private InputStreamSource getDataSource(int type) {
+ private void addChannelsWithoutVct(ChannelScanFileParser.ScanChannel scanChannel) {
+ if (scanChannel.radioFrequencyNumber == null
+ || !(mScanTsStreamer instanceof TunerTsStreamer)) {
+ return;
+ }
+ for (TunerChannel tunerChannel
+ : ((TunerTsStreamer) mScanTsStreamer).getMalFormedChannels()) {
+ if ((tunerChannel.getVideoPid() != TunerChannel.INVALID_PID)
+ && (tunerChannel.getAudioPid() != TunerChannel.INVALID_PID)) {
+ tunerChannel.setFrequency(scanChannel.frequency);
+ tunerChannel.setModulation(scanChannel.modulation);
+ tunerChannel.setShortName(String.format(Locale.US, VCTLESS_CHANNEL_NAME_FORMAT,
+ scanChannel.radioFrequencyNumber,
+ tunerChannel.getProgramNumber()));
+ tunerChannel.setVirtualMajor(scanChannel.radioFrequencyNumber);
+ tunerChannel.setVirtualMinor(tunerChannel.getProgramNumber());
+ onChannelDetected(tunerChannel, true);
+ }
+ }
+ }
+
+ private TsStreamer getStreamer(int type) {
switch (type) {
case Channel.TYPE_TUNER:
- return mTunerSource;
+ return mScanTsStreamer;
case Channel.TYPE_FILE:
- return mFileSource;
+ return mFileTsStreamer;
default:
return null;
}
@@ -377,57 +412,69 @@ public class ScanFragment extends SetupFragment {
}
@Override
- public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
- if (DEBUG && channelArrivedAtFirstTime) {
- Log.d(TAG, "Found channel " + channel);
+ public void onChannelScanDone() {
+ if (mLatch != null) {
+ mLatch.countDown();
}
+ }
+
+ @Override
+ public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
if (channelArrivedAtFirstTime) {
+ Log.i(TAG, "Found channel " + channel);
+ }
+ if (channelArrivedAtFirstTime && channel.hasAudio()) {
+ // Playbacks with video-only stream have not been tested yet.
+ // No video-only channel has been found.
addChannel(channel);
}
mChannelDataManager.notifyChannelDetected(channel, channelArrivedAtFirstTime);
}
- public synchronized void showFinishingProgressDialog() {
+ public void showFinishingProgressDialog() {
// Show a progress dialog to wait for the scanning process if it's not done yet.
if (!mIsFinished && mFinishingProgressDialog == null) {
mFinishingProgressDialog = ProgressDialog.show(mActivity, "",
getString(R.string.ut_setup_cancel), true, false);
}
}
+
+ @Override
+ public void onChannelHandlingDone() {
+ mChannelDataManager.setCurrentVersion(mActivity);
+ mChannelDataManager.releaseSafely();
+ mIsFinished = true;
+ TunerPreferences.setScannedChannelCount(mActivity.getApplicationContext(),
+ mChannelDataManager.getScannedChannelCount());
+ // Cancel a previously shown recommendation card.
+ TunerSetupActivity.cancelRecommendationCard(mActivity.getApplicationContext());
+ // Mark scan as done
+ TunerPreferences.setScanDone(mActivity.getApplicationContext());
+ // finishing will be done manually.
+ if (mFinishingProgressDialog != null) {
+ mFinishingProgressDialog.dismiss();
+ }
+ onActionClick(ACTION_CATEGORY, mIsCanceled ? ACTION_CANCEL : ACTION_FINISH);
+ mChannelScanTask = null;
+ }
}
- private static class FakeInputStreamSource implements InputStreamSource {
+ private static class FakeTsStreamer implements TsStreamer {
private final EventDetector.EventListener mEventListener;
private int mProgramNumber = 0;
- FakeInputStreamSource(EventDetector.EventListener eventListener) {
+ FakeTsStreamer(EventDetector.EventListener eventListener) {
mEventListener = eventListener;
}
@Override
- public int getType() {
- return 0;
- }
-
- @Override
- public boolean setScanChannel(ScanChannel channel) {
- return true;
- }
-
- @Override
- public boolean tuneToChannel(TunerChannel channel) {
- return false;
- }
-
- @Override
- public void startStream() {
+ public boolean startStream(ChannelScanFileParser.ScanChannel channel) {
if (++mProgramNumber % 2 == 1) {
- return;
+ return true;
}
final String displayNumber = Integer.toString(mProgramNumber);
final String name = "Channel-" + mProgramNumber;
- mEventListener.onChannelDetected(new TunerChannel(mProgramNumber,
- new ArrayList<PsiData.PmtItem>()) {
+ mEventListener.onChannelDetected(new TunerChannel(mProgramNumber, new ArrayList<>()) {
@Override
public String getDisplayNumber() {
return displayNumber;
@@ -438,24 +485,21 @@ public class ScanFragment extends SetupFragment {
return name;
}
}, true);
+ return true;
}
@Override
- public void stopStream() {
- }
-
- @Override
- public long getLimit() {
- return 0;
+ public boolean startStream(TunerChannel channel) {
+ return false;
}
@Override
- public long getPosition() {
- return 0;
+ public void stopStream() {
}
@Override
- public void close() {
+ public TsDataSource createDataSource() {
+ return null;
}
}
}
diff --git a/usbtuner/src/com/android/usbtuner/setup/ScanResultFragment.java b/src/com/android/tv/tuner/setup/ScanResultFragment.java
index bf2ca477..068543cd 100644
--- a/usbtuner/src/com/android/usbtuner/setup/ScanResultFragment.java
+++ b/src/com/android/tv/tuner/setup/ScanResultFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.setup;
+package com.android.tv.tuner.setup;
import android.content.Context;
import android.content.res.Resources;
@@ -22,14 +22,12 @@ import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v17.leanback.widget.GuidanceStylist.Guidance;
import android.support.v17.leanback.widget.GuidedAction;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.usbtuner.R;
-import com.android.usbtuner.UsbTunerPreferences;
+import com.android.tv.tuner.R;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.util.TunerInputInfoUtils;
import java.util.List;
@@ -38,13 +36,7 @@ import java.util.List;
*/
public class ScanResultFragment extends SetupMultiPaneFragment {
public static final String ACTION_CATEGORY =
- "com.android.usbtuner.setup.ScanResultFragment";
-
- /**
- * An action which moves to previous page when the user presses BACK button.
- * In some cases, more than one page can be popped out.
- */
- public static final int ACTION_BACK_TO_CONNECTION_TYPE = ACTION_DONE - 1;
+ "com.android.tv.tuner.setup.ScanResultFragment";
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
@@ -67,7 +59,7 @@ public class ScanResultFragment extends SetupMultiPaneFragment {
@Override
public void onAttach(Context context) {
super.onAttach(context);
- mChannelCountOnPreference = UsbTunerPreferences.getScannedChannelCount(context);
+ mChannelCountOnPreference = TunerPreferences.getScannedChannelCount(context);
}
@NonNull
@@ -85,7 +77,11 @@ public class ScanResultFragment extends SetupMultiPaneFragment {
breadcrumb = null;
} else {
title = getString(R.string.ut_result_not_found_title);
- description = getString(R.string.ut_result_not_found_description);
+ if (TunerInputInfoUtils.isBuiltInTuner(getActivity())) {
+ description = getString(R.string.bt_result_not_found_description);
+ } else {
+ description = getString(R.string.ut_result_not_found_description);
+ }
breadcrumb = getString(R.string.ut_setup_breadcrumb);
}
return new Guidance(title, description, breadcrumb, null);
diff --git a/usbtuner/src/com/android/usbtuner/setup/TunerSetupActivity.java b/src/com/android/tv/tuner/setup/TunerSetupActivity.java
index a67cc1ea..78121bc5 100644
--- a/usbtuner/src/com/android/usbtuner/setup/TunerSetupActivity.java
+++ b/src/com/android/tv/tuner/setup/TunerSetupActivity.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.setup;
+package com.android.tv.tuner.setup;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -24,30 +24,37 @@ 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.Bundle;
import android.support.v4.app.NotificationCompat;
+import android.util.Log;
import android.view.KeyEvent;
+import android.widget.Toast;
+import com.android.tv.TvApplication;
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.usbtuner.R;
-import com.android.usbtuner.UsbTunerPreferences;
-import com.android.usbtuner.tvinput.UsbTunerTvInputService;
+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.TunerInputInfoUtils;
/**
- * An activity that serves USB tuner setup process.
+ * An activity that serves tuner setup process.
*/
public class TunerSetupActivity extends SetupActivity {
+ private final String TAG = "TunerSetupActivity";
// For the recommendation card
private static final String TV_ACTIVITY_CLASS_NAME = "com.android.tv.TvActivity";
- private static final String NOTIFY_TAG = "UsbTunerSetup";
+ 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";
@@ -64,6 +71,19 @@ public class TunerSetupActivity extends SetupActivity {
private ScanFragment mLastScanFragment;
@Override
+ protected void onCreate(Bundle savedInstanceState) {
+ TvApplication.setCurrentRunningProcess(this, false);
+ super.onCreate(savedInstanceState);
+ // TODO: check {@link shouldShowRequestPermissionRationale}.
+ if (checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ != PackageManager.PERMISSION_GRANTED) {
+ // No need to check the request result.
+ requestPermissions(new String[] {android.Manifest.permission.ACCESS_COARSE_LOCATION},
+ 0);
+ }
+ }
+
+ @Override
protected Fragment onCreateInitialFragment() {
SetupFragment fragment = new WelcomeFragment();
fragment.setShortDistance(SetupFragment.FRAGMENT_EXIT_TRANSITION
@@ -72,7 +92,7 @@ public class TunerSetupActivity extends SetupActivity {
}
@Override
- protected void executeAction(String category, int actionId) {
+ protected boolean executeAction(String category, int actionId, Bundle params) {
switch (category) {
case WelcomeFragment.ACTION_CATEGORY:
switch (actionId) {
@@ -89,25 +109,39 @@ public class TunerSetupActivity extends SetupActivity {
break;
}
}
- break;
+ return true;
case ConnectionTypeFragment.ACTION_CATEGORY:
+ TunerHal hal = TunerHal.createInstance(getApplicationContext());
+ if (hal == null) {
+ finish();
+ Toast.makeText(getApplicationContext(),
+ R.string.ut_channel_scan_tuner_unavailable,Toast.LENGTH_LONG).show();
+ return true;
+ }
+ try {
+ hal.close();
+ } catch (Exception e) {
+ Log.e(TAG, "Tuner hal close failed", e);
+ return true;
+ }
mLastScanFragment = new ScanFragment();
Bundle args = new Bundle();
- args.putInt(ScanFragment.EXTRA_FOR_CHANNEL_SCAN_FILE, CHANNEL_MAP_SCAN_FILE[actionId]);
+ args.putInt(ScanFragment.EXTRA_FOR_CHANNEL_SCAN_FILE,
+ CHANNEL_MAP_SCAN_FILE[actionId]);
mLastScanFragment.setArguments(args);
showFragment(mLastScanFragment, true);
- break;
+ return true;
case ScanFragment.ACTION_CATEGORY:
switch (actionId) {
case ScanFragment.ACTION_CANCEL:
getFragmentManager().popBackStack();
- break;
+ return true;
case ScanFragment.ACTION_FINISH:
SetupFragment fragment = new ScanResultFragment();
fragment.setShortDistance(SetupFragment.FRAGMENT_EXIT_TRANSITION
| SetupFragment.FRAGMENT_REENTER_TRANSITION);
showFragment(fragment, true);
- break;
+ return true;
}
break;
case ScanResultFragment.ACTION_CATEGORY:
@@ -123,8 +157,9 @@ public class TunerSetupActivity extends SetupActivity {
showFragment(fragment, true);
break;
}
- break;
+ return true;
}
+ return false;
}
@Override
@@ -152,31 +187,31 @@ public class TunerSetupActivity extends SetupActivity {
* 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 UsbTunerTvInputService} to be enabled;
+ * @param enabled {@code true} for the {@link TunerTvInputService} to be enabled;
* otherwise {@code false}
*/
public static void onTvInputEnabled(Context context, boolean enabled) {
- // Send a recommendation card for USB channel tuner setup
- // if there's no channels and the USB tuner TV input setup has been not done.
- boolean channelScanDoneOnPreference = UsbTunerPreferences.isScanDone(context);
- int channelCountOnPreference = UsbTunerPreferences.getScannedChannelCount(context);
+ // Send a recommendation card 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) {
- UsbTunerPreferences.setShouldShowSetupActivity(context, true);
+ TunerPreferences.setShouldShowSetupActivity(context, true);
sendRecommendationCard(context);
} else {
- UsbTunerPreferences.setShouldShowSetupActivity(context, false);
+ TunerPreferences.setShouldShowSetupActivity(context, false);
cancelRecommendationCard(context);
}
}
/**
- * Returns a {@link Intent} to launch the USB tuner TV input service.
+ * 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(),
- UsbTunerTvInputService.class.getName()));
+ TunerTvInputService.class.getName()));
// Make an intent to launch the setup activity of USB tuner TV input.
Intent intent = TvCommonUtils.createSetupIntent(
@@ -189,7 +224,7 @@ public class TunerSetupActivity extends SetupActivity {
}
/**
- * Returns a {@link PendingIntent} to launch the USB tuner TV input service.
+ * Returns a {@link PendingIntent} to launch the tuner TV input service.
*
* @param context a {@link Context} instance
*/
@@ -199,7 +234,7 @@ public class TunerSetupActivity extends SetupActivity {
}
/**
- * Sends the recommendation card to start the USB tuner TV input setup activity.
+ * Sends the recommendation card to start the tuner TV input setup activity.
*
* @param context a {@link Context} instance
*/
@@ -207,7 +242,12 @@ public class TunerSetupActivity extends SetupActivity {
Resources resources = context.getResources();
String focusedTitle = resources.getString(
R.string.ut_setup_recommendation_card_focused_title);
- String title = resources.getString(R.string.ut_setup_recommendation_card_title);
+ String title;
+ if (TunerInputInfoUtils.isBuiltInTuner(context)) {
+ title = resources.getString(R.string.bt_setup_recommendation_card_title);
+ } else {
+ title = resources.getString(R.string.ut_setup_recommendation_card_title);
+ }
Bitmap largeIcon = BitmapFactory.decodeResource(resources,
R.drawable.recommendation_antenna);
diff --git a/usbtuner/src/com/android/usbtuner/setup/WelcomeFragment.java b/src/com/android/tv/tuner/setup/WelcomeFragment.java
index c939dd5f..7e809411 100644
--- a/usbtuner/src/com/android/usbtuner/setup/WelcomeFragment.java
+++ b/src/com/android/tv/tuner/setup/WelcomeFragment.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.setup;
+package com.android.tv.tuner.setup;
import android.os.Bundle;
import android.support.annotation.NonNull;
@@ -26,8 +26,9 @@ import android.view.ViewGroup;
import com.android.tv.common.ui.setup.SetupGuidedStepFragment;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
-import com.android.usbtuner.R;
-import com.android.usbtuner.UsbTunerPreferences;
+import com.android.tv.tuner.R;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.util.TunerInputInfoUtils;
import java.util.List;
@@ -36,7 +37,7 @@ import java.util.List;
*/
public class WelcomeFragment extends SetupMultiPaneFragment {
public static final String ACTION_CATEGORY =
- "com.android.usbtuner.setup.WelcomeFragment";
+ "com.android.tv.tuner.setup.WelcomeFragment";
@Override
protected SetupGuidedStepFragment onCreateContentFragment() {
@@ -59,7 +60,7 @@ public class WelcomeFragment extends SetupMultiPaneFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
- mChannelCountOnPreference = UsbTunerPreferences
+ mChannelCountOnPreference = TunerPreferences
.getScannedChannelCount(getActivity().getApplicationContext());
return super.onCreateView(inflater, container, savedInstanceState);
}
@@ -70,11 +71,20 @@ public class WelcomeFragment extends SetupMultiPaneFragment {
String title;
String description;
if (mChannelCountOnPreference == 0) {
- title = getString(R.string.ut_setup_new_title);
- description = getString(R.string.ut_setup_new_description);
+ if (TunerInputInfoUtils.isBuiltInTuner(getActivity())) {
+ title = getString(R.string.bt_setup_new_title);
+ description = getString(R.string.bt_setup_new_description);
+ } else {
+ title = getString(R.string.ut_setup_new_title);
+ description = getString(R.string.ut_setup_new_description);
+ }
} else {
- title = getString(R.string.ut_setup_again_title);
- description = getString(R.string.ut_setup_again_description);
+ title = getString(R.string.bt_setup_again_title);
+ if (TunerInputInfoUtils.isBuiltInTuner(getActivity())) {
+ description = getString(R.string.bt_setup_again_description);
+ } else {
+ description = getString(R.string.ut_setup_again_description);
+ }
}
return new Guidance(title, description, null, null);
}
diff --git a/usbtuner/src/com/android/usbtuner/FileDataSource.java b/src/com/android/tv/tuner/source/FileTsStreamer.java
index af831e2f..14997ee4 100644
--- a/usbtuner/src/com/android/usbtuner/FileDataSource.java
+++ b/src/com/android/tv/tuner/source/FileTsStreamer.java
@@ -14,32 +14,34 @@
* limitations under the License.
*/
-package com.android.usbtuner;
+package com.android.tv.tuner.source;
-import android.media.MediaDataSource;
import android.os.Environment;
import android.util.Log;
import android.util.SparseBooleanArray;
-import com.android.usbtuner.ChannelScanFileParser.ScanChannel;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.ts.TsParser;
-import com.android.usbtuner.tvinput.EventDetector;
-import com.android.usbtuner.tvinput.FileSourceEventDetector;
+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.ScanChannel;
+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 java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
/**
- * A {@link DataSource} implementation which provides the MPEG-2 TS stream from a local file
+ * Provides MPEG-2 TS stream sources for both channel scanning and channel playing from a local file
* generated by capturing TV signal.
*/
-public class FileDataSource extends MediaDataSource implements InputStreamSource {
- private static final String TAG = "FileDataSource";
+public class FileTsStreamer implements TsStreamer {
+ private static final String TAG = "FileTsStreamer";
private static final int TS_PACKET_SIZE = 188;
private static final int TS_SYNC_BYTE = 0x47;
@@ -66,53 +68,103 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
private Thread mStreamingThread;
private StreamProvider mSource;
- public FileDataSource(EventDetector.EventListener eventListener) {
+ public static class FileDataSource extends TsDataSource {
+ private final FileTsStreamer mTsStreamer;
+ private final AtomicLong mLastReadPosition = new AtomicLong(0);
+ private long mStartBufferedPosition;
+
+ private FileDataSource(FileTsStreamer tsStreamer) {
+ mTsStreamer = tsStreamer;
+ mStartBufferedPosition = tsStreamer.getBufferedPosition();
+ }
+
+ @Override
+ public long getBufferedPosition() {
+ return mTsStreamer.getBufferedPosition() - mStartBufferedPosition;
+ }
+
+ @Override
+ public long getLastReadPosition() {
+ return mLastReadPosition.get();
+ }
+
+ @Override
+ public void shiftStartPosition(long offset) {
+ SoftPreconditions.checkState(mLastReadPosition.get() == 0);
+ SoftPreconditions.checkArgument(0 <= offset && offset <= getBufferedPosition());
+ mStartBufferedPosition += offset;
+ }
+
+ @Override
+ public long open(DataSpec dataSpec) throws IOException {
+ mLastReadPosition.set(0);
+ return C.LENGTH_UNBOUNDED;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int readLength) throws IOException {
+ int ret = mTsStreamer.readAt(mStartBufferedPosition + mLastReadPosition.get(), buffer,
+ offset, readLength);
+ if (ret > 0) {
+ mLastReadPosition.addAndGet(ret);
+ }
+ return ret;
+ }
+ }
+
+ /**
+ * Creates {@link TsStreamer} for scanning & playing MPEG-2 TS file.
+ * @param eventListener the listener for channel & program information
+ */
+ public FileTsStreamer(EventDetector.EventListener eventListener) {
mEventDetector = new FileSourceEventDetector(eventListener);
}
@Override
- public boolean setScanChannel(ScanChannel channel) {
+ public boolean startStream(ScanChannel channel) {
String filepath = new File(FILE_DIR, channel.filename).getAbsolutePath();
mSource = new StreamProvider(filepath);
- if (mSource.isReady()) {
- mEventDetector.start(mSource);
- return true;
+ if (!mSource.isReady()) {
+ return false;
+ }
+ mEventDetector.start(mSource, FileSourceEventDetector.ALL_PROGRAM_NUMBERS);
+ mSource.addPidFilter(TsParser.ATSC_SI_BASE_PID);
+ mSource.addPidFilter(TsParser.PAT_PID);
+ synchronized (mCircularBufferMonitor) {
+ if (mStreaming) {
+ return true;
+ }
+ mStreaming = true;
}
- return false;
+
+ mStreamingThread = new StreamingThread();
+ mStreamingThread.start();
+ Log.i(TAG, "Streaming started");
+ return true;
}
- /**
- * Sets the channel required to start streaming from this device. Afterwards, prepares
- * the tuner device for streaming. Package retrieval can be made at any time after invoking
- * this method and before stopping the stream.
- *
- * @param channel a {@link TunerChannel} instance tune to
- * @return {@code true} if the entire operation was successful; {@code false} otherwise
- */
@Override
- public boolean tuneToChannel(TunerChannel channel) {
+ public boolean startStream(TunerChannel channel) {
Log.i(TAG, "tuneToChannel with: " + channel.getFilepath());
mSource = new StreamProvider(channel.getFilepath());
if (!mSource.isReady()) {
return false;
}
- mEventDetector.start(mSource);
+ mEventDetector.start(mSource, channel.getProgramNumber());
mSource.addPidFilter(channel.getVideoPid());
- mSource.addPidFilter(channel.getAudioPid());
+ for (Integer i : channel.getAudioPids()) {
+ mSource.addPidFilter(i);
+ }
mSource.addPidFilter(channel.getPcrPid());
- return true;
- }
-
- /**
- * Starts streaming data.
- */
- @Override
- public void startStream() {
mSource.addPidFilter(TsParser.ATSC_SI_BASE_PID);
mSource.addPidFilter(TsParser.PAT_PID);
synchronized (mCircularBufferMonitor) {
if (mStreaming) {
- return;
+ return true;
}
mStreaming = true;
}
@@ -120,6 +172,7 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
mStreamingThread = new StreamingThread();
mStreamingThread.start();
Log.i(TAG, "Streaming started");
+ return true;
}
/**
@@ -143,16 +196,17 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
}
@Override
- public long getLimit() {
- synchronized (mCircularBufferMonitor) {
- return mBytesFetched;
- }
+ public TsDataSource createDataSource() {
+ return new FileDataSource(this);
}
- @Override
- public long getPosition() {
+ /**
+ * Returns the current buffered position from the file.
+ * @return the current buffered position
+ */
+ public long getBufferedPosition() {
synchronized (mCircularBufferMonitor) {
- return mLastReadPosition;
+ return mBytesFetched;
}
}
@@ -184,26 +238,48 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
return mInputStream != null;
}
+ /**
+ * Returns the file path of the MPEG-2 TS file.
+ */
public String getFilepath() {
return mFilepath;
}
+ /**
+ * Adds a pid for filtering from the MPEG-2 TS file.
+ */
public void addPidFilter(int pid) {
mPids.put(pid, true);
}
+ /**
+ * Returns whether the current pid filter is empty or not.
+ */
public boolean isFilterEmpty() {
return mPids.size() > 0;
}
+ /**
+ * Clears the current pid filter.
+ */
public void clearPidFilter() {
mPids.clear();
}
+ /**
+ * Returns whether a pid is in the pid filter or not.
+ * @param pid the pid to check
+ */
public boolean isInFilter(int pid) {
return mPids.get(pid);
}
+ /**
+ * Reads from the MPEG-2 TS file to buffer.
+ *
+ * @param inputBuffer to read
+ * @return the number of read bytes
+ */
private int read(byte[] inputBuffer) {
int readSize = readInternal();
if (readSize <= 0) {
@@ -255,7 +331,15 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
}
}
- @Override
+ /**
+ * Reads data from internal buffer.
+ * @param pos the position to read from
+ * @param buffer to read
+ * @param offset start position of the read buffer
+ * @param amount number of bytes to read
+ * @return number of read bytes when successful, {@code -1} otherwise
+ * @throws IOException
+ */
public int readAt(long pos, byte[] buffer, int offset, int amount) throws IOException {
synchronized (mCircularBufferMonitor) {
long initialBytesFetched = mBytesFetched;
@@ -298,19 +382,6 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
}
}
- @Override
- public long getSize() throws IOException {
- return -1;
- }
-
- @Override
- public void close() {}
-
- @Override
- public int getType() {
- return Channel.TYPE_FILE;
- }
-
/**
* Adds {@link ScanChannel} instance for local files.
*
@@ -322,7 +393,7 @@ public class FileDataSource extends MediaDataSource implements InputStreamSource
File[] tsFiles = dir.listFiles();
if (tsFiles == null) return;
- int freq = FileDataSource.FREQ_BASE;
+ int freq = FileTsStreamer.FREQ_BASE;
for (File file : tsFiles) {
if (!file.isFile()) continue;
output.add(ScanChannel.forFile(freq, file.getName()));
diff --git a/src/com/android/tv/tuner/source/TsDataSource.java b/src/com/android/tv/tuner/source/TsDataSource.java
new file mode 100644
index 00000000..2ce3e670
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TsDataSource.java
@@ -0,0 +1,50 @@
+/*
+ * 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.source;
+
+import com.google.android.exoplayer.upstream.DataSource;
+
+/**
+ * {@link DataSource} for MPEG-TS stream, which will be used by {@link TsExtractor}.
+ */
+public abstract class TsDataSource implements DataSource {
+
+ /**
+ * Returns the number of bytes being buffered by {@link TsStreamer} so far.
+ *
+ * @return the buffered position
+ */
+ public long getBufferedPosition() {
+ return 0;
+ }
+
+ /**
+ * Returns the offset position where the last {@link DataSource#read} read.
+ *
+ * @return the last read position
+ */
+ public long getLastReadPosition() {
+ return 0;
+ }
+
+ /**
+ * Shifts start position by the specified offset.
+ * Do not call this method when the class already provided MPEG-TS stream to the extractor.
+ * @param offset 0 <= offset <= buffered position
+ */
+ public void shiftStartPosition(long offset) { }
+} \ No newline at end of file
diff --git a/src/com/android/tv/tuner/source/TsDataSourceManager.java b/src/com/android/tv/tuner/source/TsDataSourceManager.java
new file mode 100644
index 00000000..7286cd8c
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TsDataSourceManager.java
@@ -0,0 +1,135 @@
+/*
+ * 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.source;
+
+import android.content.Context;
+
+import com.android.tv.tuner.data.Channel;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.tvinput.EventDetector;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages {@link DataSource} for playback and recording.
+ * The class hides handling of {@link TunerHal} and {@link TsStreamer} from other classes.
+ * One TsDataSourceManager should be created for per session.
+ */
+public class TsDataSourceManager {
+ private static String TAG = "TsDataSourceManager";
+
+ private static final Object sLock = new Object();
+ private static final Map<TsDataSource, TsStreamer> sTsStreamers =
+ new ConcurrentHashMap<>();
+
+ private static int sSequenceId;
+
+ private final int mId;
+ private final boolean mIsRecording;
+ private final TunerTsStreamerManager mTunerStreamerManager =
+ TunerTsStreamerManager.getInstance();
+
+ private boolean mKeepTuneStatus;
+
+ /**
+ * Creates TsDataSourceManager to create and release {@link DataSource} which will be
+ * used for playing and recording.
+ * @param isRecording {@code true} when for recording, {@code false} otherwise
+ * @return {@link TsDataSourceManager}
+ */
+ public static TsDataSourceManager createSourceManager(boolean isRecording) {
+ int id;
+ synchronized (sLock) {
+ id = ++sSequenceId;
+ }
+ return new TsDataSourceManager(id, isRecording);
+ }
+
+ private TsDataSourceManager(int id, boolean isRecording) {
+ mId = id;
+ mIsRecording = isRecording;
+ mKeepTuneStatus = true;
+ }
+
+ /**
+ * Creates or retrieves {@link TsDataSource} for playing or recording
+ * @param context a {@link Context} instance
+ * @param channel to play or record
+ * @param eventListener for program information which will be scanned from MPEG2-TS stream
+ * @return {@link TsDataSource} which will provide the specified channel stream
+ */
+ public TsDataSource createDataSource(Context context, TunerChannel channel,
+ EventDetector.EventListener eventListener) {
+ if (channel.getType() == Channel.TYPE_FILE) {
+ // MPEG2 TS captured stream file recording is not supported.
+ if (mIsRecording) {
+ return null;
+ }
+ FileTsStreamer streamer = new FileTsStreamer(eventListener);
+ if (streamer.startStream(channel)) {
+ TsDataSource source = streamer.createDataSource();
+ sTsStreamers.put(source, streamer);
+ return source;
+ }
+ return null;
+ }
+ return mTunerStreamerManager.createDataSource(context, channel, eventListener,
+ mId, !mIsRecording && mKeepTuneStatus);
+ }
+
+ /**
+ * Releases the specified {@link TsDataSource} and underlying {@link TunerHal}.
+ * @param source to release
+ */
+ public void releaseDataSource(TsDataSource source) {
+ if (source instanceof TunerTsStreamer.TunerDataSource) {
+ mTunerStreamerManager.releaseDataSource(
+ source, mId, !mIsRecording && mKeepTuneStatus);
+ } else if (source instanceof FileTsStreamer.FileDataSource) {
+ FileTsStreamer streamer = (FileTsStreamer) sTsStreamers.get(source);
+ if (streamer != null) {
+ sTsStreamers.remove(source);
+ streamer.stopStream();
+ }
+ }
+ }
+
+ /**
+ * Indicates that the current session has pending tunes.
+ */
+ public void setHasPendingTune() {
+ mTunerStreamerManager.setHasPendingTune(mId);
+ }
+
+ /**
+ * Indicates whether the underlying {@link TunerHal} should be kept or not when data source
+ * is being released.
+ * TODO: If b/30750953 is fixed, we can remove this function.
+ * @param keepTuneStatus underlying {@link TunerHal} will be reused when data source releasing.
+ */
+ public void setKeepTuneStatus(boolean keepTuneStatus) {
+ mKeepTuneStatus = keepTuneStatus;
+ }
+
+ /**
+ * Releases persistent resources.
+ */
+ public void release() {
+ mTunerStreamerManager.release(mId);
+ }
+}
diff --git a/src/com/android/tv/tuner/source/TsStreamWriter.java b/src/com/android/tv/tuner/source/TsStreamWriter.java
new file mode 100644
index 00000000..30650555
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TsStreamWriter.java
@@ -0,0 +1,237 @@
+/*
+ * 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.source;
+
+import android.content.Context;
+import android.util.Log;
+import com.android.tv.tuner.data.TunerChannel;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Stores TS files to the disk for debugging.
+ */
+public class TsStreamWriter {
+ private static final String TAG = "TsStreamWriter";
+ private static final boolean DEBUG = false;
+
+ private static final long TIME_LIMIT_MS = 10000; // 10s
+ private static final int NO_INSTANCE_ID = 0;
+ private static final int MAX_GET_ID_RETRY_COUNT = 5;
+ private static final int MAX_INSTANCE_ID = 10000;
+ private static final String SEPARATOR = "_";
+
+ private FileOutputStream mFileOutputStream;
+ private long mFileStartTimeMs;
+ private String mFileName = null;
+ private final String mDirectoryPath;
+ private final File mDirectory;
+ private final int mInstanceId;
+ private TunerChannel mChannel;
+
+ public TsStreamWriter(Context context) {
+ File externalFilesDir = context.getExternalFilesDir(null);
+ if (externalFilesDir == null || !externalFilesDir.isDirectory()) {
+ mDirectoryPath = null;
+ mDirectory = null;
+ mInstanceId = NO_INSTANCE_ID;
+ if (DEBUG) {
+ Log.w(TAG, "Fail to get external files dir!");
+ }
+ } else {
+ mDirectoryPath = externalFilesDir.getPath() + "/EngTsStream";
+ mDirectory = new File(mDirectoryPath);
+ if (!mDirectory.exists()) {
+ boolean madeDir = mDirectory.mkdir();
+ if (!madeDir) {
+ Log.w(TAG, "Error. Fail to create folder!");
+ }
+ }
+ mInstanceId = generateInstanceId();
+ }
+ }
+
+ /**
+ * Sets the current channel.
+ *
+ * @param channel curren channel of the stream
+ */
+ public void setChannel(TunerChannel channel) {
+ mChannel = channel;
+ }
+
+ /**
+ * Opens a file to store TS data.
+ */
+ public void openFile() {
+ if (mChannel == null || mDirectoryPath == null) {
+ return;
+ }
+ mFileStartTimeMs = System.currentTimeMillis();
+ mFileName = mChannel.getDisplayNumber() + SEPARATOR + mFileStartTimeMs + SEPARATOR
+ + mInstanceId + ".ts";
+ String filePath = mDirectoryPath + "/" + mFileName;
+ try {
+ mFileOutputStream = new FileOutputStream(filePath, false);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "Cannot open file: " + filePath, e);
+ }
+ }
+
+ /**
+ * Closes the file and stops storing TS data.
+ *
+ * @param calledWhenStopStream {@code true} if this method is called when the stream is stopped
+ * {@code false} otherwise
+ */
+ public void closeFile(boolean calledWhenStopStream) {
+ if (mFileOutputStream == null) {
+ return;
+ }
+ try {
+ mFileOutputStream.close();
+ deleteOutdatedFiles(calledWhenStopStream);
+ mFileName = null;
+ mFileOutputStream = null;
+ } catch (IOException e) {
+ Log.w(TAG, "Error on closing file.", e);
+ }
+ }
+
+ /**
+ * Writes the data to the file.
+ *
+ * @param buffer the data to be written
+ * @param bytesWritten number of bytes written
+ */
+ public void writeToFile(byte[] buffer, int bytesWritten) {
+ if (mFileOutputStream == null) {
+ return;
+ }
+ if (System.currentTimeMillis() - mFileStartTimeMs > TIME_LIMIT_MS) {
+ closeFile(false);
+ openFile();
+ }
+ try {
+ mFileOutputStream.write(buffer, 0, bytesWritten);
+ } catch (IOException e) {
+ Log.w(TAG, "Error on writing TS stream.", e);
+ }
+ }
+
+ /**
+ * Deletes outdated files to save storage.
+ *
+ * @param deleteAll {@code true} if all the files with the relative ID should be deleted
+ * {@code false} if the most recent file should not be deleted
+ */
+ private void deleteOutdatedFiles(boolean deleteAll) {
+ if (mFileName == null) {
+ return;
+ }
+ if (mDirectory == null || !mDirectory.isDirectory()) {
+ Log.e(TAG, "Error. The folder doesn't exist!");
+ return;
+ }
+ if (mFileName == null) {
+ Log.e(TAG, "Error. The current file name is null!");
+ return;
+ }
+ for (File file : mDirectory.listFiles()) {
+ if (file.isFile() && getFileId(file) == mInstanceId
+ && (deleteAll || !mFileName.equals(file.getName()))) {
+ boolean deleted = file.delete();
+ if (DEBUG && !deleted) {
+ Log.w(TAG, "Failed to delete " + file.getName());
+ }
+ }
+ }
+ }
+
+ /**
+ * Generates a unique instance ID.
+ *
+ * @return a unique instance ID
+ */
+ private int generateInstanceId() {
+ if (mDirectory == null) {
+ return NO_INSTANCE_ID;
+ }
+ Set<Integer> idSet = getExistingIds();
+ if (idSet == null) {
+ return NO_INSTANCE_ID;
+ }
+ for (int i = 0; i < MAX_GET_ID_RETRY_COUNT; i++) {
+ // Range [1, MAX_INSTANCE_ID]
+ int id = (int)Math.floor(Math.random() * MAX_INSTANCE_ID) + 1;
+ if (!idSet.contains(id)) {
+ return id;
+ }
+ }
+ return NO_INSTANCE_ID;
+ }
+
+ /**
+ * Gets all existing instance IDs.
+ *
+ * @return a set of all existing instance IDs
+ */
+ private Set<Integer> getExistingIds() {
+ if (mDirectory == null || !mDirectory.isDirectory()) {
+ return null;
+ }
+
+ Set<Integer> idSet = new HashSet<>();
+ for (File file : mDirectory.listFiles()) {
+ int id = getFileId(file);
+ if(id != NO_INSTANCE_ID) {
+ idSet.add(id);
+ }
+ }
+ return idSet;
+ }
+
+ /**
+ * Gets the instance ID of a given file.
+ *
+ * @param file the file whose TsStreamWriter ID is returned
+ * @return the TsStreamWriter ID of the file or NO_INSTANCE_ID if not available
+ */
+ private static int getFileId(File file) {
+ if (file == null || !file.isFile()) {
+ return NO_INSTANCE_ID;
+ }
+ String fileName = file.getName();
+ int lastSeparator = fileName.lastIndexOf(SEPARATOR);
+ if (!fileName.endsWith(".ts") || lastSeparator == -1) {
+ return NO_INSTANCE_ID;
+ }
+ try {
+ return Integer.parseInt(fileName.substring(lastSeparator + 1, fileName.length() - 3));
+ } catch (NumberFormatException e) {
+ if (DEBUG) {
+ Log.e(TAG, fileName + " is not a valid file name.");
+ }
+ }
+ return NO_INSTANCE_ID;
+ }
+}
diff --git a/src/com/android/tv/tuner/source/TsStreamer.java b/src/com/android/tv/tuner/source/TsStreamer.java
new file mode 100644
index 00000000..1ac950bb
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TsStreamer.java
@@ -0,0 +1,56 @@
+/*
+ * 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.source;
+
+import com.android.tv.tuner.ChannelScanFileParser;
+import com.android.tv.tuner.data.TunerChannel;
+
+/**
+ * Interface definition for a stream generator. The interface will provide streams
+ * for scanning channels and/or playback.
+ */
+public interface TsStreamer {
+ /**
+ * Starts streaming the data for channel scanning process.
+ *
+ * @param channel {@link ChannelScanFileParser.ScanChannel} to be scanned
+ * @return {@code true} if ready to stream, otherwise {@code false}
+ */
+ boolean startStream(ChannelScanFileParser.ScanChannel channel);
+
+ /**
+ * Starts streaming the data for channel playing or recording.
+ *
+ * @param channel {@link TunerChannel} to tune
+ * @return {@code true} if ready to stream, otherwise {@code false}
+ */
+ boolean startStream(TunerChannel channel);
+
+ /**
+ * Stops streaming the data.
+ */
+ void stopStream();
+
+ /**
+ * Creates {@link TsDataSource} which will provide MPEG-2 TS stream for
+ * {@link android.media.MediaExtractor}. The source will start from the position
+ * where it is created.
+ *
+ * @return {@link TsDataSource}
+ */
+ TsDataSource createDataSource();
+}
diff --git a/src/com/android/tv/tuner/source/TunerTsStreamer.java b/src/com/android/tv/tuner/source/TunerTsStreamer.java
new file mode 100644
index 00000000..b24048e6
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TunerTsStreamer.java
@@ -0,0 +1,363 @@
+/*
+ * 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.source;
+
+import android.content.Context;
+import android.util.Log;
+
+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;
+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 java.io.IOException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Provides MPEG-2 TS stream sources for channel playing from an underlying tuner device.
+ */
+public class TunerTsStreamer implements TsStreamer {
+ private static final String TAG = "TunerTsStreamer";
+
+ private static final int MIN_READ_UNIT = 1500;
+ private static final int READ_BUFFER_SIZE = MIN_READ_UNIT * 10; // ~15KB
+ private static final int CIRCULAR_BUFFER_SIZE = MIN_READ_UNIT * 20000; // ~ 30MB
+
+ private static final int READ_TIMEOUT_MS = 5000; // 5 secs.
+ private static final int BUFFER_UNDERRUN_SLEEP_MS = 10;
+
+ private final Object mCircularBufferMonitor = new Object();
+ private final byte[] mCircularBuffer = new byte[CIRCULAR_BUFFER_SIZE];
+ private long mBytesFetched;
+ private final AtomicLong mLastReadPosition = new AtomicLong();
+ private boolean mEndOfStreamSent;
+ private boolean mStreaming;
+
+ private final TunerHal mTunerHal;
+ private TunerChannel mChannel;
+ private Thread mStreamingThread;
+ private final EventDetector mEventDetector;
+
+ private final TsStreamWriter mTsStreamWriter;
+
+ public static class TunerDataSource extends TsDataSource {
+ private final TunerTsStreamer mTsStreamer;
+ private final AtomicLong mLastReadPosition = new AtomicLong(0);
+ private long mStartBufferedPosition;
+
+ private TunerDataSource(TunerTsStreamer tsStreamer) {
+ mTsStreamer = tsStreamer;
+ mStartBufferedPosition = tsStreamer.getBufferedPosition();
+ }
+
+ @Override
+ public long getBufferedPosition() {
+ return mTsStreamer.getBufferedPosition() - mStartBufferedPosition;
+ }
+
+ @Override
+ public long getLastReadPosition() {
+ return mLastReadPosition.get();
+ }
+
+ @Override
+ public void shiftStartPosition(long offset) {
+ SoftPreconditions.checkState(mLastReadPosition.get() == 0);
+ SoftPreconditions.checkArgument(0 <= offset && offset <= getBufferedPosition());
+ mStartBufferedPosition += offset;
+ }
+
+ @Override
+ public long open(DataSpec dataSpec) throws IOException {
+ mLastReadPosition.set(0);
+ return C.LENGTH_UNBOUNDED;
+ }
+
+ @Override
+ public void close() {
+ }
+
+ @Override
+ public int read(byte[] buffer, int offset, int readLength) throws IOException {
+ int ret = mTsStreamer.readAt(mStartBufferedPosition + mLastReadPosition.get(), buffer,
+ offset, readLength);
+ if (ret > 0) {
+ mLastReadPosition.addAndGet(ret);
+ }
+ return ret;
+ }
+ }
+ /**
+ * Creates {@link TsStreamer} for playing or recording the specified channel.
+ * @param tunerHal the HAL for tuner device
+ * @param eventListener the listener for channel & program information
+ */
+ public TunerTsStreamer(TunerHal tunerHal, EventListener eventListener, Context context) {
+ mTunerHal = tunerHal;
+ mEventDetector = new EventDetector(mTunerHal, eventListener);
+ mTsStreamWriter = context != null && TunerPreferences.getStoreTsStream(context) ?
+ new TsStreamWriter(context) : null;
+ }
+
+ public TunerTsStreamer(TunerHal tunerHal, EventListener eventListener) {
+ this(tunerHal, eventListener, null);
+ }
+
+ @Override
+ public boolean startStream(TunerChannel channel) {
+ if (mTunerHal.tune(channel.getFrequency(), channel.getModulation())) {
+ if (channel.hasVideo()) {
+ mTunerHal.addPidFilter(channel.getVideoPid(),
+ TunerHal.FILTER_TYPE_VIDEO);
+ }
+ boolean audioFilterSet = false;
+ for (Integer audioPid : channel.getAudioPids()) {
+ if (!audioFilterSet) {
+ mTunerHal.addPidFilter(audioPid, TunerHal.FILTER_TYPE_AUDIO);
+ audioFilterSet = true;
+ } else {
+ // FILTER_TYPE_AUDIO overrides the previous filter for audio. We use
+ // FILTER_TYPE_OTHER from the secondary one to get the all audio tracks.
+ mTunerHal.addPidFilter(audioPid, TunerHal.FILTER_TYPE_OTHER);
+ }
+ }
+ mTunerHal.addPidFilter(channel.getPcrPid(),
+ TunerHal.FILTER_TYPE_PCR);
+ if (mEventDetector != null) {
+ mEventDetector.startDetecting(channel.getFrequency(), channel.getModulation(),
+ channel.getProgramNumber());
+ }
+ mChannel = channel;
+ synchronized (mCircularBufferMonitor) {
+ if (mStreaming) {
+ Log.w(TAG, "Streaming should be stopped before start streaming");
+ return true;
+ }
+ mStreaming = true;
+ mBytesFetched = 0;
+ mLastReadPosition.set(0L);
+ mEndOfStreamSent = false;
+ }
+ if (mTsStreamWriter != null) {
+ mTsStreamWriter.setChannel(mChannel);
+ mTsStreamWriter.openFile();
+ }
+ mStreamingThread = new StreamingThread();
+ mStreamingThread.start();
+ Log.i(TAG, "Streaming started");
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean startStream(ChannelScanFileParser.ScanChannel channel) {
+ if (mTunerHal.tune(channel.frequency, channel.modulation)) {
+ mEventDetector.startDetecting(
+ channel.frequency, channel.modulation, EventDetector.ALL_PROGRAM_NUMBERS);
+ synchronized (mCircularBufferMonitor) {
+ if (mStreaming) {
+ Log.w(TAG, "Streaming should be stopped before start streaming");
+ return true;
+ }
+ mStreaming = true;
+ mBytesFetched = 0;
+ mLastReadPosition.set(0L);
+ mEndOfStreamSent = false;
+ }
+ mStreamingThread = new StreamingThread();
+ mStreamingThread.start();
+ Log.i(TAG, "Streaming started");
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Blocks the current thread until the streaming thread stops. In rare cases when the tuner
+ * device is overloaded this can take a while, but usually it returns pretty quickly.
+ */
+ @Override
+ public void stopStream() {
+ mChannel = null;
+ synchronized (mCircularBufferMonitor) {
+ mStreaming = false;
+ mCircularBufferMonitor.notifyAll();
+ }
+
+ try {
+ if (mStreamingThread != null) {
+ mStreamingThread.join();
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ if (mTsStreamWriter != null) {
+ mTsStreamWriter.closeFile(true);
+ mTsStreamWriter.setChannel(null);
+ }
+ }
+
+ @Override
+ public TsDataSource createDataSource() {
+ return new TunerDataSource(this);
+ }
+
+ /**
+ * Returns incomplete channel lists which was scanned so far. Incomplete channel means
+ * the channel whose channel information is not complete or is not well-formed.
+ * @return {@link List} of {@link TunerChannel}
+ */
+ public List<TunerChannel> getMalFormedChannels() {
+ return mEventDetector.getMalFormedChannels();
+ }
+
+ /**
+ * Returns the current {@link TunerHal} which provides MPEG-TS stream for TunerTsStreamer.
+ * @return {@link TunerHal}
+ */
+ public TunerHal getTunerHal() {
+ return mTunerHal;
+ }
+
+ /**
+ * Returns the current tuned channel for TunerTsStreamer.
+ * @return {@link TunerChannel}
+ */
+ public TunerChannel getChannel() {
+ return mChannel;
+ }
+
+ /**
+ * Returns the current buffered position from tuner.
+ * @return the current buffered position
+ */
+ public long getBufferedPosition() {
+ synchronized (mCircularBufferMonitor) {
+ return mBytesFetched;
+ }
+ }
+
+ private class StreamingThread extends Thread {
+ @Override
+ public void run() {
+ // Buffers for streaming data from the tuner and the internal buffer.
+ byte[] dataBuffer = new byte[READ_BUFFER_SIZE];
+
+ while (true) {
+ synchronized (mCircularBufferMonitor) {
+ if (!mStreaming) {
+ break;
+ }
+ }
+
+ int bytesWritten = mTunerHal.readTsStream(dataBuffer, dataBuffer.length);
+ if (bytesWritten <= 0) {
+ try {
+ // When buffer is underrun, we sleep for short time to prevent
+ // unnecessary CPU draining.
+ sleep(BUFFER_UNDERRUN_SLEEP_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ continue;
+ }
+
+ if (mTsStreamWriter != null) {
+ mTsStreamWriter.writeToFile(dataBuffer, bytesWritten);
+ }
+
+ if (mEventDetector != null) {
+ mEventDetector.feedTSStream(dataBuffer, 0, bytesWritten);
+ }
+ synchronized (mCircularBufferMonitor) {
+ int posInBuffer = (int) (mBytesFetched % CIRCULAR_BUFFER_SIZE);
+ int bytesToCopyInFirstPass = bytesWritten;
+ if (posInBuffer + bytesToCopyInFirstPass > mCircularBuffer.length) {
+ bytesToCopyInFirstPass = mCircularBuffer.length - posInBuffer;
+ }
+ System.arraycopy(dataBuffer, 0, mCircularBuffer, posInBuffer,
+ bytesToCopyInFirstPass);
+ if (bytesToCopyInFirstPass < bytesWritten) {
+ System.arraycopy(dataBuffer, bytesToCopyInFirstPass, mCircularBuffer, 0,
+ bytesWritten - bytesToCopyInFirstPass);
+ }
+ mBytesFetched += bytesWritten;
+ mCircularBufferMonitor.notifyAll();
+ }
+ }
+
+ Log.i(TAG, "Streaming stopped");
+ }
+ }
+
+ /**
+ * Reads data from internal buffer.
+ * @param pos the position to read from
+ * @param buffer to read
+ * @param offset start position of the read buffer
+ * @param amount number of bytes to read
+ * @return number of read bytes when successful, {@code -1} otherwise
+ * @throws IOException
+ */
+ public int readAt(long pos, byte[] buffer, int offset, int amount) throws IOException {
+ long readStartTime = System.currentTimeMillis();
+ while (true) {
+ synchronized (mCircularBufferMonitor) {
+ if (mEndOfStreamSent || !mStreaming) {
+ return -1;
+ }
+ if (mBytesFetched - CIRCULAR_BUFFER_SIZE > pos) {
+ Log.e(TAG, "Demux is requesting the data which is already overwritten.");
+ return -1;
+ }
+ if (System.currentTimeMillis() - readStartTime > READ_TIMEOUT_MS) {
+ // Nothing was received during READ_TIMEOUT_MS before.
+ mEndOfStreamSent = true;
+ mCircularBufferMonitor.notifyAll();
+ return -1;
+ }
+ if (mBytesFetched < pos + amount) {
+ try {
+ mCircularBufferMonitor.wait(READ_TIMEOUT_MS);
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ // Try again to prevent starvation.
+ // Give chances to read from other threads.
+ continue;
+ }
+ int startPos = (int) (pos % CIRCULAR_BUFFER_SIZE);
+ int endPos = (int) ((pos + amount) % CIRCULAR_BUFFER_SIZE);
+ int firstLength = (startPos > endPos ? CIRCULAR_BUFFER_SIZE : endPos) - startPos;
+ System.arraycopy(mCircularBuffer, startPos, buffer, offset, firstLength);
+ if (firstLength < amount) {
+ System.arraycopy(mCircularBuffer, 0, buffer, offset + firstLength,
+ amount - firstLength);
+ }
+ mCircularBufferMonitor.notifyAll();
+ return amount;
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/tuner/source/TunerTsStreamerManager.java b/src/com/android/tv/tuner/source/TunerTsStreamerManager.java
new file mode 100644
index 00000000..cf1f6dcf
--- /dev/null
+++ b/src/com/android/tv/tuner/source/TunerTsStreamerManager.java
@@ -0,0 +1,287 @@
+/*
+ * 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.source;
+
+import android.content.Context;
+
+import com.android.tv.common.AutoCloseableUtils;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.tuner.TunerHal;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.tvinput.EventDetector;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Manages {@link TunerTsStreamer} for playback and recording.
+ * The class hides handling of {@link TunerHal} from other classes.
+ * This class is used by {@link TsDataSourceManager}. Don't use this class directly.
+ */
+class TunerTsStreamerManager {
+ // The lock will protect mStreamerFinder, mSourceToStreamerMap and some part of TsStreamCreator
+ // to support timely {@link TunerTsStreamer} cancellation due to a new tune request from
+ // the same session.
+ private final Object mCancelLock = new Object();
+ private final StreamerFinder mStreamerFinder = new StreamerFinder();
+ private final Map<Integer, TsStreamerCreator> mCreators = new HashMap<>();
+ private final Map<TsDataSource, TunerTsStreamer> mSourceToStreamerMap = new HashMap<>();
+ private final TunerHalManager mTunerHalManager = new TunerHalManager();
+ private static TunerTsStreamerManager sInstance;
+
+ /**
+ * Returns the singleton instance for the class
+ * @return TunerTsStreamerManager
+ */
+ static synchronized TunerTsStreamerManager getInstance() {
+ if (sInstance == null) {
+ sInstance = new TunerTsStreamerManager();
+ }
+ return sInstance;
+ }
+
+ private TunerTsStreamerManager() { }
+
+ synchronized TsDataSource createDataSource(
+ Context context, TunerChannel channel, EventDetector.EventListener listener,
+ int sessionId, boolean reuse) {
+ TsStreamerCreator creator;
+ synchronized (mCancelLock) {
+ if (mStreamerFinder.containsLocked(channel)) {
+ mStreamerFinder.appendSessionLocked(channel, sessionId);
+ TunerTsStreamer streamer = mStreamerFinder.getStreamerLocked(channel);
+ TsDataSource source = streamer.createDataSource();
+ mSourceToStreamerMap.put(source, streamer);
+ return source;
+ }
+ creator = new TsStreamerCreator(context, channel, listener);
+ mCreators.put(sessionId, creator);
+ }
+ TunerTsStreamer streamer = creator.create(sessionId, reuse);
+ synchronized (mCancelLock) {
+ mCreators.remove(sessionId);
+ if (streamer == null) {
+ return null;
+ }
+ if (!creator.isCancelledLocked()) {
+ mStreamerFinder.putLocked(channel, sessionId, streamer);
+ TsDataSource source = streamer.createDataSource();
+ mSourceToStreamerMap.put(source, streamer);
+ return source;
+ }
+ }
+ // Created streamer was cancelled by a new tune request.
+ streamer.stopStream();
+ TunerHal hal = streamer.getTunerHal();
+ hal.setHasPendingTune(false);
+ mTunerHalManager.releaseTunerHal(hal, sessionId, reuse);
+ return null;
+ }
+
+ synchronized void releaseDataSource(TsDataSource source, int sessionId,
+ boolean reuse) {
+ TunerTsStreamer streamer;
+ synchronized (mCancelLock) {
+ streamer = mSourceToStreamerMap.get(source);
+ mSourceToStreamerMap.remove(source);
+ if (streamer == null) {
+ return;
+ }
+ TunerChannel channel = streamer.getChannel();
+ SoftPreconditions.checkState(channel != null);
+ mStreamerFinder.removeSessionLocked(channel, sessionId);
+ if (mStreamerFinder.containsLocked(channel)) {
+ return;
+ }
+ }
+ streamer.stopStream();
+ TunerHal hal = streamer.getTunerHal();
+ hal.setHasPendingTune(false);
+ mTunerHalManager.releaseTunerHal(hal, sessionId, reuse);
+ }
+
+ void setHasPendingTune(int sessionId) {
+ synchronized (mCancelLock) {
+ if (mCreators.containsKey(sessionId)) {
+ mCreators.get(sessionId).cancelLocked();
+ }
+ }
+ }
+
+ synchronized void release(int sessionId) {
+ mTunerHalManager.releaseCachedHal(sessionId);
+ }
+
+ private class StreamerFinder {
+ private final Map<TunerChannel, Set<Integer>> mSessions = new HashMap<>();
+ private final Map<TunerChannel, TunerTsStreamer> mStreamers = new HashMap<>();
+
+ // @GuardedBy("mCancelLock")
+ private void putLocked(TunerChannel channel, int sessionId, TunerTsStreamer streamer) {
+ Set<Integer> sessions = new HashSet<>();
+ sessions.add(sessionId);
+ mSessions.put(channel, sessions);
+ mStreamers.put(channel, streamer);
+ }
+
+ // @GuardedBy("mCancelLock")
+ private void appendSessionLocked(TunerChannel channel, int sessionId) {
+ if (mSessions.containsKey(channel)) {
+ mSessions.get(channel).add(sessionId);
+ }
+ }
+
+ // @GuardedBy("mCancelLock")
+ private void removeSessionLocked(TunerChannel channel, int sessionId) {
+ Set<Integer> sessions = mSessions.get(channel);
+ sessions.remove(sessionId);
+ if (sessions.size() == 0) {
+ mSessions.remove(channel);
+ mStreamers.remove(channel);
+ }
+ }
+
+ // @GuardedBy("mCancelLock")
+ private boolean containsLocked(TunerChannel channel) {
+ return mSessions.containsKey(channel);
+ }
+
+ // @GuardedBy("mCancelLock")
+ private TunerTsStreamer getStreamerLocked(TunerChannel channel) {
+ return mStreamers.containsKey(channel) ? mStreamers.get(channel) : null;
+ }
+ }
+
+ /**
+ * {@link TunerTsStreamer} creation can be cancelled by a new tune request for the same
+ * session. The class supports the cancellation in creating new {@link TunerTsStreamer}.
+ */
+ private class TsStreamerCreator {
+ private final Context mContext;
+ private final TunerChannel mChannel;
+ private final EventDetector.EventListener mEventListener;
+ // mCancelled will be {@code true} if a new tune request for the same session
+ // cancels create().
+ private boolean mCancelled;
+ private TunerHal mTunerHal;
+
+ private TsStreamerCreator(Context context, TunerChannel channel,
+ EventDetector.EventListener listener) {
+ mContext = context;
+ mChannel = channel;
+ mEventListener = listener;
+ }
+
+ private TunerTsStreamer create(int sessionId, boolean reuse) {
+ TunerHal hal = mTunerHalManager.getOrCreateTunerHal(mContext, sessionId);
+ if (hal == null) {
+ return null;
+ }
+ boolean canceled = false;
+ synchronized (mCancelLock) {
+ if (!mCancelled) {
+ mTunerHal = hal;
+ } else {
+ canceled = true;
+ }
+ }
+ if (!canceled) {
+ TunerTsStreamer tsStreamer = new TunerTsStreamer(hal, mEventListener, mContext);
+ if (tsStreamer.startStream(mChannel)) {
+ return tsStreamer;
+ }
+ synchronized (mCancelLock) {
+ mTunerHal = null;
+ }
+ }
+ hal.setHasPendingTune(false);
+ // Since TunerTsStreamer is not properly created, closes TunerHal.
+ // And do not re-use TunerHal when it is not cancelled.
+ mTunerHalManager.releaseTunerHal(hal, sessionId, mCancelled && reuse);
+ return null;
+ }
+
+ // @GuardedBy("mCancelLock")
+ private void cancelLocked() {
+ if (mCancelled) {
+ return;
+ }
+ mCancelled = true;
+ if (mTunerHal != null) {
+ mTunerHal.setHasPendingTune(true);
+ }
+ }
+
+ // @GuardedBy("mCancelLock")
+ private boolean isCancelledLocked() {
+ return mCancelled;
+ }
+ }
+
+ /**
+ * Supports sharing {@link TunerHal} among multiple sessions.
+ * The class also supports session affinity for {@link TunerHal} allocation.
+ */
+ private class TunerHalManager {
+ private final Map<Integer, TunerHal> mTunerHals = new HashMap<>();
+
+ private TunerHal getOrCreateTunerHal(Context context, int sessionId) {
+ // Handles session affinity.
+ TunerHal hal = mTunerHals.get(sessionId);
+ if (hal != null) {
+ mTunerHals.remove(sessionId);
+ return hal;
+ }
+ // Finds a TunerHal which is cached for other sessions.
+ Iterator it = mTunerHals.keySet().iterator();
+ if (it.hasNext()) {
+ Integer key = (Integer) it.next();
+ hal = mTunerHals.get(key);
+ mTunerHals.remove(key);
+ return hal;
+ }
+ return TunerHal.createInstance(context);
+ }
+
+ private void releaseTunerHal(TunerHal hal, int sessionId, boolean reuse) {
+ if (!reuse) {
+ AutoCloseableUtils.closeQuietly(hal);
+ return;
+ }
+ TunerHal cachedHal = mTunerHals.get(sessionId);
+ if (cachedHal != hal) {
+ mTunerHals.put(sessionId, hal);
+ }
+ if (cachedHal != null && cachedHal != hal) {
+ AutoCloseableUtils.closeQuietly(cachedHal);
+ }
+ }
+
+ private void releaseCachedHal(int sessionId) {
+ TunerHal hal = mTunerHals.get(sessionId);
+ if (hal != null) {
+ mTunerHals.remove(sessionId);
+ }
+ if (hal != null) {
+ AutoCloseableUtils.closeQuietly(hal);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/usbtuner/src/com/android/usbtuner/ts/SectionParser.java b/src/com/android/tv/tuner/ts/SectionParser.java
index 0553904c..5d3e728a 100644
--- a/usbtuner/src/com/android/usbtuner/ts/SectionParser.java
+++ b/src/com/android/tv/tuner/ts/SectionParser.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.ts;
+package com.android.tv.tuner.ts;
import android.media.tv.TvContentRating;
import android.media.tv.TvContract.Programs.Genres;
@@ -22,26 +22,26 @@ import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.PsiData.PatItem;
-import com.android.usbtuner.data.PsiData.PmtItem;
-import com.android.usbtuner.data.PsipData.Ac3AudioDescriptor;
-import com.android.usbtuner.data.PsipData.CaptionServiceDescriptor;
-import com.android.usbtuner.data.PsipData.ContentAdvisoryDescriptor;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.PsipData.EttItem;
-import com.android.usbtuner.data.PsipData.ExtendedChannelNameDescriptor;
-import com.android.usbtuner.data.PsipData.GenreDescriptor;
-import com.android.usbtuner.data.PsipData.Iso639LanguageDescriptor;
-import com.android.usbtuner.data.PsipData.MgtItem;
-import com.android.usbtuner.data.PsipData.PsipSection;
-import com.android.usbtuner.data.PsipData.RatingRegion;
-import com.android.usbtuner.data.PsipData.RegionalRating;
-import com.android.usbtuner.data.PsipData.TsDescriptor;
-import com.android.usbtuner.data.PsipData.VctItem;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.util.ByteArrayBuffer;
+import com.android.tv.tuner.data.Channel;
+import com.android.tv.tuner.data.PsiData.PatItem;
+import com.android.tv.tuner.data.PsiData.PmtItem;
+import com.android.tv.tuner.data.PsipData.Ac3AudioDescriptor;
+import com.android.tv.tuner.data.PsipData.CaptionServiceDescriptor;
+import com.android.tv.tuner.data.PsipData.ContentAdvisoryDescriptor;
+import com.android.tv.tuner.data.PsipData.EitItem;
+import com.android.tv.tuner.data.PsipData.EttItem;
+import com.android.tv.tuner.data.PsipData.ExtendedChannelNameDescriptor;
+import com.android.tv.tuner.data.PsipData.GenreDescriptor;
+import com.android.tv.tuner.data.PsipData.Iso639LanguageDescriptor;
+import com.android.tv.tuner.data.PsipData.MgtItem;
+import com.android.tv.tuner.data.PsipData.PsipSection;
+import com.android.tv.tuner.data.PsipData.RatingRegion;
+import com.android.tv.tuner.data.PsipData.RegionalRating;
+import com.android.tv.tuner.data.PsipData.TsDescriptor;
+import com.android.tv.tuner.data.PsipData.VctItem;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.util.ByteArrayBuffer;
import com.ibm.icu.text.UnicodeDecompressor;
@@ -292,6 +292,33 @@ public class SectionParser {
"Volleyball", "Wrestling",
};
+ // Audio language code map from ISO 639-2/B to 639-2/T, in order to show correct audio language.
+ private static final HashMap<String, String> ISO_LANGUAGE_CODE_MAP;
+ static {
+ ISO_LANGUAGE_CODE_MAP = new HashMap<>();
+ ISO_LANGUAGE_CODE_MAP.put("alb", "sqi");
+ ISO_LANGUAGE_CODE_MAP.put("arm", "hye");
+ ISO_LANGUAGE_CODE_MAP.put("baq", "eus");
+ ISO_LANGUAGE_CODE_MAP.put("bur", "mya");
+ ISO_LANGUAGE_CODE_MAP.put("chi", "zho");
+ ISO_LANGUAGE_CODE_MAP.put("cze", "ces");
+ ISO_LANGUAGE_CODE_MAP.put("dut", "nld");
+ ISO_LANGUAGE_CODE_MAP.put("fre", "fra");
+ ISO_LANGUAGE_CODE_MAP.put("geo", "kat");
+ ISO_LANGUAGE_CODE_MAP.put("ger", "deu");
+ ISO_LANGUAGE_CODE_MAP.put("gre", "ell");
+ ISO_LANGUAGE_CODE_MAP.put("ice", "isl");
+ ISO_LANGUAGE_CODE_MAP.put("mac", "mkd");
+ ISO_LANGUAGE_CODE_MAP.put("mao", "mri");
+ ISO_LANGUAGE_CODE_MAP.put("may", "msa");
+ ISO_LANGUAGE_CODE_MAP.put("per", "fas");
+ ISO_LANGUAGE_CODE_MAP.put("rum", "ron");
+ ISO_LANGUAGE_CODE_MAP.put("slo", "slk");
+ ISO_LANGUAGE_CODE_MAP.put("tib", "bod");
+ ISO_LANGUAGE_CODE_MAP.put("wel", "cym");
+ ISO_LANGUAGE_CODE_MAP.put("esl", "spa"); // Special entry for channel 9-1 KQED in bay area.
+ }
+
// 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<>();
@@ -300,12 +327,12 @@ public class SectionParser {
void onPatParsed(List<PatItem> items);
void onPmtParsed(int programNumber, List<PmtItem> items);
void onMgtParsed(List<MgtItem> items);
- void onVctParsed(List<VctItem> items);
+ void onVctParsed(List<VctItem> items, int sectionNumber, int lastSectionNumber);
void onEitParsed(int sourceId, List<EitItem> items);
void onEttParsed(int sourceId, List<EttItem> descriptions);
}
- private OutputListener mListener;
+ private final OutputListener mListener;
public SectionParser(OutputListener listener) {
mListener = listener;
@@ -432,6 +459,10 @@ public class SectionParser {
}
List<PmtItem> results = new ArrayList<>();
for (; pos < data.length - 4;) {
+ if (pos < 0) {
+ Log.e(TAG, "Broken PMT.");
+ return false;
+ }
int streamType = data[pos] & 0xff;
int esPid = (data[pos + 1] & 0x1f) << 8 | (data[pos + 2] & 0xff);
int esInfoLen = (data[pos + 3] & 0xf) << 8 | (data[pos + 4] & 0xff);
@@ -499,6 +530,15 @@ public class SectionParser {
return false;
}
int numChannelsInSection = (data[9] & 0xff);
+ int sectionNumber = (data[6] & 0xff);
+ int lastSectionNumber = (data[7] & 0xff);
+ if (sectionNumber > lastSectionNumber) {
+ // According to section 6.3.1 of the spec ATSC A/65,
+ // last section number is the largest section number.
+ Log.w(TAG, "Invalid VCT. Section Number " + sectionNumber + " > Last Section Number "
+ + lastSectionNumber);
+ return false;
+ }
int pos = 10;
List<VctItem> results = new ArrayList<>();
for (int i = 0; i < numChannelsInSection; ++i) {
@@ -566,12 +606,10 @@ public class SectionParser {
programNumber, majorNumber, minorNumber, sourceId));
}
}
- if ((data[pos] & 0xfc) != 0xfc) {
- Log.e(TAG, "Broken VCT.");
- return false;
- }
+ // Skip the remaining descriptor part which we don't use.
+
if (mListener != null) {
- mListener.onVctParsed(results);
+ mListener.onVctParsed(results, sectionNumber, lastSectionNumber);
}
return true;
}
@@ -671,7 +709,7 @@ public class SectionParser {
// Language descriptor.
List<AtscAudioTrack> ac3Tracks = new ArrayList<>();
List<AtscAudioTrack> iso639LanguageTracks = new ArrayList<>();
- for (TsDescriptor descriptor : descriptors) {
+ for (TsDescriptor descriptor : descriptors) {
if (descriptor instanceof Ac3AudioDescriptor) {
Ac3AudioDescriptor audioDescriptor =
(Ac3AudioDescriptor) descriptor;
@@ -722,12 +760,16 @@ public class SectionParser {
audioTrack = iso639LanguageTracks.get(i);
} else {
AtscAudioTrack iso639LanguageTrack = iso639LanguageTracks.get(i);
- if (audioTrack.language == null) {
+ if (audioTrack.language == null || TextUtils.equals(audioTrack.language, "")) {
audioTrack.language = iso639LanguageTrack.language;
}
audioTrack.audioType = iso639LanguageTrack.audioType;
}
}
+ String language = ISO_LANGUAGE_CODE_MAP.get(audioTrack.language);
+ if (language != null) {
+ audioTrack.language = language;
+ }
tracks.add(audioTrack);
}
return tracks;
diff --git a/usbtuner/src/com/android/usbtuner/ts/TsParser.java b/src/com/android/tv/tuner/ts/TsParser.java
index 838baad9..c24c2a21 100644
--- a/usbtuner/src/com/android/usbtuner/ts/TsParser.java
+++ b/src/com/android/tv/tuner/ts/TsParser.java
@@ -14,21 +14,21 @@
* limitations under the License.
*/
-package com.android.usbtuner.ts;
+package com.android.tv.tuner.ts;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.usbtuner.data.PsiData.PatItem;
-import com.android.usbtuner.data.PsiData.PmtItem;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.PsipData.EttItem;
-import com.android.usbtuner.data.PsipData.MgtItem;
-import com.android.usbtuner.data.PsipData.VctItem;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.ts.SectionParser.OutputListener;
-import com.android.usbtuner.util.ByteArrayBuffer;
+import com.android.tv.tuner.data.PsiData.PatItem;
+import com.android.tv.tuner.data.PsiData.PmtItem;
+import com.android.tv.tuner.data.PsipData.EitItem;
+import com.android.tv.tuner.data.PsipData.EttItem;
+import com.android.tv.tuner.data.PsipData.MgtItem;
+import com.android.tv.tuner.data.PsipData.VctItem;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.ts.SectionParser.OutputListener;
+import com.android.tv.tuner.util.ByteArrayBuffer;
import java.util.ArrayList;
import java.util.Arrays;
@@ -42,7 +42,7 @@ import java.util.TreeSet;
*/
public class TsParser {
private static final String TAG = "TsParser";
- private static boolean DEBUG = false;
+ private static final boolean DEBUG = false;
public static final int ATSC_SI_BASE_PID = 0x1ffb;
public static final int PAT_PID = 0x0000;
@@ -70,10 +70,12 @@ public class TsParser {
private final TreeSet<Integer> mETTPids = new TreeSet<>();
private final SparseBooleanArray mProgramNumberHandledStatus = new SparseBooleanArray();
private final SparseBooleanArray mVctItemHandledStatus = new SparseBooleanArray();
- private TsOutputListener mListener;
+ private final TsOutputListener mListener;
- private int mPartialTSPacketSize;
- private byte[] mPartialTSPacketBuf = new byte[TS_PACKET_SIZE];
+ private int mVctItemCount;
+ private int mHandledVctItemCount;
+ private int mVctSectionParsedCount;
+ private boolean[] mVctSectionParsed;
public interface TsOutputListener {
void onPatDetected(List<PatItem> items);
@@ -81,6 +83,7 @@ public class TsParser {
void onVctItemParsed(VctItem channel, List<PmtItem> pmtItems);
void onEitItemParsed(VctItem channel, List<EitItem> items);
void onEttPidDetected(int pid);
+ void onAllVctItemsParsed();
}
private abstract class Stream {
@@ -135,7 +138,7 @@ public class TsParser {
mSectionParser.parseSections(mPacket);
}
- private OutputListener mSectionListener = new OutputListener() {
+ private final OutputListener mSectionListener = new OutputListener() {
@Override
public void onPatParsed(List<PatItem> items) {
for (PatItem i : items) {
@@ -156,14 +159,19 @@ public class TsParser {
int statusIndex = mProgramNumberHandledStatus.indexOfKey(programNumber);
if (statusIndex < 0) {
mProgramNumberHandledStatus.put(programNumber, false);
- return;
}
- if (!mProgramNumberHandledStatus.valueAt(statusIndex)) {
+ if (!mProgramNumberHandledStatus.get(programNumber)) {
VctItem vctItem = mProgramNumberToVctItemMap.get(programNumber);
if (vctItem != null) {
// When PMT is parsed later than VCT.
mProgramNumberHandledStatus.put(programNumber, true);
handleVctItem(vctItem, items);
+ mHandledVctItemCount++;
+ if (mHandledVctItemCount >= mVctItemCount
+ && mVctSectionParsedCount >= mVctSectionParsed.length
+ && mListener != null) {
+ mListener.onAllVctItemsParsed();
+ }
}
}
}
@@ -194,7 +202,19 @@ public class TsParser {
}
@Override
- public void onVctParsed(List<VctItem> items) {
+ public void onVctParsed(List<VctItem> items, int sectionNumber, int lastSectionNumber) {
+ if (mVctSectionParsed == null) {
+ mVctSectionParsed = new boolean[lastSectionNumber + 1];
+ } else if (mVctSectionParsed[sectionNumber]) {
+ // The current section was handled before.
+ if (DEBUG) {
+ Log.d(TAG, "Duplicate VCT section found.");
+ }
+ return;
+ }
+ mVctSectionParsed[sectionNumber] = true;
+ mVctSectionParsedCount++;
+ mVctItemCount += items.size();
for (VctItem i : items) {
if (DEBUG) Log.d(TAG, "onVCTParsed " + i);
if (i.getSourceId() != 0) {
@@ -207,6 +227,12 @@ public class TsParser {
if (pmtList != null) {
mProgramNumberHandledStatus.put(programNumber, true);
handleVctItem(i, pmtList);
+ mHandledVctItemCount++;
+ if (mHandledVctItemCount >= mVctItemCount
+ && mVctSectionParsedCount >= mVctSectionParsed.length
+ && mListener != null) {
+ mListener.onAllVctItemsParsed();
+ }
} else {
mProgramNumberHandledStatus.put(programNumber, false);
Log.i(TAG, "onVCTParsed, but PMT for programNo " + programNumber
@@ -281,6 +307,9 @@ public class TsParser {
}
private void handleVctItem(VctItem channel, List<PmtItem> pmtItems) {
+ if (DEBUG) {
+ Log.d(TAG, "handleVctItem " + channel);
+ }
if (mListener != null) {
mListener.onVctItemParsed(channel, pmtItems);
}
@@ -342,6 +371,10 @@ public class TsParser {
}
}
+ /**
+ * Creates MPEG-2 TS parser.
+ * @param listener TsOutputListener
+ */
public TsParser(TsOutputListener listener) {
startListening(ATSC_SI_BASE_PID);
startListening(PAT_PID);
@@ -388,26 +421,23 @@ public class TsParser {
return true;
}
+ /**
+ * Feeds MPEG-2 TS data to parse.
+ * @param tsData buffer for ATSC TS stream
+ * @param pos the offset where buffer starts
+ * @param length The length of available data
+ */
public void feedTSData(byte[] tsData, int pos, int length) {
- int origPos = pos;
- if (mPartialTSPacketSize != 0
- && (mPartialTSPacketSize + length) > TS_PACKET_SIZE) {
- System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize,
- TS_PACKET_SIZE - mPartialTSPacketSize);
- feedTSPacket(mPartialTSPacketBuf, 0);
- pos += TS_PACKET_SIZE - mPartialTSPacketSize;
- mPartialTSPacketSize = 0;
- }
for (; pos <= length - TS_PACKET_SIZE; pos += TS_PACKET_SIZE) {
feedTSPacket(tsData, pos);
}
- int remaining = origPos + length - pos;
- if (remaining > 0) {
- System.arraycopy(tsData, pos, mPartialTSPacketBuf, mPartialTSPacketSize, remaining);
- }
}
- public List<TunerChannel> getIncompleteChannels() {
+ /**
+ * Retrieves the channel information regardless of being well-formed.
+ * @return {@link List} of {@link TunerChannel}
+ */
+ public List<TunerChannel> getMalFormedChannels() {
List<TunerChannel> incompleteChannels = new ArrayList<>();
for (int i = 0; i < mProgramNumberHandledStatus.size(); i++) {
if (!mProgramNumberHandledStatus.valueAt(i)) {
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/ChannelDataManager.java b/src/com/android/tv/tuner/tvinput/ChannelDataManager.java
index 57affe22..a16bc522 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/ChannelDataManager.java
+++ b/src/com/android/tv/tuner/tvinput/ChannelDataManager.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.content.ComponentName;
import android.content.ContentProviderOperation;
@@ -29,16 +29,18 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.RemoteException;
+import android.support.annotation.Nullable;
import android.text.format.DateUtils;
import android.util.Log;
-import com.android.usbtuner.UsbTunerPreferences;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.util.ConvertUtils;
-import com.android.usbtuner.util.TisConfiguration;
+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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -46,7 +48,7 @@ import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -67,14 +69,21 @@ public class ChannelDataManager implements Handler.Callback {
TvContract.Programs.COLUMN_VERSION_NUMBER };
private static final String[] CHANNEL_DATA_SELECTION_ARGS = new String[] {
TvContract.Channels._ID,
- TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA };
+ TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA,
+ TvContract.Channels.COLUMN_INTERNAL_PROVIDER_FLAG1};
private static final int MSG_HANDLE_EVENTS = 1;
private static final int MSG_HANDLE_CHANNEL = 2;
private static final int MSG_BUILD_CHANNEL_MAP = 3;
private static final int MSG_REQUEST_PROGRAMS = 4;
private static final int MSG_CLEAR_CHANNELS = 6;
- private static final int MSG_SCAN_COMPLETED = 7;
+ private static final int MSG_CHECK_VERSION = 7;
+
+ // Throttle the batch operations to avoid TransactionTooLargeException.
+ private static final int BATCH_OPERATION_COUNT = 100;
+ // At most 16 days of program information is delivered through an EIT,
+ // according to the Chapter 6.4 of ATSC Recommended Practice A/69.
+ private static final long PROGRAM_QUERY_DURATION = TimeUnit.DAYS.toMillis(16);
/**
* A version number to enforce consistency of the channel data.
@@ -86,19 +95,21 @@ public class ChannelDataManager implements Handler.Callback {
private static final int VERSION = 6;
private final Context mContext;
- private String mInputId;
+ private final String mInputId;
private ProgramInfoListener mListener;
- private HandlerThread mHandlerThread;
- private Handler mHandler;
- private ConcurrentHashMap<Long, TunerChannel> mTunerChannelMap;
- private ConcurrentSkipListMap<TunerChannel, Long> mTunerChannelIdMap;
+ private ChannelScanListener mChannelScanListener;
+ private Handler mChannelScanHandler;
+ private final HandlerThread mHandlerThread;
+ private final Handler mHandler;
+ private final ConcurrentHashMap<Long, TunerChannel> mTunerChannelMap;
+ private final ConcurrentSkipListMap<TunerChannel, Long> mTunerChannelIdMap;
private final Uri mChannelsUri;
// Used for scanning
private final ConcurrentSkipListSet<TunerChannel> mScannedChannels;
private final ConcurrentSkipListSet<TunerChannel> mPreviousScannedChannels;
- private AtomicBoolean mIsScanning;
- private CountDownLatch mScanLatch;
+ private final AtomicBoolean mIsScanning;
+ private final AtomicBoolean scanCompleted = new AtomicBoolean();
public interface ProgramInfoListener {
@@ -126,16 +137,17 @@ public class ChannelDataManager implements Handler.Callback {
void onRescanNeeded();
}
+ public interface ChannelScanListener {
+ /**
+ * Invoked when all pending channels have been handled.
+ */
+ void onChannelHandlingDone();
+ }
+
public ChannelDataManager(Context context) {
mContext = context;
- if (TisConfiguration.isInternalTunerTvInput(context)) {
- mInputId = TvContract.buildInputId(new ComponentName(mContext.getPackageName(),
- InternalTunerTvInputService.class.getName())) + "/HW" +
- TisConfiguration.getTunerHwDeviceId(context);
- } else {
- mInputId = TvContract.buildInputId(new ComponentName(mContext.getPackageName(),
- UsbTunerTvInputService.class.getName()));
- }
+ mInputId = TvContract.buildInputId(new ComponentName(mContext.getPackageName(),
+ TunerTvInputService.class.getName()));
mChannelsUri = TvContract.buildChannelsUriForInput(mInputId);
mTunerChannelMap = new ConcurrentHashMap<>();
mTunerChannelIdMap = new ConcurrentSkipListMap<>();
@@ -149,7 +161,7 @@ public class ChannelDataManager implements Handler.Callback {
// Public methods
public void checkDataVersion(Context context) {
- int version = UsbTunerPreferences.getChannelDataVersion(context);
+ int version = TunerPreferences.getChannelDataVersion(context);
Log.d(TAG, "ChannelDataManager.VERSION=" + VERSION + " (current=" + version + ")");
if (version == VERSION) {
// Everything is awesome. Return and continue.
@@ -157,23 +169,36 @@ public class ChannelDataManager implements Handler.Callback {
}
setCurrentVersion(context);
- // The stored channel data seem outdated. Delete them all.
- mHandler.sendEmptyMessage(MSG_CLEAR_CHANNELS);
+ if (version == TunerPreferences.CHANNEL_DATA_VERSION_NOT_SET) {
+ mHandler.sendEmptyMessage(MSG_CHECK_VERSION);
+ } else {
+ // The stored channel data seem outdated. Delete them all.
+ mHandler.sendEmptyMessage(MSG_CLEAR_CHANNELS);
+ }
}
public void setCurrentVersion(Context context) {
- UsbTunerPreferences.setChannelDataVersion(context, VERSION);
+ TunerPreferences.setChannelDataVersion(context, VERSION);
}
public void setListener(ProgramInfoListener listener) {
mListener = listener;
}
+ public void setChannelScanListener(ChannelScanListener listener, Handler handler) {
+ mChannelScanListener = listener;
+ mChannelScanHandler = handler;
+ }
+
public void release() {
mHandler.removeCallbacksAndMessages(null);
mHandlerThread.quitSafely();
}
+ public void releaseSafely() {
+ mHandlerThread.quitSafely();
+ }
+
public TunerChannel getChannel(long channelId) {
TunerChannel channel = mTunerChannelMap.get(channelId);
if (channel != null) {
@@ -208,7 +233,13 @@ public class ChannelDataManager implements Handler.Callback {
}
public void notifyChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
- mHandler.obtainMessage(MSG_HANDLE_CHANNEL, channel).sendToTarget();
+ if (mIsScanning.get()) {
+ // During scanning, channels should be handle first to improve scan time.
+ // EIT items can be handled in background after channel scan.
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_HANDLE_CHANNEL, channel));
+ } else {
+ mHandler.obtainMessage(MSG_HANDLE_CHANNEL, channel).sendToTarget();
+ }
}
// For scanning process
@@ -238,30 +269,39 @@ public class ChannelDataManager implements Handler.Callback {
/**
* Invoked when completing the scanning mode. Passes {@code MSG_SCAN_COMPLETED} to the handler
- * in order to wait for finish the remaining messages in the handler queue. Then removes the
- * obsolete channels, which are previous scanned but are in the scanned result.
+ * in order to wait for finishing the remaining messages in the handler queue. Then removes the
+ * obsolete channels, which are previously scanned but are not in the current scanned result.
*/
public void notifyScanCompleted() {
- mScanLatch = new CountDownLatch(1);
- mHandler.sendEmptyMessage(MSG_SCAN_COMPLETED);
- try {
- mScanLatch.await();
- } catch (InterruptedException e) {
- Log.e(TAG, "Scanning process could not finish", e);
- }
+ // Send a dummy message to check whether there is any MSG_HANDLE_CHANNEL in queue
+ // and avoid race conditions.
+ scanCompleted.set(true);
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_HANDLE_CHANNEL, null));
+ }
+
+ public void scannedChannelHandlingCompleted() {
mIsScanning.set(false);
- if (mPreviousScannedChannels.isEmpty()) {
- return;
- }
- ArrayList<ContentProviderOperation> ops = new ArrayList<>();
- for (TunerChannel channel : mPreviousScannedChannels) {
- ops.add(ContentProviderOperation.newDelete(
- TvContract.buildChannelUri(channel.getChannelId())).build());
+ if (!mPreviousScannedChannels.isEmpty()) {
+ ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+ for (TunerChannel channel : mPreviousScannedChannels) {
+ ops.add(ContentProviderOperation.newDelete(
+ TvContract.buildChannelUri(channel.getChannelId())).build());
+ }
+ try {
+ mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
+ } catch (RemoteException | OperationApplicationException e) {
+ Log.e(TAG, "Error deleting obsolete channels", e);
+ }
}
- try {
- mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
- } catch (RemoteException | OperationApplicationException e) {
- Log.e(TAG, "Error deleting obsolete channels", e);
+ if (mChannelScanListener != null && mChannelScanHandler != null) {
+ mChannelScanHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mChannelScanListener.onChannelHandlingDone();
+ }
+ });
+ } else {
+ Log.e(TAG, "Error. mChannelScanListener is null.");
}
}
@@ -272,6 +312,13 @@ public class ChannelDataManager implements Handler.Callback {
return mScannedChannels.size();
}
+ /**
+ * Removes all callbacks and messages in handler to avoid previous messages from last channel.
+ */
+ public void removeAllCallbacksAndMessages() {
+ mHandler.removeCallbacksAndMessages(null);
+ }
+
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
@@ -282,7 +329,14 @@ public class ChannelDataManager implements Handler.Callback {
}
case MSG_HANDLE_CHANNEL: {
TunerChannel channel = (TunerChannel) msg.obj;
- handleChannel(channel);
+ if (channel != null) {
+ handleChannel(channel);
+ }
+ if (scanCompleted.get() && mIsScanning.get()
+ && !mHandler.hasMessages(MSG_HANDLE_CHANNEL)) {
+ // Complete the scan when all found channels have already been handled.
+ scannedChannelHandlingCompleted();
+ }
return true;
}
case MSG_BUILD_CHANNEL_MAP: {
@@ -304,8 +358,8 @@ public class ChannelDataManager implements Handler.Callback {
clearChannels();
return true;
}
- case MSG_SCAN_COMPLETED: {
- mScanLatch.countDown();
+ case MSG_CHECK_VERSION: {
+ checkVersion();
return true;
}
}
@@ -319,30 +373,89 @@ public class ChannelDataManager implements Handler.Callback {
return;
}
channel.setChannelId(channelId);
+
+ // Schedule the audio and caption tracks of the current program and the programs being
+ // listed after the current one into TIS.
+ if (mListener != null) {
+ mListener.onProgramsArrived(channel, items);
+ }
+
long currentTime = System.currentTimeMillis();
- List<EitItem> oldItems = getAllProgramsForChannel(channel);
- // TODO: Find a right to check if the programs are added outside.
+ List<EitItem> oldItems = getAllProgramsForChannel(channel, currentTime,
+ currentTime + PROGRAM_QUERY_DURATION);
+ ArrayList<ContentProviderOperation> ops = new ArrayList<>();
+ // TODO: Find a right way to check if the programs are added outside.
+ boolean addedOutside = false;
for (EitItem item : oldItems) {
if (item.getEventId() == 0) {
- // The event has been added outside TV tuner. Do not update programs.
- return;
+ // The event has been added outside TV tuner.
+ addedOutside = true;
+ break;
}
}
+
+ // Inserting programs only when there is no overlapping with existing data assuming that:
+ // 1. external EPG is more accurate and rich and
+ // 2. the data we add here will be updated when we apply external EPG.
+ if (addedOutside) {
+ // oldItemCount cannot be 0 if addedOutside is true.
+ int oldItemCount = oldItems.size();
+ for (EitItem newItem : items) {
+ if (newItem.getEndTimeUtcMillis() < currentTime) {
+ continue;
+ }
+ long newItemStartTime = newItem.getStartTimeUtcMillis();
+ long newItemEndTime = newItem.getEndTimeUtcMillis();
+ if (newItemStartTime < oldItems.get(0).getStartTimeUtcMillis()) {
+ // Start time smaller than that of any old items. Insert if no overlap.
+ if (newItemEndTime > oldItems.get(0).getStartTimeUtcMillis()) continue;
+ } else if (newItemStartTime
+ > oldItems.get(oldItemCount - 1).getStartTimeUtcMillis()) {
+ // Start time larger than that of any old item. Insert if no overlap.
+ if (newItemStartTime
+ < oldItems.get(oldItemCount - 1).getEndTimeUtcMillis()) continue;
+ } else {
+ int pos = Collections.binarySearch(oldItems, newItem,
+ new Comparator<EitItem>() {
+ @Override
+ public int compare(EitItem lhs, EitItem rhs) {
+ return Long.compare(lhs.getStartTimeUtcMillis(),
+ rhs.getStartTimeUtcMillis());
+ }
+ });
+ if (pos >= 0) {
+ // Same start Time found. Overlapped.
+ continue;
+ }
+ int insertPoint = -1 - pos;
+ // Check the two adjacent items.
+ if (newItemStartTime < oldItems.get(insertPoint - 1).getEndTimeUtcMillis()
+ || newItemEndTime > oldItems.get(insertPoint).getStartTimeUtcMillis()) {
+ continue;
+ }
+ }
+ ops.add(buildContentProviderOperation(ContentProviderOperation.newInsert(
+ TvContract.Programs.CONTENT_URI), newItem, channel.getChannelId()));
+ if (ops.size() >= BATCH_OPERATION_COUNT) {
+ applyBatch(channel.getName(), ops);
+ ops.clear();
+ }
+ }
+ applyBatch(channel.getName(), ops);
+ return;
+ }
+
List<EitItem> outdatedOldItems = new ArrayList<>();
- List<EitItem> programsAddedToEPG = new ArrayList<>();
- ArrayList<ContentProviderOperation> ops = new ArrayList<>();
- Map<Integer, EitItem> eitItemMap = new HashMap<>();
+ Map<Integer, EitItem> newEitItemMap = new HashMap<>();
for (EitItem item : items) {
- eitItemMap.put(item.getEventId(), item);
+ newEitItemMap.put(item.getEventId(), item);
}
for (EitItem oldItem : oldItems) {
- EitItem item = eitItemMap.get(oldItem.getEventId());
+ EitItem item = newEitItemMap.get(oldItem.getEventId());
if (item == null) {
outdatedOldItems.add(oldItem);
continue;
}
- items.remove(item);
- programsAddedToEPG.add(item);
// Since program descriptions arrive at different time, the older one may have the
// correct program description while the newer one has no clue what value is.
@@ -356,34 +469,59 @@ public class ChannelDataManager implements Handler.Callback {
item.setDescription(oldItem.getDescription());
}
if (item.compareTo(oldItem) != 0) {
- ops.add(ContentProviderOperation.newUpdate(
- TvContract.buildProgramUri(oldItem.getProgramId()))
- .withValue(TvContract.Programs.COLUMN_TITLE, item.getTitleText())
- .withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
- item.getStartTimeUtcMillis())
- .withValue(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
- item.getEndTimeUtcMillis())
- .withValue(TvContract.Programs.COLUMN_CONTENT_RATING,
- item.getContentRating())
- .withValue(TvContract.Programs.COLUMN_AUDIO_LANGUAGE,
- item.getAudioLanguage())
- .withValue(TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
- item.getDescription())
- .withValue(TvContract.Programs.COLUMN_VERSION_NUMBER,
- item.getEventId())
- .build());
+ ops.add(buildContentProviderOperation(ContentProviderOperation.newUpdate(
+ TvContract.buildProgramUri(oldItem.getProgramId())), item, null));
+ if (ops.size() >= BATCH_OPERATION_COUNT) {
+ applyBatch(channel.getName(), ops);
+ ops.clear();
+ }
}
+ newEitItemMap.remove(item.getEventId());
}
- for (EitItem outdatedOldItem : outdatedOldItems) {
- if (outdatedOldItem.getStartTimeUtcMillis() > currentTime) {
- ops.add(ContentProviderOperation.newDelete(
- TvContract.buildProgramUri(outdatedOldItem.getProgramId())).build());
+ for (EitItem unverifiedOldItems : outdatedOldItems) {
+ if (unverifiedOldItems.getStartTimeUtcMillis() > currentTime) {
+ // The given new EIT item list covers partial time span of EPG. Here, we delete old
+ // item only when it has an overlapping with the new EIT item list.
+ long startTime = unverifiedOldItems.getStartTimeUtcMillis();
+ long endTime = unverifiedOldItems.getEndTimeUtcMillis();
+ for (EitItem item : newEitItemMap.values()) {
+ long newItemStartTime = item.getStartTimeUtcMillis();
+ long newItemEndTime = item.getEndTimeUtcMillis();
+ if ((startTime >= newItemStartTime && startTime < newItemEndTime)
+ || (endTime > newItemStartTime && endTime <= newItemEndTime)) {
+ ops.add(ContentProviderOperation.newDelete(TvContract.buildProgramUri(
+ unverifiedOldItems.getProgramId())).build());
+ if (ops.size() >= BATCH_OPERATION_COUNT) {
+ applyBatch(channel.getName(), ops);
+ ops.clear();
+ }
+ break;
+ }
+ }
}
}
- for (EitItem item : items) {
- ops.add(ContentProviderOperation.newInsert(TvContract.Programs.CONTENT_URI)
- .withValue(TvContract.Programs.COLUMN_CHANNEL_ID, channel.getChannelId())
- .withValue(TvContract.Programs.COLUMN_TITLE, item.getTitleText())
+ for (EitItem item : newEitItemMap.values()) {
+ if (item.getEndTimeUtcMillis() < currentTime) {
+ continue;
+ }
+ ops.add(buildContentProviderOperation(ContentProviderOperation.newInsert(
+ TvContract.Programs.CONTENT_URI), item, channel.getChannelId()));
+ if (ops.size() >= BATCH_OPERATION_COUNT) {
+ applyBatch(channel.getName(), ops);
+ ops.clear();
+ }
+ }
+
+ applyBatch(channel.getName(), ops);
+ }
+
+ private ContentProviderOperation buildContentProviderOperation(
+ ContentProviderOperation.Builder builder, EitItem item, Long channelId) {
+ if (channelId != null) {
+ builder.withValue(TvContract.Programs.COLUMN_CHANNEL_ID, channelId);
+ }
+ if (item != null) {
+ builder.withValue(TvContract.Programs.COLUMN_TITLE, item.getTitleText())
.withValue(TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS,
item.getStartTimeUtcMillis())
.withValue(TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS,
@@ -395,21 +533,16 @@ public class ChannelDataManager implements Handler.Callback {
.withValue(TvContract.Programs.COLUMN_SHORT_DESCRIPTION,
item.getDescription())
.withValue(TvContract.Programs.COLUMN_VERSION_NUMBER,
- item.getEventId())
- .build());
- programsAddedToEPG.add(item);
+ item.getEventId());
}
+ return builder.build();
+ }
+ private void applyBatch(String channelName, ArrayList<ContentProviderOperation> operations) {
try {
- mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, ops);
+ mContext.getContentResolver().applyBatch(TvContract.AUTHORITY, operations);
} catch (RemoteException | OperationApplicationException e) {
- Log.e(TAG, "Error updating EPG " + channel.getName(), e);
- }
-
- // Schedule the audio and caption tracks of the current program and the programs being
- // listed after the current one into TIS.
- if (mListener != null) {
- mListener.onProgramsArrived(channel, programsAddedToEPG);
+ Log.e(TAG, "Error updating EPG " + channelName, e);
}
}
@@ -423,6 +556,8 @@ public class ChannelDataManager implements Handler.Callback {
values.put(TvContract.Channels.COLUMN_DISPLAY_NAME, channel.getName());
values.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, channel.toByteArray());
values.put(TvContract.Channels.COLUMN_DESCRIPTION, channel.getDescription());
+ values.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_FLAG1, VERSION);
+
if (channelId <= 0) {
values.put(TvContract.Channels.COLUMN_INPUT_ID, mInputId);
values.put(TvContract.Channels.COLUMN_TYPE, "QAM256".equals(channel.getModulation())
@@ -462,6 +597,18 @@ public class ChannelDataManager implements Handler.Callback {
}
}
+ private void checkVersion() {
+ String selection = TvContract.Channels.COLUMN_INTERNAL_PROVIDER_FLAG1 + "<>?";
+ try (Cursor cursor = mContext.getContentResolver().query(mChannelsUri,
+ CHANNEL_DATA_SELECTION_ARGS, selection,
+ new String[] {Integer.toString(VERSION)}, null)) {
+ if (cursor != null && cursor.moveToFirst()) {
+ // The stored channel data seem outdated. Delete them all.
+ clearChannels();
+ }
+ }
+ }
+
private long getChannelId(TunerChannel channel) {
Long channelId = mTunerChannelIdMap.get(channel);
if (channelId != null) {
@@ -488,9 +635,17 @@ public class ChannelDataManager implements Handler.Callback {
}
private List<EitItem> getAllProgramsForChannel(TunerChannel channel) {
+ return getAllProgramsForChannel(channel, null, null);
+ }
+
+ private List<EitItem> getAllProgramsForChannel(TunerChannel channel, @Nullable Long startTimeMs,
+ @Nullable Long endTimeMs) {
List<EitItem> items = new ArrayList<>();
- try (Cursor cursor = mContext.getContentResolver().query(
- TvContract.buildProgramsUriForChannel(channel.getChannelId()),
+ long channelId = channel.getChannelId();
+ Uri programsUri = (startTimeMs == null || endTimeMs == null) ?
+ TvContract.buildProgramsUriForChannel(channelId) :
+ TvContract.buildProgramsUriForChannel(channelId, startTimeMs, endTimeMs);
+ try (Cursor cursor = mContext.getContentResolver().query(programsUri,
ALL_PROGRAMS_SELECTION_ARGS, null, null, null)) {
if (cursor != null && cursor.moveToFirst()) {
do {
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/EventDetector.java b/src/com/android/tv/tuner/tvinput/EventDetector.java
index 9d3c1ab9..27bbb8c7 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/EventDetector.java
+++ b/src/com/android/tv/tuner/tvinput/EventDetector.java
@@ -14,22 +14,19 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.usbtuner.TunerHal;
-import com.android.usbtuner.data.PsiData.PatItem;
-import com.android.usbtuner.data.PsiData.PmtItem;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.PsipData.VctItem;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.ts.TsParser;
-import com.android.usbtuner.ts.TsParser.TsOutputListener;
+import com.android.tv.tuner.TunerHal;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.ts.TsParser;
+import com.android.tv.tuner.data.PsiData;
+import com.android.tv.tuner.data.PsipData;
import java.util.ArrayList;
import java.util.HashSet;
@@ -42,6 +39,7 @@ import java.util.Set;
public class EventDetector {
private static final String TAG = "EventDetector";
private static final boolean DEBUG = false;
+ public static final int ALL_PROGRAM_NUMBERS = -1;
private final TunerHal mTunerHal;
@@ -53,15 +51,18 @@ public class EventDetector {
private final SparseArray<TunerChannel> mChannelMap = new SparseArray<>();
private final SparseBooleanArray mVctCaptionTracksFound = new SparseBooleanArray();
private final SparseBooleanArray mEitCaptionTracksFound = new SparseBooleanArray();
- private EventListener mEventListener;
+ private final EventListener mEventListener;
private int mFrequency;
private String mModulation;
+ private int mProgramNumber = ALL_PROGRAM_NUMBERS;
- private TsOutputListener mTsOutputListener = new TsOutputListener() {
+ private final TsParser.TsOutputListener mTsOutputListener = new TsParser.TsOutputListener() {
@Override
- public void onPatDetected(List<PatItem> items) {
- for (PatItem i : items) {
- mTunerHal.addPidFilter(i.getPmtPid(), TunerHal.FILTER_TYPE_OTHER);
+ public void onPatDetected(List<PsiData.PatItem> items) {
+ for (PsiData.PatItem i : items) {
+ if (mProgramNumber == ALL_PROGRAM_NUMBERS || mProgramNumber == i.getProgramNo()) {
+ mTunerHal.addPidFilter(i.getPmtPid(), TunerHal.FILTER_TYPE_OTHER);
+ }
}
}
@@ -71,7 +72,7 @@ public class EventDetector {
}
@Override
- public void onEitItemParsed(VctItem channel, List<EitItem> items) {
+ public void onEitItemParsed(PsipData.VctItem channel, List<PsipData.EitItem> items) {
TunerChannel tunerChannel = mChannelMap.get(channel.getProgramNumber());
if (DEBUG) {
Log.d(TAG, "onEitItemParsed tunerChannel:" + tunerChannel + " "
@@ -89,7 +90,7 @@ public class EventDetector {
// If at least a one caption track have been found in EIT items for the given channel,
// we starts to interpret the zero tracks as a clearance of the caption tracks.
boolean captionTracksFound = mEitCaptionTracksFound.get(channelSourceId);
- for (EitItem item : items) {
+ for (PsipData.EitItem item : items) {
if (captionTracksFound) {
break;
}
@@ -100,7 +101,7 @@ public class EventDetector {
}
mEitCaptionTracksFound.put(channelSourceId, captionTracksFound);
if (captionTracksFound) {
- for (EitItem item : items) {
+ for (PsipData.EitItem item : items) {
item.setHasCaptionTrack();
}
}
@@ -115,7 +116,14 @@ public class EventDetector {
}
@Override
- public void onVctItemParsed(VctItem channel, List<PmtItem> pmtItems) {
+ public void onAllVctItemsParsed() {
+ if (mEventListener != null) {
+ mEventListener.onChannelScanDone();
+ }
+ }
+
+ @Override
+ public void onVctItemParsed(PsipData.VctItem channel, List<PsiData.PmtItem> pmtItems) {
if (DEBUG) {
Log.d(TAG, "onVctItemParsed VCT " + channel);
Log.d(TAG, " PMT " + pmtItems);
@@ -126,7 +134,7 @@ public class EventDetector {
TunerChannel tunerChannel = new TunerChannel(channel, pmtItems);
List<AtscAudioTrack> audioTracks = new ArrayList<>();
List<AtscCaptionTrack> captionTracks = new ArrayList<>();
- for (PmtItem pmtItem : pmtItems) {
+ for (PsiData.PmtItem pmtItem : pmtItems) {
if (pmtItem.getAudioTracks() != null) {
audioTracks.addAll(pmtItem.getAudioTracks());
}
@@ -178,9 +186,19 @@ public class EventDetector {
* @param channel an ATSC TV channel
* @param items a list of EIT items that were received
*/
- void onEventDetected(TunerChannel channel, List<EitItem> items);
+ void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items);
+
+ /**
+ * Fired when information of all detectable ATSC TV channels in current frequency arrived.
+ */
+ void onChannelScanDone();
}
+ /**
+ * Creates a detector for ATSC TV channles and program information.
+ * @param usbTunerInteface {@link TunerHal}
+ * @param listener for ATSC TV channels and program information
+ */
public EventDetector(TunerHal usbTunerInteface, EventListener listener) {
mTunerHal = usbTunerInteface;
mEventListener = listener;
@@ -195,10 +213,19 @@ public class EventDetector {
mChannelMap.clear();
}
- public void startDetecting(int frequency, String modulation) {
+ /**
+ * Starts detecting channel and program information.
+ *
+ * @param frequency The frequency to listen to.
+ * @param modulation The modulation type.
+ * @param programNumber The program number if this is for handling tune request. For scanning
+ * purpose, supply {@link #ALL_PROGRAM_NUMBERS}.
+ */
+ public void startDetecting(int frequency, String modulation, int programNumber) {
reset();
mFrequency = frequency;
mModulation = modulation;
+ mProgramNumber = programNumber;
}
private void startListening(int pid) {
@@ -209,6 +236,12 @@ public class EventDetector {
mTunerHal.addPidFilter(pid, TunerHal.FILTER_TYPE_OTHER);
}
+ /**
+ * Feeds ATSC TS stream to detect channel and program information.
+ * @param data buffer for ATSC TS stream
+ * @param startOffset the offset where buffer starts
+ * @param length The length of available data
+ */
public void feedTSStream(byte[] data, int startOffset, int length) {
if (mPidSet.isEmpty()) {
startListening(TsParser.ATSC_SI_BASE_PID);
@@ -218,7 +251,11 @@ public class EventDetector {
}
}
- public List<TunerChannel> getIncompleteChannels() {
- return mTsParser.getIncompleteChannels();
+ /**
+ * Retrieves the channel information regardless of being well-formed.
+ * @return {@link List} of {@link TunerChannel}
+ */
+ public List<TunerChannel> getMalFormedChannels() {
+ return mTsParser.getMalFormedChannels();
}
}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/FileSourceEventDetector.java b/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java
index afc48544..46ff4ea1 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/FileSourceEventDetector.java
+++ b/src/com/android/tv/tuner/tvinput/FileSourceEventDetector.java
@@ -14,23 +14,22 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import com.android.usbtuner.FileDataSource;
-import com.android.usbtuner.data.PsiData.PatItem;
-import com.android.usbtuner.data.PsiData.PmtItem;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.PsipData.VctItem;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.ts.TsParser;
-import com.android.usbtuner.ts.TsParser.TsOutputListener;
-import com.android.usbtuner.tvinput.EventDetector.EventListener;
+import com.android.tv.tuner.data.PsiData.PatItem;
+import com.android.tv.tuner.data.PsiData.PmtItem;
+import com.android.tv.tuner.data.PsipData.EitItem;
+import com.android.tv.tuner.data.PsipData.VctItem;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.source.FileTsStreamer;
+import com.android.tv.tuner.ts.TsParser;
+import com.android.tv.tuner.tvinput.EventDetector.EventListener;
import java.util.ArrayList;
import java.util.HashSet;
@@ -41,11 +40,12 @@ import java.util.Set;
* PSIP event detector for a file source.
*
* <p>Uses {@link TsParser} to analyze input MPEG-2 transport stream, detects and reports
- * various PSIP-related events via {@link TsOutputListener}.
+ * various PSIP-related events via {@link TsParser.TsOutputListener}.
*/
public class FileSourceEventDetector {
private static final String TAG = "FileSourceEventDetector";
private static final boolean DEBUG = true;
+ public static final int ALL_PROGRAM_NUMBERS = 0;
private TsParser mTsParser;
private final Set<Integer> mVctProgramNumberSet = new HashSet<>();
@@ -53,20 +53,29 @@ public class FileSourceEventDetector {
private final SparseBooleanArray mVctCaptionTracksFound = new SparseBooleanArray();
private final SparseBooleanArray mEitCaptionTracksFound = new SparseBooleanArray();
private final EventListener mEventListener;
- private FileDataSource.StreamProvider mSource;
+ private FileTsStreamer.StreamProvider mStreamProvider;
+ private int mProgramNumber = ALL_PROGRAM_NUMBERS;
public FileSourceEventDetector(EventDetector.EventListener listener) {
mEventListener = listener;
}
- public void start(FileDataSource.StreamProvider source) {
- mSource = source;
+ /**
+ * Starts detecting channel and program information.
+ *
+ * @param provider MPEG-2 transport stream source.
+ * @param programNumber The program number if this is for handling tune request. For scanning
+ * purpose, supply {@link #ALL_PROGRAM_NUMBERS}.
+ */
+ public void start(FileTsStreamer.StreamProvider provider, int programNumber) {
+ mStreamProvider = provider;
+ mProgramNumber = programNumber;
reset();
}
private void reset() {
mTsParser = new TsParser(mTsOutputListener); // TODO: Use TsParser.reset()
- mSource.clearPidFilter();
+ mStreamProvider.clearPidFilter();
mVctProgramNumberSet.clear();
mVctCaptionTracksFound.clear();
mEitCaptionTracksFound.clear();
@@ -74,7 +83,7 @@ public class FileSourceEventDetector {
}
public void feedTSStream(byte[] data, int startOffset, int length) {
- if (mSource.isFilterEmpty()) {
+ if (mStreamProvider.isFilterEmpty()) {
startListening(TsParser.ATSC_SI_BASE_PID);
startListening(TsParser.PAT_PID);
}
@@ -84,17 +93,19 @@ public class FileSourceEventDetector {
}
private void startListening(int pid) {
- if (mSource.isInFilter(pid)) {
+ if (mStreamProvider.isInFilter(pid)) {
return;
}
- mSource.addPidFilter(pid);
+ mStreamProvider.addPidFilter(pid);
}
- private TsOutputListener mTsOutputListener = new TsOutputListener() {
+ private final TsParser.TsOutputListener mTsOutputListener = new TsParser.TsOutputListener() {
@Override
public void onPatDetected(List<PatItem> items) {
for (PatItem i : items) {
- mSource.addPidFilter(i.getPmtPid());
+ if (mProgramNumber == ALL_PROGRAM_NUMBERS || mProgramNumber == i.getProgramNo()) {
+ mStreamProvider.addPidFilter(i.getPmtPid());
+ }
}
}
@@ -148,6 +159,11 @@ public class FileSourceEventDetector {
}
@Override
+ public void onAllVctItemsParsed() {
+ // do nothing.
+ }
+
+ @Override
public void onVctItemParsed(VctItem channel, List<PmtItem> pmtItems) {
if (DEBUG) {
Log.d(TAG, "onVctItemParsed VCT " + channel);
@@ -177,7 +193,7 @@ public class FileSourceEventDetector {
if (captionTracksFound) {
tunerChannel.setHasCaptionTrack();
}
- tunerChannel.setFilepath(mSource.getFilepath());
+ tunerChannel.setFilepath(mStreamProvider.getFilepath());
tunerChannel.setAudioTracks(audioTracks);
tunerChannel.setCaptionTracks(captionTracks);
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/PlaybackCacheListener.java b/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java
index 98e07907..3908fe6c 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/PlaybackCacheListener.java
+++ b/src/com/android/tv/tuner/tvinput/PlaybackBufferListener.java
@@ -14,29 +14,29 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
/**
- * The listener for cache events occurred during playback.
+ * The listener for buffer events occurred during playback.
*/
-public interface PlaybackCacheListener {
+public interface PlaybackBufferListener {
/**
- * Invoked when the start position of the cache has been changed.
+ * Invoked when the start position of the buffer has been changed.
*
- * @param startTimeMs the new start time of the cache in millisecond
+ * @param startTimeMs the new start time of the buffer in millisecond
*/
- void onCacheStartTimeChanged(long startTimeMs);
+ void onBufferStartTimeChanged(long startTimeMs);
/**
- * Invoked when the state of the cache has been changed.
+ * Invoked when the state of the buffer has been changed.
*
- * @param available whether the cache is available or not
+ * @param available whether the buffer is available or not
*/
- void onCacheStateChanged(boolean available);
+ void onBufferStateChanged(boolean available);
/**
- * Invoked when the disk speed is too slow to write the caches.
+ * Invoked when the disk speed is too slow to write the buffers.
*/
void onDiskTooSlow();
}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/UsbTunerDebug.java b/src/com/android/tv/tuner/tvinput/TunerDebug.java
index 4732eea1..a7a41ea7 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/UsbTunerDebug.java
+++ b/src/com/android/tv/tuner/tvinput/TunerDebug.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.os.SystemClock;
import android.util.Log;
@@ -22,8 +22,8 @@ import android.util.Log;
/**
* A class to maintain various debugging information.
*/
-public class UsbTunerDebug {
- private static final String TAG = "UsbTunerDebug";
+public class TunerDebug {
+ private static final String TAG = "TunerDebug";
public static final boolean ENABLED = false;
private int mVideoFrameDrop;
@@ -42,109 +42,109 @@ public class UsbTunerDebug {
private long mAudioPtsUsRate;
private long mVideoPtsUsRate;
- private UsbTunerDebug() {
+ private TunerDebug() {
mVideoFrameDrop = 0;
mLastCheckTimestampMs = SystemClock.elapsedRealtime();
}
private static class LazyHolder {
- private static final UsbTunerDebug INSTANCE = new UsbTunerDebug();
+ private static final TunerDebug INSTANCE = new TunerDebug();
}
- public static UsbTunerDebug getInstance() {
+ public static TunerDebug getInstance() {
return LazyHolder.INSTANCE;
}
public static void notifyVideoFrameDrop(long delta) {
// TODO: provide timestamp mismatch information using delta
- UsbTunerDebug sUsbTunerDebug = getInstance();
- sUsbTunerDebug.mVideoFrameDrop++;
+ TunerDebug sTunerDebug = getInstance();
+ sTunerDebug.mVideoFrameDrop++;
}
public static int getVideoFrameDrop() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- int videoFrameDrop = sUsbTunerDebug.mVideoFrameDrop;
+ TunerDebug sTunerDebug = getInstance();
+ int videoFrameDrop = sTunerDebug.mVideoFrameDrop;
if (videoFrameDrop > 0) {
Log.d(TAG, "Dropped video frame: " + videoFrameDrop);
}
- sUsbTunerDebug.mVideoFrameDrop = 0;
+ sTunerDebug.mVideoFrameDrop = 0;
return videoFrameDrop;
}
public static void setBytesInQueue(int bytesInQueue) {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- sUsbTunerDebug.mBytesInQueue = bytesInQueue;
+ TunerDebug sTunerDebug = getInstance();
+ sTunerDebug.mBytesInQueue = bytesInQueue;
}
public static int getBytesInQueue() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mBytesInQueue;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mBytesInQueue;
}
public static void setAudioPositionUs(long audioPositionUs) {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- sUsbTunerDebug.mAudioPositionUs = audioPositionUs;
+ TunerDebug sTunerDebug = getInstance();
+ sTunerDebug.mAudioPositionUs = audioPositionUs;
}
public static long getAudioPositionUs() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mAudioPositionUs;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mAudioPositionUs;
}
public static void setAudioPtsUs(long audioPtsUs) {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- sUsbTunerDebug.mAudioPtsUs = audioPtsUs;
+ TunerDebug sTunerDebug = getInstance();
+ sTunerDebug.mAudioPtsUs = audioPtsUs;
}
public static long getAudioPtsUs() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mAudioPtsUs;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mAudioPtsUs;
}
public static void setVideoPtsUs(long videoPtsUs) {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- sUsbTunerDebug.mVideoPtsUs = videoPtsUs;
+ TunerDebug sTunerDebug = getInstance();
+ sTunerDebug.mVideoPtsUs = videoPtsUs;
}
public static long getVideoPtsUs() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mVideoPtsUs;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mVideoPtsUs;
}
public static void calculateDiff() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
+ TunerDebug sTunerDebug = getInstance();
long currentTime = SystemClock.elapsedRealtime();
- long duration = currentTime - sUsbTunerDebug.mLastCheckTimestampMs;
+ long duration = currentTime - sTunerDebug.mLastCheckTimestampMs;
if (duration != 0) {
- sUsbTunerDebug.mAudioPositionUsRate =
- (sUsbTunerDebug.mAudioPositionUs - sUsbTunerDebug.mLastAudioPositionUs) * 1000
+ sTunerDebug.mAudioPositionUsRate =
+ (sTunerDebug.mAudioPositionUs - sTunerDebug.mLastAudioPositionUs) * 1000
/ duration;
- sUsbTunerDebug.mAudioPtsUsRate =
- (sUsbTunerDebug.mAudioPtsUs - sUsbTunerDebug.mLastAudioPtsUs) * 1000
+ sTunerDebug.mAudioPtsUsRate =
+ (sTunerDebug.mAudioPtsUs - sTunerDebug.mLastAudioPtsUs) * 1000
/ duration;
- sUsbTunerDebug.mVideoPtsUsRate =
- (sUsbTunerDebug.mVideoPtsUs - sUsbTunerDebug.mLastVideoPtsUs) * 1000
+ sTunerDebug.mVideoPtsUsRate =
+ (sTunerDebug.mVideoPtsUs - sTunerDebug.mLastVideoPtsUs) * 1000
/ duration;
}
- sUsbTunerDebug.mLastAudioPositionUs = sUsbTunerDebug.mAudioPositionUs;
- sUsbTunerDebug.mLastAudioPtsUs = sUsbTunerDebug.mAudioPtsUs;
- sUsbTunerDebug.mLastVideoPtsUs = sUsbTunerDebug.mVideoPtsUs;
- sUsbTunerDebug.mLastCheckTimestampMs = currentTime;
+ sTunerDebug.mLastAudioPositionUs = sTunerDebug.mAudioPositionUs;
+ sTunerDebug.mLastAudioPtsUs = sTunerDebug.mAudioPtsUs;
+ sTunerDebug.mLastVideoPtsUs = sTunerDebug.mVideoPtsUs;
+ sTunerDebug.mLastCheckTimestampMs = currentTime;
}
public static long getAudioPositionUsRate() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mAudioPositionUsRate;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mAudioPositionUsRate;
}
public static long getAudioPtsUsRate() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mAudioPtsUsRate;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mAudioPtsUsRate;
}
public static long getVideoPtsUsRate() {
- UsbTunerDebug sUsbTunerDebug = getInstance();
- return sUsbTunerDebug.mVideoPtsUsRate;
+ TunerDebug sTunerDebug = getInstance();
+ return sTunerDebug.mVideoPtsUsRate;
}
}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSession.java b/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
index 3d27a946..acdd149f 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSession.java
+++ b/src/com/android/tv/tuner/tvinput/TunerRecordingSession.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.content.Context;
import android.media.tv.TvInputManager;
@@ -29,16 +29,14 @@ import android.util.Log;
* Processes DVR recordings, and deletes the previously recorded contents.
*/
public class TunerRecordingSession extends TvInputService.RecordingSession {
- private static String TAG = "TunerRecordingSession";
- private static boolean DEBUG = false;
+ private static final String TAG = "TunerRecordingSession";
+ private static final boolean DEBUG = false;
private final TunerRecordingSessionWorker mSessionWorker;
- private final String mInputId;
public TunerRecordingSession(Context context, String inputId,
ChannelDataManager channelDataManager) {
super(context);
- mInputId = inputId;
mSessionWorker = new TunerRecordingSessionWorker(context, inputId, channelDataManager,
this);
}
@@ -51,7 +49,7 @@ public class TunerRecordingSession extends TvInputService.RecordingSession {
if (DEBUG) {
Log.d(TAG, "Requesting recording session tune: " + channelUri);
}
- mSessionWorker.connect(channelUri);
+ mSessionWorker.tune(channelUri);
}
@MainThread
@@ -65,11 +63,11 @@ public class TunerRecordingSession extends TvInputService.RecordingSession {
@MainThread
@Override
- public void onStartRecording(@Nullable Uri programHint) {
+ public void onStartRecording(@Nullable Uri programUri) {
if (DEBUG) {
Log.d(TAG, "Requesting start recording.");
}
- mSessionWorker.startRecording();
+ mSessionWorker.startRecording(programUri);
}
@MainThread
@@ -91,14 +89,6 @@ public class TunerRecordingSession extends TvInputService.RecordingSession {
}
@WorkerThread
- public void onConnectFailed() {
- if (DEBUG) {
- Log.d(TAG, "Notifying recording session connection failed.");
- }
- notifyError(TvInputManager.RECORDING_ERROR_UNKNOWN);
- }
-
- @WorkerThread
public void onRecordFinished(final Uri recordedProgramUri) {
if (DEBUG) {
Log.d(TAG, "Notifying record successfully finished.");
@@ -107,8 +97,8 @@ public class TunerRecordingSession extends TvInputService.RecordingSession {
}
@WorkerThread
- public void onRecordUnexpectedlyStopped(int reason) {
- Log.w(TAG, "Notifying record failed: " + reason);
+ public void onError(int reason) {
+ Log.w(TAG, "Notifying recording error: " + reason);
notifyError(reason);
}
}
diff --git a/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java b/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
new file mode 100644
index 00000000..6ec55e4f
--- /dev/null
+++ b/src/com/android/tv/tuner/tvinput/TunerRecordingSessionWorker.java
@@ -0,0 +1,594 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.tuner.tvinput;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.media.tv.TvInputManager;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.support.annotation.IntDef;
+import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import com.android.tv.TvApplication;
+import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.recording.RecordingCapability;
+import com.android.tv.dvr.DvrStorageStatusManager;
+import com.android.tv.dvr.RecordedProgram;
+import com.android.tv.tuner.DvbDeviceAccessor;
+import com.android.tv.tuner.data.PsipData;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.exoplayer.ExoPlayerSampleExtractor;
+import com.android.tv.tuner.exoplayer.SampleExtractor;
+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 java.io.File;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Implements a DVR feature.
+ */
+public class TunerRecordingSessionWorker implements PlaybackBufferListener,
+ EventDetector.EventListener, SampleExtractor.OnCompletionListener,
+ Handler.Callback {
+ private static final String TAG = "TunerRecordingSessionW";
+ private static final boolean DEBUG = false;
+
+ private static final String SORT_BY_TIME = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS
+ + ", " + TvContract.Programs.COLUMN_CHANNEL_ID + ", "
+ + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS;
+ private static final long STORAGE_MONITOR_INTERVAL_MS = TimeUnit.SECONDS.toMillis(4);
+ private static final long MIN_PARTIAL_RECORDING_DURATION_MS = TimeUnit.SECONDS.toMillis(10);
+ private static final long PREPARE_RECORDER_POLL_MS = 50;
+ private static final int MSG_TUNE = 1;
+ private static final int MSG_START_RECORDING = 2;
+ private static final int MSG_PREPARE_RECODER = 3;
+ private static final int MSG_STOP_RECORDING = 4;
+ private static final int MSG_MONITOR_STORAGE_STATUS = 5;
+ private static final int MSG_RELEASE = 6;
+ private final RecordingCapability mCapabilities;
+
+ public RecordingCapability getCapabilities() {
+ return mCapabilities;
+ }
+
+ @IntDef({STATE_IDLE, STATE_TUNED, STATE_RECORDING})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DvrSessionState {}
+ private static final int STATE_IDLE = 1;
+ private static final int STATE_TUNED = 2;
+ private static final int STATE_RECORDING = 3;
+
+ private static final long CHANNEL_ID_NONE = -1;
+
+ private final Context mContext;
+ private final ChannelDataManager mChannelDataManager;
+ private final DvrStorageStatusManager mDvrStorageStatusManager;
+ private final Handler mHandler;
+ private final TsDataSourceManager mSourceManager;
+ private final Random mRandom = new Random();
+
+ private TsDataSource mTunerSource;
+ private TunerChannel mChannel;
+ private File mStorageDir;
+ private long mRecordStartTime;
+ private long mRecordEndTime;
+ private boolean mRecorderRunning;
+ private BufferManager mBufferManager;
+ private SampleExtractor mRecorder;
+ private final TunerRecordingSession mSession;
+ @DvrSessionState private int mSessionState = STATE_IDLE;
+ private final String mInputId;
+ private Uri mProgramUri;
+
+ public TunerRecordingSessionWorker(Context context, String inputId,
+ ChannelDataManager dataManager, TunerRecordingSession session) {
+ mRandom.setSeed(System.nanoTime());
+ mContext = context;
+ HandlerThread handlerThread = new HandlerThread(TAG);
+ handlerThread.start();
+ mHandler = new Handler(handlerThread.getLooper(), this);
+ mDvrStorageStatusManager =
+ TvApplication.getSingletons(context).getDvrStorageStatusManager();
+ mChannelDataManager = dataManager;
+ mChannelDataManager.checkDataVersion(context);
+ mSourceManager = TsDataSourceManager.createSourceManager(true);
+ mCapabilities = new DvbDeviceAccessor(context).getRecordingCapability(inputId);
+ mInputId = inputId;
+ if (DEBUG) Log.d(TAG, mCapabilities.toString());
+ mSession = session;
+ }
+
+ // PlaybackBufferListener
+ @Override
+ public void onBufferStartTimeChanged(long startTimeMs) { }
+
+ @Override
+ public void onBufferStateChanged(boolean available) { }
+
+ @Override
+ public void onDiskTooSlow() { }
+
+ // EventDetector.EventListener
+ @Override
+ public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
+ if (mChannel == null || mChannel.compareTo(channel) != 0) {
+ return;
+ }
+ mChannelDataManager.notifyChannelDetected(channel, channelArrivedAtFirstTime);
+ }
+
+ @Override
+ public void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items) {
+ if (mChannel == null || mChannel.compareTo(channel) != 0) {
+ return;
+ }
+ mChannelDataManager.notifyEventDetected(channel, items);
+ }
+
+ @Override
+ public void onChannelScanDone() {
+ // do nothing.
+ }
+
+ // SampleExtractor.OnCompletionListener
+ @Override
+ public void onCompletion(boolean success, long lastExtractedPositionUs) {
+ onRecordingResult(success, lastExtractedPositionUs);
+ reset();
+ }
+
+ /**
+ * Tunes to {@code channelUri}.
+ */
+ @MainThread
+ public void tune(Uri channelUri) {
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.obtainMessage(MSG_TUNE, channelUri).sendToTarget();
+ }
+
+ /**
+ * Starts recording.
+ */
+ @MainThread
+ public void startRecording(@Nullable Uri programUri) {
+ mHandler.obtainMessage(MSG_START_RECORDING, programUri).sendToTarget();
+ }
+
+ /**
+ * Stops recording.
+ */
+ @MainThread
+ public void stopRecording() {
+ mHandler.sendEmptyMessage(MSG_STOP_RECORDING);
+ }
+
+ /**
+ * Releases all resources.
+ */
+ @MainThread
+ public void release() {
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.sendEmptyMessage(MSG_RELEASE);
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_TUNE: {
+ Uri channelUri = (Uri) msg.obj;
+ if (DEBUG) Log.d(TAG, "Tune to " + channelUri);
+ if (doTune(channelUri)) {
+ mSession.onTuned(channelUri);
+ } else {
+ reset();
+ }
+ return true;
+ }
+ case MSG_START_RECORDING: {
+ if (DEBUG) Log.d(TAG, "Start recording");
+ if (!doStartRecording((Uri) msg.obj)) {
+ reset();
+ }
+ return true;
+ }
+ case MSG_PREPARE_RECODER: {
+ if (DEBUG) Log.d(TAG, "Preparing recorder");
+ if (!mRecorderRunning) {
+ return true;
+ }
+ try {
+ if (!mRecorder.prepare()) {
+ mHandler.sendEmptyMessageDelayed(MSG_PREPARE_RECODER,
+ PREPARE_RECORDER_POLL_MS);
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to start recording. Couldn't prepare an extractor");
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ reset();
+ }
+ return true;
+ }
+ case MSG_STOP_RECORDING: {
+ if (DEBUG) Log.d(TAG, "Stop recording");
+ if (mSessionState != STATE_RECORDING) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ reset();
+ return true;
+ }
+ if (mRecorderRunning) {
+ stopRecorder();
+ }
+ return true;
+ }
+ case MSG_MONITOR_STORAGE_STATUS: {
+ if (mSessionState != STATE_RECORDING) {
+ return true;
+ }
+ if (!mDvrStorageStatusManager.isStorageSufficient()) {
+ if (mRecorderRunning) {
+ stopRecorder();
+ }
+ new DeleteRecordingTask().execute(mStorageDir);
+ mSession.onError(TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ reset();
+ } else {
+ mHandler.sendEmptyMessageDelayed(MSG_MONITOR_STORAGE_STATUS,
+ STORAGE_MONITOR_INTERVAL_MS);
+ }
+ return true;
+ }
+ case MSG_RELEASE: {
+ // Since release was requested, current recording will be cancelled
+ // without notification.
+ reset();
+ mSourceManager.release();
+ mHandler.removeCallbacksAndMessages(null);
+ mHandler.getLooper().quitSafely();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Nullable
+ private TunerChannel getChannel(Uri channelUri) {
+ if (channelUri == null) {
+ return null;
+ }
+ long channelId;
+ try {
+ channelId = ContentUris.parseId(channelUri);
+ } catch (UnsupportedOperationException | NumberFormatException e) {
+ channelId = CHANNEL_ID_NONE;
+ }
+ return (channelId == CHANNEL_ID_NONE) ? null : mChannelDataManager.getChannel(channelId);
+ }
+
+ private String getStorageKey() {
+ long prefix = System.currentTimeMillis();
+ int suffix = mRandom.nextInt();
+ return String.format(Locale.ENGLISH, "%016x_%016x", prefix, suffix);
+ }
+
+ private void reset() {
+ if (mRecorder != null) {
+ mRecorder.release();
+ mRecorder = null;
+ }
+ if (mBufferManager != null) {
+ mBufferManager.close();
+ mBufferManager = null;
+ }
+ if (mTunerSource != null) {
+ mSourceManager.releaseDataSource(mTunerSource);
+ mTunerSource = null;
+ }
+ mSessionState = STATE_IDLE;
+ mRecorderRunning = false;
+ }
+
+ private boolean doTune(Uri channelUri) {
+ if (mSessionState != STATE_IDLE) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.e(TAG, "Tuning was requested from wrong status.");
+ return false;
+ }
+ mChannel = getChannel(channelUri);
+ if (mChannel == null) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.w(TAG, "Failed to start recording. Couldn't find the channel for " + mChannel);
+ return false;
+ }
+ if (!mDvrStorageStatusManager.isStorageSufficient()) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ Log.w(TAG, "Tuning failed due to insufficient storage.");
+ return false;
+ }
+ mTunerSource = mSourceManager.createDataSource(mContext, mChannel, this);
+ if (mTunerSource == null) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_RESOURCE_BUSY);
+ Log.w(TAG, "Tuner stream cannot be created due to resource shortage.");
+ return false;
+ }
+ mSessionState = STATE_TUNED;
+ return true;
+ }
+
+ private boolean doStartRecording(@Nullable Uri programUri) {
+ if (mSessionState != STATE_TUNED) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.e(TAG, "Recording session status abnormal");
+ return false;
+ }
+ mStorageDir = mDvrStorageStatusManager.isStorageSufficient() ?
+ new File(mDvrStorageStatusManager.getRecordingRootDataDirectory(),
+ getStorageKey()) : null;
+ if (mStorageDir == null) {
+ mSession.onError(TvInputManager.RECORDING_ERROR_INSUFFICIENT_SPACE);
+ Log.w(TAG, "Failed to start recording due to insufficient storage.");
+ return false;
+ }
+ // Since tuning might be happened a while ago, shifts the start position of tuned source.
+ mTunerSource.shiftStartPosition(mTunerSource.getBufferedPosition());
+ mBufferManager = new BufferManager(new DvrStorageManager(mStorageDir, true));
+ mRecordStartTime = System.currentTimeMillis();
+ mRecorder = new ExoPlayerSampleExtractor(Uri.EMPTY, mTunerSource, mBufferManager, this,
+ true);
+ mRecorder.setOnCompletionListener(this, mHandler);
+ mProgramUri = programUri;
+ mSessionState = STATE_RECORDING;
+ mRecorderRunning = true;
+ mHandler.sendEmptyMessage(MSG_PREPARE_RECODER);
+ mHandler.removeMessages(MSG_MONITOR_STORAGE_STATUS);
+ mHandler.sendEmptyMessageDelayed(MSG_MONITOR_STORAGE_STATUS,
+ STORAGE_MONITOR_INTERVAL_MS);
+ return true;
+ }
+
+ private void stopRecorder() {
+ // Do not change session status.
+ if (mRecorder != null) {
+ mRecorder.release();
+ mRecordEndTime = System.currentTimeMillis();
+ mRecorder = null;
+ }
+ mRecorderRunning = false;
+ mHandler.removeMessages(MSG_MONITOR_STORAGE_STATUS);
+ Log.i(TAG, "Recording stopped");
+ }
+
+ 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;
+ if (mProgramUri == null) {
+ 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) {
+ Program result = Program.onQuery(c);
+ if (DEBUG) {
+ Log.v(TAG, "Finished query for " + this);
+ }
+ return result;
+ } else {
+ if (c == null) {
+ Log.e(TAG, "Unknown query error for " + this);
+ } else {
+ if (DEBUG) Log.d(TAG, "Canceled query for " + this);
+ }
+ return null;
+ }
+ }
+ }
+
+ private Uri insertRecordedProgram(Program program, long channelId, String storageUri,
+ long totalBytes, long startTime, long 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.buildValues());
+ }
+ return mContext.getContentResolver().insert(TvContract.RecordedPrograms.CONTENT_URI,
+ values);
+ }
+
+ private void onRecordingResult(boolean success, long lastExtractedPositionUs) {
+ if (mSessionState != STATE_RECORDING) {
+ // Error notification is not needed.
+ Log.e(TAG, "Recording session status abnormal");
+ return;
+ }
+ if (mRecorderRunning) {
+ // In case of recorder not being stopped, because of premature termination of recording.
+ stopRecorder();
+ }
+ if (!success && lastExtractedPositionUs <
+ TimeUnit.MILLISECONDS.toMicros(MIN_PARTIAL_RECORDING_DURATION_MS)) {
+ new DeleteRecordingTask().execute(mStorageDir);
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.w(TAG, "Recording failed during recording");
+ return;
+ }
+ Log.i(TAG, "recording finished " + (success ? "completely" : "partially"));
+ Uri uri = insertRecordedProgram(getRecordedProgram(), mChannel.getChannelId(),
+ Uri.fromFile(mStorageDir).toString(), 1024 * 1024, mRecordStartTime,
+ mRecordStartTime + TimeUnit.MICROSECONDS.toMillis(lastExtractedPositionUs));
+ if (uri == null) {
+ new DeleteRecordingTask().execute(mStorageDir);
+ mSession.onError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ Log.e(TAG, "Inserting a recording to DB failed");
+ return;
+ }
+ mSession.onRecordFinished(uri);
+ }
+
+ private static class DeleteRecordingTask extends AsyncTask<File, Void, Void> {
+
+ @Override
+ public Void doInBackground(File... files) {
+ if (files == null || files.length == 0) {
+ return null;
+ }
+ for(File file : files) {
+ Utils.deleteDirOrFile(file);
+ }
+ return null;
+ }
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/TunerSession.java b/src/com/android/tv/tuner/tvinput/TunerSession.java
index da3f17f3..abfd2b30 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/TunerSession.java
+++ b/src/com/android/tv/tuner/tvinput/TunerSession.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.annotation.TargetApi;
import android.content.Context;
@@ -37,24 +37,25 @@ import android.widget.TextView;
import android.widget.Toast;
import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.android.usbtuner.R;
-import com.android.usbtuner.cc.CaptionLayout;
-import com.android.usbtuner.cc.CaptionTrackRenderer;
-import com.android.usbtuner.data.Cea708Data.CaptionEvent;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.util.StatusTextUtils;
-import com.android.usbtuner.util.SystemPropertiesProxy;
+import com.android.tv.tuner.R;
+import com.android.tv.tuner.cc.CaptionLayout;
+import com.android.tv.tuner.cc.CaptionTrackRenderer;
+import com.android.tv.tuner.data.Cea708Data.CaptionEvent;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.util.GlobalSettingsUtils;
+import com.android.tv.tuner.util.StatusTextUtils;
+import com.android.tv.tuner.util.SystemPropertiesProxy;
/**
- * Provides a USB tuner TV input session. It handles Overlay UI works. Main tuner input functions
+ * 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 {
private static final String TAG = "TunerSession";
private static final boolean DEBUG = false;
- private static final String USBTUNER_SHOW_DEBUG = "persist.usbtuner.show_debug";
+ private static final String USBTUNER_SHOW_DEBUG = "persist.tv.tuner.show_debug";
public static final int MSG_UI_SHOW_MESSAGE = 1;
public static final int MSG_UI_HIDE_MESSAGE = 2;
@@ -77,12 +78,11 @@ public class TunerSession extends TvInputService.Session implements Handler.Call
private final CaptionTrackRenderer mCaptionTrackRenderer;
private final TunerSessionWorker mSessionWorker;
private boolean mReleased = false;
- private boolean mVideoAvailable = false;
private boolean mPlayPaused;
private long mTuneStartTimestamp;
public TunerSession(Context context, ChannelDataManager channelDataManager,
- CacheManager cacheManager) {
+ BufferManager bufferManager) {
super(context);
mContext = context;
mUiHandler = new Handler(this);
@@ -98,11 +98,11 @@ public class TunerSession extends TvInputService.Session implements Handler.Call
mAudioStatusView = (TextView) mOverlayView.findViewById(R.id.audio_status);
mAudioStatusView.setVisibility(View.INVISIBLE);
mAudioStatusView.setText(Html.fromHtml(StatusTextUtils.getAudioWarningInHTML(
- context.getString(R.string.ut_ac3_passthrough_unavailable))));
+ context.getString(R.string.ut_surround_sound_disabled))));
CaptionLayout captionLayout = (CaptionLayout) mOverlayView.findViewById(R.id.caption);
mCaptionTrackRenderer = new CaptionTrackRenderer(captionLayout);
mSessionWorker = new TunerSessionWorker(context, channelDataManager,
- cacheManager, this);
+ bufferManager, this);
}
public boolean isReleased() {
@@ -116,25 +116,23 @@ public class TunerSession extends TvInputService.Session implements Handler.Call
@Override
public boolean onSelectTrack(int type, String trackId) {
- mSessionWorker.sendMessage(
- TunerSessionWorker.MSG_SELECT_TRACK, type, 0, trackId);
+ mSessionWorker.sendMessage(TunerSessionWorker.MSG_SELECT_TRACK, type, 0, trackId);
return false;
}
@Override
public void onSetCaptionEnabled(boolean enabled) {
- mSessionWorker.sendMessage(
- TunerSessionWorker.MSG_SET_CAPTION_ENABLED, enabled);
+ mSessionWorker.setCaptionEnabled(enabled);
}
@Override
public void onSetStreamVolume(float volume) {
- mSessionWorker.sendMessage(TunerSessionWorker.MSG_SET_STREAM_VOLUME, volume);
+ mSessionWorker.setStreamVolume(volume);
}
@Override
public boolean onSetSurface(Surface surface) {
- mSessionWorker.sendMessage(TunerSessionWorker.MSG_SET_SURFACE, surface);
+ mSessionWorker.setSurface(surface);
return true;
}
@@ -234,31 +232,11 @@ public class TunerSession extends TvInputService.Session implements Handler.Call
+ (SystemClock.elapsedRealtime() - mTuneStartTimestamp) + " ms");
mTuneStartTimestamp = 0;
}
- mVideoAvailable = true;
}
@Override
public void notifyVideoUnavailable(int reason) {
- switch (reason) {
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING:
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING:
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY:
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL:
- super.notifyVideoUnavailable(reason);
- break;
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN:
- default:
- super.notifyVideoAvailable();
- TunerChannel channel = mSessionWorker.getCurrentChannel();
- if (channel != null) {
- sendUiMessage(TunerSession.MSG_UI_SHOW_MESSAGE,
- mContext.getString(R.string.ut_fail_to_tune, channel.getName()));
- } else {
- sendUiMessage(TunerSession.MSG_UI_SHOW_MESSAGE,
- mContext.getString(R.string.ut_fail_to_tune_to_unknown_channel));
- }
- break;
- }
+ super.notifyVideoUnavailable(reason);
if (reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING
&& reason != TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL) {
notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_UNAVAILABLE);
@@ -290,7 +268,14 @@ public class TunerSession extends TvInputService.Session implements Handler.Call
return true;
}
case MSG_UI_SHOW_AUDIO_UNPLAYABLE: {
- mAudioStatusView.setVisibility(View.VISIBLE);
+ // Showing message of enabling surround sound only when global surround sound
+ // setting is "never".
+ final int value = GlobalSettingsUtils.getEncodedSurroundOutputSettings(mContext);
+ if (value == GlobalSettingsUtils.ENCODED_SURROUND_OUTPUT_NEVER) {
+ mAudioStatusView.setVisibility(View.VISIBLE);
+ } else {
+ Log.e(TAG, "Audio is unavailable, surround sound setting is " + value);
+ }
return true;
}
case MSG_UI_HIDE_AUDIO_UNPLAYABLE: {
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/TunerSessionWorker.java b/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
index 6b71fcf6..c0a613a4 100644
--- a/usbtuner/src/com/android/usbtuner/tvinput/TunerSessionWorker.java
+++ b/src/com/android/tv/tuner/tvinput/TunerSessionWorker.java
@@ -14,13 +14,12 @@
* limitations under the License.
*/
-package com.android.usbtuner.tvinput;
+package com.android.tv.tuner.tvinput;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
-import android.media.MediaDataSource;
import android.media.MediaFormat;
import android.media.PlaybackParams;
import android.media.tv.TvContentRating;
@@ -32,35 +31,35 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.SystemClock;
+import android.support.annotation.AnyThread;
+import android.support.annotation.MainThread;
+import android.support.annotation.WorkerThread;
import android.text.Html;
import android.util.Log;
import android.util.Pair;
-import android.util.Size;
import android.util.SparseArray;
import android.view.Surface;
import android.view.accessibility.CaptioningManager;
import com.google.android.exoplayer.audio.AudioCapabilities;
+import com.google.android.exoplayer.ExoPlayer;
+import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvContentRatingCache;
-import com.android.usbtuner.FileDataSource;
-import com.android.usbtuner.InputStreamSource;
-import com.android.usbtuner.TunerHal;
-import com.android.usbtuner.UsbTunerDataSource;
-import com.android.usbtuner.data.Cea708Data;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.PsipData.EitItem;
-import com.android.usbtuner.data.PsipData.TvTracksInterface;
-import com.android.usbtuner.data.Track.AtscAudioTrack;
-import com.android.usbtuner.data.Track.AtscCaptionTrack;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.exoplayer.MpegTsPassthroughAc3RendererBuilder;
-import com.android.usbtuner.exoplayer.MpegTsPlayer;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.DvrStorageManager;
-import com.android.usbtuner.util.IsoUtils;
-import com.android.usbtuner.util.StatusTextUtils;
-
-import junit.framework.Assert;
+import com.android.tv.tuner.TunerPreferences;
+import com.android.tv.tuner.data.Cea708Data;
+import com.android.tv.tuner.data.Channel;
+import com.android.tv.tuner.data.PsipData.EitItem;
+import com.android.tv.tuner.data.PsipData.TvTracksInterface;
+import com.android.tv.tuner.data.Track.AtscAudioTrack;
+import com.android.tv.tuner.data.Track.AtscCaptionTrack;
+import com.android.tv.tuner.data.TunerChannel;
+import com.android.tv.tuner.exoplayer.MpegTsRendererBuilder;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.exoplayer.buffer.DvrStorageManager;
+import com.android.tv.tuner.exoplayer.MpegTsPlayer;
+import com.android.tv.tuner.source.TsDataSource;
+import com.android.tv.tuner.source.TsDataSourceManager;
+import com.android.tv.tuner.util.StatusTextUtils;
import java.io.File;
import java.io.FileNotFoundException;
@@ -75,7 +74,8 @@ import java.util.concurrent.CountDownLatch;
* {@link TunerSessionWorker} implements a handler thread which processes TV input jobs
* such as handling {@link ExoPlayer}, managing a tuner device, trickplay, and so on.
*/
-public class TunerSessionWorker implements PlaybackCacheListener,
+@WorkerThread
+public class TunerSessionWorker implements PlaybackBufferListener,
MpegTsPlayer.VideoEventListener, MpegTsPlayer.Listener, EventDetector.EventListener,
ChannelDataManager.ProgramInfoListener, Handler.Callback {
private static final String TAG = "TunerSessionWorker";
@@ -85,39 +85,36 @@ public class TunerSessionWorker implements PlaybackCacheListener,
// Public messages
public static final int MSG_SELECT_TRACK = 1;
- public static final int MSG_SET_CAPTION_ENABLED = 2;
- public static final int MSG_SET_SURFACE = 3;
- public static final int MSG_SET_STREAM_VOLUME = 4;
- public static final int MSG_TIMESHIFT_PAUSE = 5;
- public static final int MSG_TIMESHIFT_RESUME = 6;
- public static final int MSG_TIMESHIFT_SEEK_TO = 7;
- public static final int MSG_TIMESHIFT_SET_PLAYBACKPARAMS = 8;
- public static final int MSG_AUDIO_CAPABILITIES_CHANGED = 9;
- public static final int MSG_UNBLOCKED_RATING = 10;
+ public static final int MSG_UPDATE_CAPTION_TRACK = 2;
+ public static final int MSG_SET_STREAM_VOLUME = 3;
+ public static final int MSG_TIMESHIFT_PAUSE = 4;
+ public static final int MSG_TIMESHIFT_RESUME = 5;
+ public static final int MSG_TIMESHIFT_SEEK_TO = 6;
+ public static final int MSG_TIMESHIFT_SET_PLAYBACKPARAMS = 7;
+ public static final int MSG_AUDIO_CAPABILITIES_CHANGED = 8;
+ public static final int MSG_UNBLOCKED_RATING = 9;
// Private messages
private static final int MSG_TUNE = 1000;
private static final int MSG_RELEASE = 1001;
private static final int MSG_RETRY_PLAYBACK = 1002;
private static final int MSG_START_PLAYBACK = 1003;
- private static final int MSG_PLAYBACK_STATE_CHANGED = 1004;
- private static final int MSG_PLAYBACK_ERROR = 1005;
- private static final int MSG_PLAYBACK_VIDEO_SIZE_CHANGED = 1006;
- private static final int MSG_AUDIO_UNPLAYABLE = 1007;
private static final int MSG_UPDATE_PROGRAM = 1008;
private static final int MSG_SCHEDULE_OF_PROGRAMS = 1009;
private static final int MSG_UPDATE_CHANNEL_INFO = 1010;
- private static final int MSG_TRICKPLAY = 1011;
- private static final int MSG_DRAWN_TO_SURFACE = 1012;
- private static final int MSG_PARENTAL_CONTROLS = 1013;
- private static final int MSG_RESCHEDULE_PROGRAMS = 1014;
- private static final int MSG_CACHE_START_TIME_CHANGED = 1015;
- private static final int MSG_CHECK_SIGNAL = 1016;
- private static final int MSG_DISCOVER_CAPTION_SERVICE_NUMBER = 1017;
- private static final int MSG_RECOVER_STOPPED_PLAYBACK = 1018;
- private static final int MSG_CACHE_STATE_CHANGED = 1019;
- private static final int MSG_PROGRAM_DATA_RESULT = 1020;
- private static final int MSG_STOP_TUNE = 1021;
+ private static final int MSG_TRICKPLAY_BY_SEEK = 1011;
+ private static final int MSG_SMOOTH_TRICKPLAY_MONITOR = 1012;
+ private static final int MSG_PARENTAL_CONTROLS = 1015;
+ private static final int MSG_RESCHEDULE_PROGRAMS = 1016;
+ private static final int MSG_BUFFER_START_TIME_CHANGED = 1017;
+ private static final int MSG_CHECK_SIGNAL = 1018;
+ private static final int MSG_DISCOVER_CAPTION_SERVICE_NUMBER = 1019;
+ private static final int MSG_RESET_PLAYBACK = 1020;
+ private static final int MSG_BUFFER_STATE_CHANGED = 1021;
+ private static final int MSG_PROGRAM_DATA_RESULT = 1022;
+ private static final int MSG_STOP_TUNE = 1023;
+ private static final int MSG_SET_SURFACE = 1024;
+ private static final int MSG_NOTIFY_AUDIO_TRACK_UPDATED = 1025;
private static final int TS_PACKET_SIZE = 188;
private static final int CHECK_NO_SIGNAL_INITIAL_DELAY_MS = 4000;
@@ -127,7 +124,12 @@ public class TunerSessionWorker implements PlaybackCacheListener,
private static final int RESCHEDULE_PROGRAMS_INITIAL_DELAY_MS = 4000;
private static final int RESCHEDULE_PROGRAMS_INTERVAL_MS = 10000;
private static final int RESCHEDULE_PROGRAMS_TOLERANCE_MS = 2000;
- private static final int MAX_RETRY_COUNT = 2;
+ // The following 3s is defined empirically. This should be larger than 2s considering video
+ // key frame interval in the TS stream.
+ private static final int PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS = 3000;
+ private static final int PLAYBACK_RETRY_DELAY_MS = 5000;
+ private static final int MAX_IMMEDIATE_RETRY_COUNT = 5;
+ private static final long INVALID_TIME = -1;
// Some examples of the track ids of the audio tracks, "a0", "a1", "a2".
// The number after prefix is being used for indicating a index of the given audio track.
@@ -139,61 +141,57 @@ public class TunerSessionWorker implements PlaybackCacheListener,
private static final String SUBTITLE_TRACK_PREFIX = "s";
private static final int TRACK_PREFIX_SIZE = 1;
private static final String VIDEO_TRACK_ID = "v";
- private static final long CACHE_UNDERFLOW_BUFFER_MS = 5000;
+ private static final long BUFFER_UNDERFLOW_BUFFER_MS = 5000;
// Actual interval would be divided by the speed.
- private static final int TRICKPLAY_SEEK_INTERVAL_MS = 2000;
- private static final int MIN_TRICKPLAY_SEEK_INTERVAL_MS = 500;
+ private static final int EXPECTED_KEY_FRAME_INTERVAL_MS = 500;
+ private static final int MIN_TRICKPLAY_SEEK_INTERVAL_MS = 20;
+ private static final int TRICKPLAY_MONITOR_INTERVAL_MS = 250;
private final Context mContext;
private final ChannelDataManager mChannelDataManager;
- private final TunerHal mTunerHal;
- private UsbTunerDataSource mTunerSource;
- private FileDataSource mFileSource;
- private InputStreamSource mSource;
- private Surface mSurface;
- private int mPlayerGeneration;
- private int mPreparingGeneration;
- private int mEndedGeneration;
+ private final TsDataSourceManager mSourceManager;
+ private volatile Surface mSurface;
+ private volatile float mVolume = 1.0f;
+ private volatile boolean mCaptionEnabled;
private volatile MpegTsPlayer mPlayer;
private volatile TunerChannel mChannel;
- private String mRecordingId;
private volatile Long mRecordingDuration;
+ private volatile long mRecordStartTimeMs;
+ private volatile long mBufferStartTimeMs;
+ private String mRecordingId;
private final Handler mHandler;
private int mRetryCount;
- private float mVolume;
private final ArrayList<TvTrackInfo> mTvTracks;
- private SparseArray<AtscAudioTrack> mAudioTrackMap;
- private SparseArray<AtscCaptionTrack> mCaptionTrackMap;
+ private final SparseArray<AtscAudioTrack> mAudioTrackMap;
+ private final SparseArray<AtscCaptionTrack> mCaptionTrackMap;
private AtscCaptionTrack mCaptionTrack;
- private boolean mCaptionEnabled;
- private volatile long mRecordStartTimeMs;
- private volatile long mCacheStartTimeMs;
private PlaybackParams mPlaybackParams = new PlaybackParams();
private boolean mPlayerStarted = false;
private boolean mReportedDrawnToSurface = false;
- private boolean mReportedSignalAvailable = false;
+ private boolean mReportedWeakSignal = false;
private EitItem mProgram;
private List<EitItem> mPrograms;
- private TvInputManager mTvInputManager;
+ private final TvInputManager mTvInputManager;
private boolean mChannelBlocked;
private TvContentRating mUnblockedContentRating;
private long mLastPositionMs;
private AudioCapabilities mAudioCapabilities;
private final CountDownLatch mReleaseLatch = new CountDownLatch(1);
- private long mLastLimitInBytes = 0L;
- private long mLastPositionInBytes = 0L;
- private final CacheManager mCacheManager;
+ private long mLastLimitInBytes;
+ private long mLastPositionInBytes;
+ private final BufferManager mBufferManager;
private final TvContentRatingCache mTvContentRatingCache = TvContentRatingCache.getInstance();
private final TunerSession mSession;
+ private int mPlayerState = ExoPlayer.STATE_IDLE;
+ private long mPreparingStartTimeMs;
+ private long mBufferingStartTimeMs;
+ private long mReadyStartTimeMs;
public TunerSessionWorker(Context context, ChannelDataManager channelDataManager,
- CacheManager cacheManager, TunerSession tunerSession) {
+ BufferManager bufferManager, TunerSession tunerSession) {
+ if (DEBUG) Log.d(TAG, "TunerSessionWorker created");
mContext = context;
- mTunerHal = TunerHal.createInstance(context);
- if (mTunerHal == null) {
- throw new RuntimeException("Failed to open a DVB device");
- }
// HandlerThread should be set up before it is registered as a listener in the all other
// components.
@@ -202,13 +200,10 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mHandler = new Handler(handlerThread.getLooper(), this);
mSession = tunerSession;
mChannelDataManager = channelDataManager;
- // TODO: need to refactor it for multi-tuner support.
mChannelDataManager.setListener(this);
mChannelDataManager.checkDataVersion(mContext);
+ mSourceManager = TsDataSourceManager.createSourceManager(false);
mTvInputManager = (TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE);
- mTunerSource = new UsbTunerDataSource(mTunerHal, this);
- mFileSource = new FileDataSource(this);
- mVolume = 1.0f;
mTvTracks = new ArrayList<>();
mAudioTrackMap = new SparseArray<>();
mCaptionTrackMap = new SparseArray<>();
@@ -216,28 +211,72 @@ public class TunerSessionWorker implements PlaybackCacheListener,
(CaptioningManager) context.getSystemService(Context.CAPTIONING_SERVICE);
mCaptionEnabled = captioningManager.isEnabled();
mPlaybackParams.setSpeed(1.0f);
- mCacheManager = cacheManager;
+ mBufferManager = bufferManager;
+ mPreparingStartTimeMs = INVALID_TIME;
+ mBufferingStartTimeMs = INVALID_TIME;
+ mReadyStartTimeMs = INVALID_TIME;
}
// Public methods
+ @MainThread
public void tune(Uri channelUri) {
- if (mSurface != null) { // To avoid removing MSG_SET_SURFACE
- mHandler.removeCallbacksAndMessages(null);
- }
+ mHandler.removeCallbacksAndMessages(null);
+ mSourceManager.setHasPendingTune();
sendMessage(MSG_TUNE, channelUri);
}
+ @MainThread
public void stopTune() {
mHandler.removeCallbacksAndMessages(null);
sendMessage(MSG_STOP_TUNE);
}
+ /**
+ * Sets {@link Surface}.
+ */
+ @MainThread
+ public void setSurface(Surface surface) {
+ if (surface != null && !surface.isValid()) {
+ Log.w(TAG, "Ignoring invalid surface.");
+ return;
+ }
+ // mSurface is kept even when tune is called right after. But, messages can be deleted by
+ // tune or updateChannelBlockStatus. So mSurface should be stored here, not through message.
+ mSurface = surface;
+ mHandler.sendEmptyMessage(MSG_SET_SURFACE);
+ }
+
+ /**
+ * Sets volume.
+ */
+ @MainThread
+ public void setStreamVolume(float volume) {
+ // mVolume is kept even when tune is called right after. But, messages can be deleted by
+ // tune or updateChannelBlockStatus. So mVolume is stored here and mPlayer.setVolume will be
+ // called in MSG_SET_STREAM_VOLUME.
+ mVolume = volume;
+ mHandler.sendEmptyMessage(MSG_SET_STREAM_VOLUME);
+ }
+
+ /**
+ * Sets if caption is enabled or disabled.
+ */
+ @MainThread
+ public void setCaptionEnabled(boolean captionEnabled) {
+ // mCaptionEnabled is kept even when tune is called right after. But, messages can be
+ // deleted by tune or updateChannelBlockStatus. So mCaptionEnabled is stored here and
+ // start/stopCaptionTrack will be called in MSG_UPDATE_CAPTION_STATUS.
+ mCaptionEnabled = captionEnabled;
+ mHandler.sendEmptyMessage(MSG_UPDATE_CAPTION_TRACK);
+ }
+
public TunerChannel getCurrentChannel() {
return mChannel;
}
+ @MainThread
public long getStartPosition() {
- return mCacheStartTimeMs;
+ return mBufferStartTimeMs;
}
@@ -245,10 +284,6 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return Uri.parse(mRecordingId).getPath();
}
- public Long getDurationForRecording() {
- return mRecordingDuration;
- }
-
private Long getDurationForRecording(String recordingId) {
try {
DvrStorageManager storageManager =
@@ -270,11 +305,15 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
}
+ @MainThread
public long getCurrentPosition() {
// TODO: More precise time may be necessary.
MpegTsPlayer mpegTsPlayer = mPlayer;
long currentTime = mpegTsPlayer != null
? mRecordStartTimeMs + mpegTsPlayer.getCurrentPosition() : mRecordStartTimeMs;
+ if (mChannel == null && mPlayerState == ExoPlayer.STATE_ENDED) {
+ currentTime = mRecordingDuration + mRecordStartTimeMs;
+ }
if (DEBUG) {
long systemCurrentTime = System.currentTimeMillis();
Log.d(TAG, "currentTime = " + currentTime
@@ -284,19 +323,25 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return currentTime;
}
+ @AnyThread
public void sendMessage(int messageType) {
mHandler.sendEmptyMessage(messageType);
}
+ @AnyThread
public void sendMessage(int messageType, Object object) {
mHandler.obtainMessage(messageType, object).sendToTarget();
}
+ @AnyThread
public void sendMessage(int messageType, int arg1, int arg2, Object object) {
mHandler.obtainMessage(messageType, arg1, arg2, object).sendToTarget();
}
+ @MainThread
public void release() {
+ if (DEBUG) Log.d(TAG, "release()");
+ mChannelDataManager.setListener(null);
mHandler.removeCallbacksAndMessages(null);
mHandler.sendEmptyMessage(MSG_RELEASE);
try {
@@ -309,29 +354,104 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
// MpegTsPlayer.Listener
+ // Called in the same thread as mHandler.
@Override
- public void onStateChanged(int generation, boolean playWhenReady, int playbackState) {
- sendMessage(MSG_PLAYBACK_STATE_CHANGED, generation, playbackState, playWhenReady);
+ public void onStateChanged(boolean playWhenReady, int playbackState) {
+ if (DEBUG) Log.d(TAG, "ExoPlayer state change: " + playbackState + " " + playWhenReady);
+ if (playbackState == mPlayerState) {
+ return;
+ }
+ mReadyStartTimeMs = INVALID_TIME;
+ mPreparingStartTimeMs = INVALID_TIME;
+ mBufferingStartTimeMs = INVALID_TIME;
+ if (playbackState == ExoPlayer.STATE_READY) {
+ if (DEBUG) Log.d(TAG, "ExoPlayer ready");
+ if (!mPlayerStarted) {
+ sendMessage(MSG_START_PLAYBACK, mPlayer);
+ }
+ mReadyStartTimeMs = SystemClock.elapsedRealtime();
+ } else if (playbackState == ExoPlayer.STATE_PREPARING) {
+ mPreparingStartTimeMs = SystemClock.elapsedRealtime();
+ } else if (playbackState == ExoPlayer.STATE_BUFFERING) {
+ mBufferingStartTimeMs = SystemClock.elapsedRealtime();
+ } else if (playbackState == ExoPlayer.STATE_ENDED) {
+ // Final status
+ // notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards.
+ Log.i(TAG, "Player ended: end of stream");
+ if (mChannel != null) {
+ sendMessage(MSG_RETRY_PLAYBACK, mPlayer);
+ }
+ }
+ mPlayerState = playbackState;
}
@Override
- public void onError(int generation, Exception e) {
- sendMessage(MSG_PLAYBACK_ERROR, generation, 0, e);
+ public void onError(Exception e) {
+ if (TunerPreferences.getStoreTsStream(mContext)) {
+ // Crash intentionally to capture the error causing TS file.
+ Log.e(TAG, "Crash intentionally to capture the error causing TS file. "
+ + e.getMessage());
+ SoftPreconditions.checkState(false);
+ }
+ // There maybe some errors that finally raise ExoPlaybackException and will be handled here.
+ // If we are playing live stream, retrying playback maybe helpful. But for recorded stream,
+ // retrying playback is not helpful.
+ if (mChannel != null) {
+ mHandler.obtainMessage(MSG_RETRY_PLAYBACK, mPlayer).sendToTarget();
+ }
}
@Override
- public void onVideoSizeChanged(int generation, int width, int height, float pixelWidthHeight) {
- sendMessage(MSG_PLAYBACK_VIDEO_SIZE_CHANGED, generation, 0, new Size(width, height));
+ public void onVideoSizeChanged(int width, int height, float pixelWidthHeight) {
+ if (mChannel != null && mChannel.hasVideo()) {
+ updateVideoTrack(width, height);
+ }
+ if (mRecordingId != null) {
+ updateVideoTrack(width, height);
+ }
}
@Override
public void onDrawnToSurface(MpegTsPlayer player, Surface surface) {
- sendMessage(MSG_DRAWN_TO_SURFACE, player);
+ if (mSurface != null && mPlayerStarted) {
+ if (DEBUG) Log.d(TAG, "MSG_DRAWN_TO_SURFACE");
+ mBufferStartTimeMs = mRecordStartTimeMs =
+ (mRecordingId != null) ? 0 : System.currentTimeMillis();
+ notifyVideoAvailable();
+ mReportedDrawnToSurface = true;
+
+ // If surface is drawn successfully, it means that the playback was brought back
+ // to normal and therefore, the playback recovery status will be reset through
+ // setting a zero value to the retry count.
+ // TODO: Consider audio only channels for detecting playback status changes to
+ // be normal.
+ mRetryCount = 0;
+ if (mCaptionEnabled && mCaptionTrack != null) {
+ startCaptionTrack();
+ } else {
+ stopCaptionTrack();
+ }
+ mHandler.sendEmptyMessage(MSG_NOTIFY_AUDIO_TRACK_UPDATED);
+ }
}
@Override
- public void onAudioUnplayable(int generation) {
- sendMessage(MSG_AUDIO_UNPLAYABLE, generation);
+ public void onSmoothTrickplayForceStopped() {
+ if (mPlayer == null || !mHandler.hasMessages(MSG_SMOOTH_TRICKPLAY_MONITOR)) {
+ return;
+ }
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ doTrickplayBySeek((int) mPlayer.getCurrentPosition());
+ }
+
+ @Override
+ public void onAudioUnplayable() {
+ if (mPlayer == null) {
+ return;
+ }
+ Log.i(TAG, "AC3 audio cannot be played due to device limitation");
+ mSession.sendUiMessage(
+ TunerSession.MSG_UI_SHOW_AUDIO_UNPLAYABLE);
}
// MpegTsPlayer.VideoEventListener
@@ -366,15 +486,15 @@ public class TunerSessionWorker implements PlaybackCacheListener,
sendMessage(MSG_PROGRAM_DATA_RESULT, new Pair<>(channel, programs));
}
- // PlaybackCacheListener
+ // PlaybackBufferListener
@Override
- public void onCacheStartTimeChanged(long startTimeMs) {
- sendMessage(MSG_CACHE_START_TIME_CHANGED, startTimeMs);
+ public void onBufferStartTimeChanged(long startTimeMs) {
+ sendMessage(MSG_BUFFER_START_TIME_CHANGED, startTimeMs);
}
@Override
- public void onCacheStateChanged(boolean available) {
- sendMessage(MSG_CACHE_STATE_CHANGED, available);
+ public void onBufferStateChanged(boolean available) {
+ sendMessage(MSG_BUFFER_STATE_CHANGED, available);
}
@Override
@@ -393,6 +513,11 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mChannelDataManager.notifyEventDetected(channel, items);
}
+ @Override
+ public void onChannelScanDone() {
+ // do nothing.
+ }
+
private long parseChannel(Uri uri) {
try {
List<String> paths = uri.getPathSegments();
@@ -405,8 +530,8 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
private static class RecordedProgram {
- private long mChannelId;
- private String mDataUri;
+ private final long mChannelId;
+ private final String mDataUri;
private static final String[] PROJECTION = {
TvContract.Programs.COLUMN_CHANNEL_ID,
@@ -441,7 +566,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
ContentResolver resolver = mContext.getContentResolver();
try(Cursor c = resolver.query(recordedUri, RecordedProgram.PROJECTION, null, null, null)) {
if (c != null) {
- RecordedProgram result = RecordedProgram.onQuery(c);
+ RecordedProgram result = RecordedProgram.onQuery(c);
if (DEBUG) {
Log.d(TAG, "Finished query for " + this);
}
@@ -450,9 +575,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
if (c == null) {
Log.e(TAG, "Unknown query error for " + this);
} else {
- if (DEBUG) {
- Log.d(TAG, "Canceled query for " + this);
- }
+ if (DEBUG) Log.d(TAG, "Canceled query for " + this);
}
return null;
}
@@ -478,6 +601,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
if (mHandler.hasMessages(MSG_TUNE)) {
return true;
}
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
Uri channelUri = (Uri) msg.obj;
String recording = null;
long channelId = parseChannel(channelUri);
@@ -489,8 +613,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
if (channel == null && recording == null) {
Log.w(TAG, "onTune() is failed. Can't find channel for " + channelUri);
stopTune();
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
return true;
}
mHandler.removeCallbacksAndMessages(null);
@@ -505,154 +628,71 @@ public class TunerSessionWorker implements PlaybackCacheListener,
resetTvTracks();
mHandler.sendEmptyMessageDelayed(MSG_RESCHEDULE_PROGRAMS,
RESCHEDULE_PROGRAMS_INITIAL_DELAY_MS);
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL,
- CHECK_NO_SIGNAL_INITIAL_DELAY_MS);
return true;
}
case MSG_STOP_TUNE: {
- if (DEBUG) {
- Log.d(TAG, "MSG_STOP_TUNE");
- }
+ if (DEBUG) Log.d(TAG, "MSG_STOP_TUNE");
mChannel = null;
stopPlayback();
stopCaptionTrack();
resetTvTracks();
- mTunerHal.stopTune();
- mSource = null;
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
return true;
}
case MSG_RELEASE: {
- if (DEBUG) {
- Log.d(TAG, "MSG_RELEASE");
- }
+ if (DEBUG) Log.d(TAG, "MSG_RELEASE");
mHandler.removeCallbacksAndMessages(null);
stopPlayback();
stopCaptionTrack();
- try {
- mTunerHal.close();
- } catch (Exception ex) {
- Log.e(TAG, "Error on closing tuner HAL.", ex);
- }
- mSource = null;
+ mSourceManager.release();
mReleaseLatch.countDown();
return true;
}
case MSG_RETRY_PLAYBACK: {
if (mPlayer == msg.obj) {
+ Log.i(TAG, "Retrying the playback for channel: " + mChannel);
mHandler.removeMessages(MSG_RETRY_PLAYBACK);
+ // When there is a request of retrying playback, don't reuse TunerHal.
+ mSourceManager.setKeepTuneStatus(false);
mRetryCount++;
if (DEBUG) {
Log.d(TAG, "MSG_RETRY_PLAYBACK " + mRetryCount);
}
- if (mRetryCount <= MAX_RETRY_COUNT) {
+ if (mRetryCount <= MAX_IMMEDIATE_RETRY_COUNT) {
resetPlayback();
} else {
// When it reaches this point, it may be due to an error that occurred in
- // the tuner device. Calling stopPlayback() and TunerHal.stopTune()
- // resets the tuner device to recover from the error.
+ // the tuner device. Calling stopPlayback() resets the tuner device
+ // to recover from the error.
stopPlayback();
stopCaptionTrack();
- mTunerHal.stopTune();
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
- // After MAX_RETRY_COUNT, give some delay of an empirically chosen value
- // before recovering the playback.
- mHandler.sendEmptyMessageDelayed(MSG_RECOVER_STOPPED_PLAYBACK,
+ // After MAX_IMMEDIATE_RETRY_COUNT, give some delay of an empirically chosen
+ // value before recovering the playback.
+ mHandler.sendEmptyMessageDelayed(MSG_RESET_PLAYBACK,
RECOVER_STOPPED_PLAYBACK_PERIOD_MS);
}
}
return true;
}
- case MSG_RECOVER_STOPPED_PLAYBACK: {
- if (DEBUG) {
- Log.d(TAG, "MSG_RECOVER_STOPPED_PLAYBACK");
- }
+ case MSG_RESET_PLAYBACK: {
+ if (DEBUG) Log.d(TAG, "MSG_RESET_PLAYBACK");
resetPlayback();
return true;
}
case MSG_START_PLAYBACK: {
- if (DEBUG) {
- Log.d(TAG, "MSG_START_PLAYBACK");
- }
+ if (DEBUG) Log.d(TAG, "MSG_START_PLAYBACK");
if (mChannel != null || mRecordingId != null) {
startPlayback(msg.obj);
}
return true;
}
- case MSG_PLAYBACK_STATE_CHANGED: {
- int generation = msg.arg1;
- int playbackState = msg.arg2;
- boolean playWhenReady = (boolean) msg.obj;
- if (DEBUG) {
- Log.d(TAG, "ExoPlayer state change: " + generation + " "
- + playbackState + " " + playWhenReady);
- }
-
- // Generation starts from 1 not 0.
- if (playbackState == MpegTsPlayer.STATE_READY
- && mPreparingGeneration == mPlayerGeneration) {
- if (DEBUG) {
- Log.d(TAG, "ExoPlayer ready: " + mPlayerGeneration);
- }
-
- // mPreparingGeneration was set to mPlayerGeneration in order to indicate that
- // ExoPlayer is in its preparing status when MpegTsPlayer::prepare() was called.
- // Now MpegTsPlayer::prepare() is finished. Clear preparing state in order to
- // ensure another DO_START_PLAYBACK will not be sent for same generation.
- mPreparingGeneration = 0;
- sendMessage(MSG_START_PLAYBACK, mPlayer);
- } else if (playbackState == MpegTsPlayer.STATE_ENDED
- && mEndedGeneration != generation) {
- // Final status
- // notification of STATE_ENDED from MpegTsPlayer will be ignored afterwards.
- mEndedGeneration = generation;
- Log.i(TAG, "Player ended: end of stream " + generation);
- sendMessage(MSG_RETRY_PLAYBACK, mPlayer);
- }
- return true;
- }
- case MSG_PLAYBACK_ERROR: {
- int generation = msg.arg1;
- Exception exception = (Exception) msg.obj;
- Log.i(TAG, "ExoPlayer Error: " + generation + " " + mPlayerGeneration);
- if (generation != mPlayerGeneration) {
- return true;
- }
- mHandler.obtainMessage(MSG_RETRY_PLAYBACK, mPlayer).sendToTarget();
- return true;
- }
- case MSG_PLAYBACK_VIDEO_SIZE_CHANGED: {
- int generation = msg.arg1;
- Size size = (Size) msg.obj;
- if (generation != mPlayerGeneration) {
- return true;
- }
- if (mChannel != null && mChannel.hasVideo()) {
- updateVideoTrack(size.getWidth(), size.getHeight());
- }
- if (mRecordingId != null) {
- updateVideoTrack(size.getWidth(), size.getHeight());
- }
- return true;
- }
- case MSG_AUDIO_UNPLAYABLE: {
- int generation = (int) msg.obj;
- if (mPlayer == null || generation != mPlayerGeneration) {
- return true;
- }
- Log.i(TAG, "AC3 audio cannot be played due to device limitation");
- mSession.sendUiMessage(
- TunerSession.MSG_UI_SHOW_AUDIO_UNPLAYABLE);
- return true;
- }
case MSG_UPDATE_PROGRAM: {
if (mChannel != null) {
EitItem program = (EitItem) msg.obj;
- updateTvTracks(program);
+ updateTvTracks(program, false);
mHandler.sendEmptyMessage(MSG_PARENTAL_CONTROLS);
}
return true;
@@ -684,7 +724,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
continue;
}
mProgram = item;
- updateTvTracks(item);
+ updateTvTracks(item, false);
} else if (item.getStartTimeUtcMillis() > currentTimeMs) {
if (DEBUG) {
Log.d(TAG, "Update next TvTracks " + item + " "
@@ -716,32 +756,37 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
return true;
}
- case MSG_DRAWN_TO_SURFACE: {
- if (mPlayer == msg.obj && mSurface != null && mPlayerStarted) {
- if (DEBUG) {
- Log.d(TAG, "MSG_DRAWN_TO_SURFACE");
- }
- mCacheStartTimeMs = mRecordStartTimeMs =
- (mRecordingId != null) ? 0 : System.currentTimeMillis();
- mSession.notifyVideoAvailable();
- mReportedDrawnToSurface = true;
-
- // If surface is drawn successfully, it means that the playback was brought back
- // to normal and therefore, the playback recovery status will be reset through
- // setting a zero value to the retry count.
- // TODO: Consider audio only channels for detecting playback status changes to
- // be normal.
- mRetryCount = 0;
- if (mCaptionEnabled && mCaptionTrack != null) {
- startCaptionTrack();
- } else {
- stopCaptionTrack();
- }
+ case MSG_TRICKPLAY_BY_SEEK: {
+ if (mPlayer == null) {
+ return true;
}
+ doTrickplayBySeek(msg.arg1);
return true;
}
- case MSG_TRICKPLAY: {
- doTrickplay(msg.arg1);
+ case MSG_SMOOTH_TRICKPLAY_MONITOR: {
+ if (mPlayer == null) {
+ return true;
+ }
+ long systemCurrentTime = System.currentTimeMillis();
+ long position = getCurrentPosition();
+ if (mRecordingId == null) {
+ // Checks if the position exceeds the upper bound when forwarding,
+ // or exceed the lower bound when rewinding.
+ // If the direction is not checked, there can be some issues.
+ // (See b/29939781 for more details.)
+ if ((position > systemCurrentTime && mPlaybackParams.getSpeed() > 0L)
+ || (position < mBufferStartTimeMs && mPlaybackParams.getSpeed() < 0L)) {
+ doTimeShiftResume();
+ return true;
+ }
+ } else {
+ if (position > mRecordingDuration || position < 0) {
+ doTimeShiftPause();
+ return true;
+ }
+ }
+ mHandler.sendEmptyMessageDelayed(MSG_SMOOTH_TRICKPLAY_MONITOR,
+ TRICKPLAY_MONITOR_INTERVAL_MS);
return true;
}
case MSG_RESCHEDULE_PROGRAMS: {
@@ -777,8 +822,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
return true;
}
- case MSG_SET_CAPTION_ENABLED: {
- mCaptionEnabled = (boolean) msg.obj;
+ case MSG_UPDATE_CAPTION_TRACK: {
if (mCaptionEnabled) {
startCaptionTrack();
} else {
@@ -787,18 +831,34 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return true;
}
case MSG_TIMESHIFT_PAUSE: {
+ if (DEBUG) Log.d(TAG, "MSG_TIMESHIFT_PAUSE");
+ if (mPlayer == null) {
+ return true;
+ }
doTimeShiftPause();
return true;
}
case MSG_TIMESHIFT_RESUME: {
+ if (DEBUG) Log.d(TAG, "MSG_TIMESHIFT_RESUME");
+ if (mPlayer == null) {
+ return true;
+ }
doTimeShiftResume();
return true;
}
case MSG_TIMESHIFT_SEEK_TO: {
- doTimeShiftSeekTo((long) msg.obj);
+ long position = (long) msg.obj;
+ if (DEBUG) Log.d(TAG, "MSG_TIMESHIFT_SEEK_TO (position=" + position + ")");
+ if (mPlayer == null) {
+ return true;
+ }
+ doTimeShiftSeekTo(position);
return true;
}
case MSG_TIMESHIFT_SET_PLAYBACKPARAMS: {
+ if (mPlayer == null) {
+ return true;
+ }
doTimeShiftSetPlaybackParams((PlaybackParams) msg.obj);
return true;
}
@@ -817,32 +877,18 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
return true;
}
- case MSG_SET_SURFACE: {
- Surface surface = (Surface) msg.obj;
- if (DEBUG) {
- Log.d(TAG, "MSG_SET_SURFACE " + surface);
- }
- if (surface != null && !surface.isValid()) {
- Log.w(TAG, "Ignoring invalid surface.");
- return true;
- }
- mSurface = surface;
- resetPlayback();
- return true;
- }
case MSG_SET_STREAM_VOLUME: {
- mVolume = (float) msg.obj;
if (mPlayer != null && mPlayer.isPlaying()) {
mPlayer.setVolume(mVolume);
}
return true;
}
- case MSG_CACHE_START_TIME_CHANGED: {
+ case MSG_BUFFER_START_TIME_CHANGED: {
if (mPlayer == null) {
return true;
}
- mCacheStartTimeMs = (long) msg.obj;
- if (!hasEnoughBackwardCache()
+ mBufferStartTimeMs = (long) msg.obj;
+ if (!hasEnoughBackwardBuffer()
&& (!mPlayer.isPlaying() || mPlaybackParams.getSpeed() < 1.0f)) {
mPlayer.setPlayWhenReady(true);
mPlayer.setAudioTrack(true);
@@ -850,7 +896,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
return true;
}
- case MSG_CACHE_STATE_CHANGED: {
+ case MSG_BUFFER_STATE_CHANGED: {
boolean available = (boolean) msg.obj;
mSession.notifyTimeShiftStatusChanged(available
? TvInputManager.TIME_SHIFT_STATUS_AVAILABLE
@@ -858,26 +904,27 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return true;
}
case MSG_CHECK_SIGNAL: {
- if (mChannel == null) {
+ if (mChannel == null || mPlayer == null) {
return true;
}
- long limitInBytes = mSource != null ? mSource.getLimit() : 0L;
- long positionInBytes = mSource != null ? mSource.getPosition() : 0L;
- if (UsbTunerDebug.ENABLED) {
- UsbTunerDebug.calculateDiff();
+ TsDataSource source = mPlayer.getDataSource();
+ long limitInBytes = source != null ? source.getBufferedPosition() : 0L;
+ long positionInBytes = source != null ? source.getLastReadPosition() : 0L;
+ if (TunerDebug.ENABLED) {
+ TunerDebug.calculateDiff();
mSession.sendUiMessage(TunerSession.MSG_UI_SET_STATUS_TEXT,
Html.fromHtml(
StatusTextUtils.getStatusWarningInHTML(
(limitInBytes - mLastLimitInBytes)
/ TS_PACKET_SIZE,
- UsbTunerDebug.getVideoFrameDrop(),
- UsbTunerDebug.getBytesInQueue(),
- UsbTunerDebug.getAudioPositionUs(),
- UsbTunerDebug.getAudioPositionUsRate(),
- UsbTunerDebug.getAudioPtsUs(),
- UsbTunerDebug.getAudioPtsUsRate(),
- UsbTunerDebug.getVideoPtsUs(),
- UsbTunerDebug.getVideoPtsUsRate()
+ TunerDebug.getVideoFrameDrop(),
+ TunerDebug.getBytesInQueue(),
+ TunerDebug.getAudioPositionUs(),
+ TunerDebug.getAudioPositionUsRate(),
+ TunerDebug.getAudioPtsUs(),
+ TunerDebug.getAudioPtsUsRate(),
+ TunerDebug.getVideoPtsUs(),
+ TunerDebug.getVideoPtsUsRate()
)));
}
if (DEBUG) {
@@ -885,23 +932,56 @@ public class TunerSessionWorker implements PlaybackCacheListener,
positionInBytes, limitInBytes));
}
mSession.sendUiMessage(TunerSession.MSG_UI_HIDE_MESSAGE);
- if (mSource != null && mChannel.getType() == Channel.TYPE_TUNER
- && positionInBytes == mLastPositionInBytes
- && limitInBytes == mLastLimitInBytes) {
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
-
- mReportedSignalAvailable = false;
- } else {
- if (mReportedDrawnToSurface && !mReportedSignalAvailable) {
- mSession.notifyVideoAvailable();
- mReportedSignalAvailable = true;
+ long currentTime = SystemClock.elapsedRealtime();
+ boolean noBufferRead = positionInBytes == mLastPositionInBytes
+ && limitInBytes == mLastLimitInBytes;
+ boolean isBufferingTooLong = mBufferingStartTimeMs != INVALID_TIME
+ && currentTime - mBufferingStartTimeMs
+ > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
+ boolean isPreparingTooLong = mPreparingStartTimeMs != INVALID_TIME
+ && currentTime - mPreparingStartTimeMs
+ > PLAYBACK_STATE_CHANGED_WAITING_THRESHOLD_MS;
+ boolean isWeakSignal = source != null
+ && mChannel.getType() == Channel.TYPE_TUNER
+ && (noBufferRead || isBufferingTooLong || isPreparingTooLong);
+ if (isWeakSignal && !mReportedWeakSignal) {
+ if (!mHandler.hasMessages(MSG_RETRY_PLAYBACK)) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_RETRY_PLAYBACK, mPlayer), PLAYBACK_RETRY_DELAY_MS);
+ }
+ if (mPlayer != null) {
+ mPlayer.setAudioTrack(false);
+ }
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
+ } 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.setAudioTrack(true);
}
}
mLastLimitInBytes = limitInBytes;
mLastPositionInBytes = positionInBytes;
- mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL,
- CHECK_NO_SIGNAL_PERIOD_MS);
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL, CHECK_NO_SIGNAL_PERIOD_MS);
+ return true;
+ }
+ case MSG_SET_SURFACE: {
+ if (mPlayer != null) {
+ mPlayer.setSurface(mSurface);
+ } else {
+ // TODO: Since surface is dynamically set, we can remove the dependency of
+ // playback start on mSurface nullity.
+ resetPlayback();
+ }
+ return true;
+ }
+ case MSG_NOTIFY_AUDIO_TRACK_UPDATED: {
+ notifyAudioTracksUpdated();
return true;
}
default: {
@@ -927,8 +1007,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mChannel.selectAudioTrack(audioTrack.index);
int newAudioPid = mChannel.getAudioPid();
if (oldAudioPid != newAudioPid) {
- // TODO: Implement a switching between tracks more smoothly.
- resetPlayback();
+ mPlayer.setSelectedTrack(MpegTsPlayer.TRACK_TYPE_AUDIO, audioTrack.index);
}
mSession.notifyTrackSelected(type, trackId);
} else if (type == TvTrackInfo.TYPE_SUBTITLE) {
@@ -951,17 +1030,16 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
}
- private MpegTsPlayer createPlayer(AudioCapabilities capabilities, CacheManager cacheManager) {
+ private MpegTsPlayer createPlayer(AudioCapabilities capabilities, BufferManager bufferManager) {
if (capabilities == null) {
Log.w(TAG, "No Audio Capabilities");
}
- ++mPlayerGeneration;
- MpegTsPlayer player = new MpegTsPlayer(mPlayerGeneration,
- new MpegTsPassthroughAc3RendererBuilder(mContext, cacheManager, this),
- mHandler, capabilities, this);
+ MpegTsPlayer player = new MpegTsPlayer(
+ new MpegTsRendererBuilder(mContext, bufferManager, this),
+ mHandler, mSourceManager, capabilities, this);
Log.i(TAG, "Passthrough AC3 renderer");
- if (DEBUG) Log.d(TAG, "ExoPlayer created: " + mPlayerGeneration);
+ if (DEBUG) Log.d(TAG, "ExoPlayer created");
return player;
}
@@ -990,13 +1068,17 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mSession.notifyTracksChanged(mTvTracks);
}
- private void updateTvTracks(TvTracksInterface tvTracksInterface) {
+ private void updateTvTracks(TvTracksInterface tvTracksInterface, boolean fromPmt) {
if (DEBUG) {
Log.d(TAG, "UpdateTvTracks " + tvTracksInterface);
}
List<AtscAudioTrack> audioTracks = tvTracksInterface.getAudioTracks();
List<AtscCaptionTrack> captionTracks = tvTracksInterface.getCaptionTracks();
- if (audioTracks != null && !audioTracks.isEmpty()) {
+ // According to ATSC A/69 chapter 6.9, both PMT and EIT should have descriptors for audio
+ // tracks, but in real world, we see some bogus audio track info in EIT, so, we trust audio
+ // track info in PMT more and use info in EIT only when we have nothing.
+ if (audioTracks != null && !audioTracks.isEmpty()
+ && (mChannel.getAudioTracks() == null || fromPmt)) {
updateAudioTracks(audioTracks);
}
if (captionTracks == null || captionTracks.isEmpty()) {
@@ -1030,39 +1112,48 @@ public class TunerSessionWorker implements PlaybackCacheListener,
if (DEBUG) {
Log.d(TAG, "Update AudioTracks " + audioTracks);
}
- removeTvTracks(TvTrackInfo.TYPE_AUDIO);
mAudioTrackMap.clear();
if (audioTracks != null) {
int index = 0;
for (AtscAudioTrack audioTrack : audioTracks) {
- String language = audioTrack.language;
- if (language == null && mChannel.getAudioTracks() != null
- && mChannel.getAudioTracks().size() == audioTracks.size()) {
- // If a language is not present, use a language field in PMT section parsed.
- language = mChannel.getAudioTracks().get(index).language;
- }
-
- // Save the index to the audio track.
- // Later, when a audio track is selected, Both an audio pid and its audio stream
- // type reside in the selected index position of the tuner channel's audio data.
audioTrack.index = index;
- TvTrackInfo.Builder builder = new TvTrackInfo.Builder(
- TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + index);
- if (IsoUtils.isValidIso3Language(language)) {
- builder.setLanguage(language);
- }
- if (audioTrack.channelCount != 0) {
- builder.setAudioChannelCount(audioTrack.channelCount);
- }
- if (audioTrack.sampleRate != 0) {
- builder.setAudioSampleRate(audioTrack.sampleRate);
- }
- TvTrackInfo track = builder.build();
- mTvTracks.add(track);
mAudioTrackMap.put(index, audioTrack);
++index;
}
}
+ mHandler.sendEmptyMessage(MSG_NOTIFY_AUDIO_TRACK_UPDATED);
+ }
+
+ private void notifyAudioTracksUpdated() {
+ if (mPlayer == null) {
+ // Audio tracks will be updated later once player initialization is done.
+ return;
+ }
+ int audioTrackCount = mPlayer.getTrackCount(MpegTsPlayer.TRACK_TYPE_AUDIO);
+ removeTvTracks(TvTrackInfo.TYPE_AUDIO);
+ for (int i = 0; i < audioTrackCount; i++) {
+ AtscAudioTrack audioTrack = mAudioTrackMap.get(i);
+ if (audioTrack == null) {
+ continue;
+ }
+ String language = audioTrack.language;
+ if (language == null && mChannel.getAudioTracks() != null
+ && mChannel.getAudioTracks().size() == mAudioTrackMap.size()) {
+ // If a language is not present, use a language field in PMT section parsed.
+ language = mChannel.getAudioTracks().get(i).language;
+ }
+ // Save the index to the audio track.
+ // Later, when an audio track is selected, both the audio pid and its audio stream
+ // type reside in the selected index position of the tuner channel's audio data.
+ audioTrack.index = i;
+ TvTrackInfo.Builder builder = new TvTrackInfo.Builder(
+ TvTrackInfo.TYPE_AUDIO, AUDIO_TRACK_PREFIX + i);
+ builder.setLanguage(language);
+ builder.setAudioChannelCount(audioTrack.channelCount);
+ builder.setAudioSampleRate(audioTrack.sampleRate);
+ TvTrackInfo track = builder.build();
+ mTvTracks.add(track);
+ }
mSession.notifyTracksChanged(mTvTracks);
}
@@ -1084,9 +1175,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
TvTrackInfo.Builder builder =
new TvTrackInfo.Builder(TvTrackInfo.TYPE_SUBTITLE,
SUBTITLE_TRACK_PREFIX + captionTrack.serviceNumber);
- if (IsoUtils.isValidIso3Language(language)) {
- builder.setLanguage(language);
- }
+ builder.setLanguage(language);
mTvTracks.add(builder.build());
mCaptionTrackMap.put(captionTrack.serviceNumber, captionTrack);
}
@@ -1112,7 +1201,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mChannel.setVideoPid(channel.getVideoPid());
mChannel.setAudioPids(audioPids);
mChannel.setAudioStreamTypes(audioStreamTypes);
- updateTvTracks(mChannel);
+ updateTvTracks(channel, true);
int index = audioPids.isEmpty() ? -1 : 0;
for (int i = 0; i < size; ++i) {
if (audioPids.get(i) == oldAudioPid) {
@@ -1138,18 +1227,20 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
private void stopPlayback() {
+ mChannelDataManager.removeAllCallbacksAndMessages();
if (mPlayer != null) {
- if (mSource != null) {
- mSource.stopStream();
- }
mPlayer.setPlayWhenReady(false);
mPlayer.release();
mPlayer = null;
+ mPlayerState = ExoPlayer.STATE_IDLE;
mPlaybackParams.setSpeed(1.0f);
mPlayerStarted = false;
mReportedDrawnToSurface = false;
- mReportedSignalAvailable = false;
+ mPreparingStartTimeMs = INVALID_TIME;
+ mBufferingStartTimeMs = INVALID_TIME;
+ mReadyStartTimeMs = INVALID_TIME;
mSession.sendUiMessage(TunerSession.MSG_UI_HIDE_AUDIO_UNPLAYABLE);
+ mSession.notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_UNAVAILABLE);
}
}
@@ -1159,73 +1250,65 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return;
}
if (mChannel != null && !mChannel.hasAudio()) {
- // A channel needs to have a audio stream at least to play in exoPlayer.
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+ if (DEBUG) Log.d(TAG, "Channel " + mChannel + " does not have audio.");
+ // Playbacks with video-only stream have not been tested yet.
+ // No video-only channel has been found.
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
return;
}
- if (mSurface != null && !mPlayerStarted) {
- mPlayer.setSurface(mSurface);
+ if (mChannel != null && ((mChannel.hasAudio() && !mPlayer.hasAudio())
+ || (mChannel.hasVideo() && !mPlayer.hasVideo()))) {
+ // Tracks haven't been detected in the extractor. Try again.
+ sendMessage(MSG_RETRY_PLAYBACK, mPlayer);
+ return;
+ }
+ // Since mSurface is volatile, we define a local variable surface to keep the same value
+ // inside this method.
+ Surface surface = mSurface;
+ if (surface != null && !mPlayerStarted) {
+ mPlayer.setSurface(surface);
mPlayer.setPlayWhenReady(true);
mPlayer.setVolume(mVolume);
if (mChannel != null && !mChannel.hasVideo() && mChannel.hasAudio()) {
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY);
- } else {
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING);
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY);
+ } else if (!mReportedWeakSignal) {
+ // Doesn't show buffering during weak signal.
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING);
}
mSession.sendUiMessage(TunerSession.MSG_UI_HIDE_MESSAGE);
mPlayerStarted = true;
}
}
- private void playFromChannel(long timestamp) {
- long oldTimestamp;
- mSource = null;
- if (mChannel.getType() == Channel.TYPE_TUNER) {
- mSource = mTunerSource;
- } else if (mChannel.getType() == Channel.TYPE_FILE) {
- mSource = mFileSource;
+ private void preparePlayback() {
+ SoftPreconditions.checkState(mPlayer == null);
+ if (mChannel == null && mRecordingId == null) {
+ return;
}
- Assert.assertNotNull(mSource);
- if (mSource.tuneToChannel(mChannel)) {
- if (ENABLE_PROFILER) {
- oldTimestamp = timestamp;
- timestamp = SystemClock.elapsedRealtime();
- Log.i(TAG, "[Profiler] tuneToChannel() takes " + (timestamp - oldTimestamp)
- + " ms");
+ mSourceManager.setKeepTuneStatus(true);
+ BufferManager bufferManager = mChannel != null ? mBufferManager : new BufferManager(
+ new DvrStorageManager(new File(getRecordingPath()), false));
+ MpegTsPlayer player = createPlayer(mAudioCapabilities, bufferManager);
+ player.setCaptionServiceNumber(Cea708Data.EMPTY_SERVICE_NUMBER);
+ player.setVideoEventListener(this);
+ player.setCaptionServiceNumber(mCaptionTrack != null ?
+ mCaptionTrack.serviceNumber : Cea708Data.EMPTY_SERVICE_NUMBER);
+ if (!player.prepare(mContext, mChannel, this)) {
+ mSourceManager.setKeepTuneStatus(false);
+ player.release();
+ if (!mHandler.hasMessages(MSG_TUNE)) {
+ // When prepare failed, there may be some errors related to hardware. In that
+ // case, retry playback immediately may not help.
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_RETRY_PLAYBACK, mPlayer),
+ PLAYBACK_RETRY_DELAY_MS);
}
- mSource.startStream();
- mPlayer = createPlayer(mAudioCapabilities, mCacheManager);
- mPlayer.setCaptionServiceNumber(Cea708Data.EMPTY_SERVICE_NUMBER);
- mPlayer.setVideoEventListener(this);
- mPlayer.setCaptionServiceNumber(mCaptionTrack != null ?
- mCaptionTrack.serviceNumber : Cea708Data.EMPTY_SERVICE_NUMBER);
- mPreparingGeneration = mPlayerGeneration;
- mPlayer.prepare((MediaDataSource) mSource);
- mPlayerStarted = false;
} else {
- // Close TunerHal when tune fails.
- mTunerHal.stopTune();
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
- }
- }
-
- private void playFromRecording() {
- // TODO: Handle errors.
- CacheManager cacheManager =
- new CacheManager(new DvrStorageManager(new File(getRecordingPath()), false));
- mSource = null;
- mPlayer = createPlayer(mAudioCapabilities, cacheManager);
- mPlayer.setCaptionServiceNumber(Cea708Data.EMPTY_SERVICE_NUMBER);
- mPlayer.setVideoEventListener(this);
- mPlayer.setCaptionServiceNumber(mCaptionTrack != null ?
- mCaptionTrack.serviceNumber : Cea708Data.EMPTY_SERVICE_NUMBER);
- mPreparingGeneration = mPlayerGeneration;
- mPlayer.prepare(null);
- mPlayerStarted = false;
+ mPlayer = player;
+ mPlayerStarted = false;
+ mHandler.removeMessages(MSG_CHECK_SIGNAL);
+ mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL, CHECK_NO_SIGNAL_INITIAL_DELAY_MS);
+ }
}
private void resetPlayback() {
@@ -1238,15 +1321,10 @@ public class TunerSessionWorker implements PlaybackCacheListener,
timestamp = SystemClock.elapsedRealtime();
Log.i(TAG, "[Profiler] stopPlayback() takes " + (timestamp - oldTimestamp) + " ms");
}
- if (!mChannelBlocked && mSurface != null) {
- mSession.notifyVideoUnavailable(
- TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
- if (mChannel != null) {
- playFromChannel(timestamp);
- } else if (mRecordingId != null){
- playFromRecording();
- }
+ if (mChannelBlocked || mSurface == null) {
+ return;
}
+ preparePlayback();
}
private void prepareTune(TunerChannel channel, String recording) {
@@ -1258,7 +1336,7 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mRecordingDuration = recording != null ? getDurationForRecording(recording) : null;
mProgram = null;
mPrograms = null;
- mCacheStartTimeMs = mRecordStartTimeMs =
+ mBufferStartTimeMs = mRecordStartTimeMs =
(mRecordingId != null) ? 0 : System.currentTimeMillis();
mLastPositionMs = 0;
mCaptionTrack = null;
@@ -1290,20 +1368,26 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
private int getTrickPlaySeekIntervalMs() {
- return Math.max(MIN_TRICKPLAY_SEEK_INTERVAL_MS,
- (int) Math.abs(TRICKPLAY_SEEK_INTERVAL_MS / mPlaybackParams.getSpeed()));
+ return Math.max(EXPECTED_KEY_FRAME_INTERVAL_MS / (int) Math.abs(mPlaybackParams.getSpeed()),
+ MIN_TRICKPLAY_SEEK_INTERVAL_MS);
}
- private void doTrickplay(int seekPositionMs) {
- mHandler.removeMessages(MSG_TRICKPLAY);
- if (mPlaybackParams.getSpeed() == 1.0f || !mPlayer.isPlaying()) {
+ private void doTrickplayBySeek(int seekPositionMs) {
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
+ if (mPlaybackParams.getSpeed() == 1.0f || !mPlayer.isPrepared()) {
return;
}
- if (seekPositionMs < mCacheStartTimeMs - mRecordStartTimeMs) {
- mPlayer.seekTo(mCacheStartTimeMs - mRecordStartTimeMs);
- mPlaybackParams.setSpeed(1.0f);
- mPlayer.setAudioTrack(true);
- return;
+ if (seekPositionMs < mBufferStartTimeMs - mRecordStartTimeMs) {
+ if (mPlaybackParams.getSpeed() > 1.0f) {
+ // If fast forwarding, the seekPositionMs can be out of the buffered range
+ // because of chuck evictions.
+ seekPositionMs = (int) (mBufferStartTimeMs - mRecordStartTimeMs);
+ } else {
+ mPlayer.seekTo(mBufferStartTimeMs - mRecordStartTimeMs);
+ mPlaybackParams.setSpeed(1.0f);
+ mPlayer.setAudioTrack(true);
+ return;
+ }
} else if (seekPositionMs > System.currentTimeMillis() - mRecordStartTimeMs) {
mPlayer.seekTo(System.currentTimeMillis() - mRecordStartTimeMs);
mPlaybackParams.setSpeed(1.0f);
@@ -1311,16 +1395,21 @@ public class TunerSessionWorker implements PlaybackCacheListener,
return;
}
+ long delayForNextSeek = getTrickPlaySeekIntervalMs();
if (!mPlayer.isBuffering()) {
mPlayer.seekTo(seekPositionMs);
+ } else {
+ delayForNextSeek = MIN_TRICKPLAY_SEEK_INTERVAL_MS;
}
- seekPositionMs += mPlaybackParams.getSpeed() * getTrickPlaySeekIntervalMs();
- mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TRICKPLAY, seekPositionMs, 0),
- getTrickPlaySeekIntervalMs());
+ seekPositionMs += mPlaybackParams.getSpeed() * delayForNextSeek;
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(
+ MSG_TRICKPLAY_BY_SEEK, seekPositionMs, 0), delayForNextSeek);
}
private void doTimeShiftPause() {
- if (!hasEnoughBackwardCache()) {
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
+ if (!hasEnoughBackwardBuffer()) {
return;
}
mPlaybackParams.setSpeed(1.0f);
@@ -1329,34 +1418,59 @@ public class TunerSessionWorker implements PlaybackCacheListener,
}
private void doTimeShiftResume() {
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
mPlaybackParams.setSpeed(1.0f);
mPlayer.setPlayWhenReady(true);
mPlayer.setAudioTrack(true);
}
private void doTimeShiftSeekTo(long timeMs) {
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
mPlayer.seekTo((int) (timeMs - mRecordStartTimeMs));
}
private void doTimeShiftSetPlaybackParams(PlaybackParams params) {
- if (!hasEnoughBackwardCache() && params.getSpeed() < 1.0f) {
+ if (!hasEnoughBackwardBuffer() && params.getSpeed() < 1.0f) {
return;
}
mPlaybackParams = params;
- if (!mHandler.hasMessages(MSG_TRICKPLAY)) {
- // Initiate trickplay
- float rate = mPlaybackParams.getSpeed();
- if (rate != 1.0f) {
+ float speed = mPlaybackParams.getSpeed();
+ if (speed == 1.0f) {
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
+ doTimeShiftResume();
+ } else if (mPlayer.supportSmoothTrickPlay(speed)) {
+ mHandler.removeMessages(MSG_TRICKPLAY_BY_SEEK);
+ mPlayer.setAudioTrack(false);
+ mPlayer.startSmoothTrickplay(mPlaybackParams);
+ mHandler.sendEmptyMessageDelayed(MSG_SMOOTH_TRICKPLAY_MONITOR,
+ TRICKPLAY_MONITOR_INTERVAL_MS);
+ } else {
+ mHandler.removeMessages(MSG_SMOOTH_TRICKPLAY_MONITOR);
+ if (!mHandler.hasMessages(MSG_TRICKPLAY_BY_SEEK)) {
mPlayer.setAudioTrack(false);
- mPlayer.setPlayWhenReady(true);
+ mPlayer.setPlayWhenReady(false);
+ // Initiate trickplay
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_TRICKPLAY_BY_SEEK,
+ (int) (mPlayer.getCurrentPosition()
+ + speed * getTrickPlaySeekIntervalMs()), 0));
}
- mHandler.sendMessage(mHandler.obtainMessage(MSG_TRICKPLAY,
- (int) (mPlayer.getCurrentPosition() + rate * getTrickPlaySeekIntervalMs()), 0));
}
}
private EitItem getCurrentProgram() {
- if (mPrograms == null) {
+ if (mPrograms == null || mPrograms.isEmpty()) {
+ return null;
+ }
+ 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 && (mProgram == null
+ || first.getStartTimeUtcMillis() < mProgram.getStartTimeUtcMillis())) {
+ return first;
+ }
return null;
}
long currentTimeMs = getCurrentPosition();
@@ -1431,7 +1545,6 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mChannelBlocked = channelBlocked;
if (mChannelBlocked) {
mHandler.removeCallbacksAndMessages(null);
- mTunerHal.stopTune();
stopPlayback();
resetTvTracks();
if (contentRating != null) {
@@ -1444,12 +1557,27 @@ public class TunerSessionWorker implements PlaybackCacheListener,
mSession.notifyContentAllowed();
mHandler.sendEmptyMessageDelayed(MSG_RESCHEDULE_PROGRAMS,
RESCHEDULE_PROGRAMS_INITIAL_DELAY_MS);
+ mHandler.removeMessages(MSG_CHECK_SIGNAL);
mHandler.sendEmptyMessageDelayed(MSG_CHECK_SIGNAL, CHECK_NO_SIGNAL_INITIAL_DELAY_MS);
}
}
- private boolean hasEnoughBackwardCache() {
- return mPlayer.getCurrentPosition() + CACHE_UNDERFLOW_BUFFER_MS
- >= mCacheStartTimeMs - mRecordStartTimeMs;
+ private boolean hasEnoughBackwardBuffer() {
+ return mPlayer.getCurrentPosition() + BUFFER_UNDERFLOW_BUFFER_MS
+ >= mBufferStartTimeMs - mRecordStartTimeMs;
+ }
+
+ private void notifyVideoUnavailable(final int reason) {
+ mReportedWeakSignal = (reason == TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL);
+ if (mSession != null) {
+ mSession.notifyVideoUnavailable(reason);
+ }
+ }
+
+ private void notifyVideoAvailable() {
+ mReportedWeakSignal = false;
+ if (mSession != null) {
+ mSession.notifyVideoAvailable();
+ }
}
}
diff --git a/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java b/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java
new file mode 100644
index 00000000..e734b779
--- /dev/null
+++ b/src/com/android/tv/tuner/tvinput/TunerStorageCleanUpService.java
@@ -0,0 +1,166 @@
+/*
+ * 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.tvinput;
+
+import android.app.job.JobParameters;
+import android.app.job.JobService;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.Cursor;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.os.AsyncTask;
+
+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;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Creates {@link JobService} to clean up recorded program files which are not referenced
+ * from database.
+ */
+public class TunerStorageCleanUpService extends JobService {
+ private CleanUpStorageTask mTask;
+
+ @Override
+ public void onCreate() {
+ TvApplication.setCurrentRunningProcess(this, false);
+ super.onCreate();
+ mTask = new CleanUpStorageTask(this, this);
+ }
+
+ @Override
+ public boolean onStartJob(JobParameters params) {
+ mTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters params) {
+ return false;
+ }
+
+ /**
+ * Cleans up recorded program files which are not referenced from database.
+ * Cleaning up will be done periodically.
+ */
+ public static class CleanUpStorageTask extends AsyncTask<JobParameters, Void, JobParameters[]> {
+ private final static String[] mProjection = {
+ TvContract.RecordedPrograms.COLUMN_PACKAGE_NAME,
+ TvContract.RecordedPrograms.COLUMN_RECORDING_DATA_URI
+ };
+ private final static long ELAPSED_MILLIS_TO_DELETE = TimeUnit.DAYS.toMillis(1);
+
+ private final Context mContext;
+ private final DvrStorageStatusManager mDvrStorageStatusManager;
+ private final JobService mJobService;
+ private final ContentResolver mContentResolver;
+
+ /**
+ * Creates a recurring storage cleaning task.
+ *
+ * @param context {@link Context}
+ * @param jobService {@link JobService}
+ */
+ public CleanUpStorageTask(Context context, JobService jobService) {
+ mContext = context;
+ mDvrStorageStatusManager =
+ TvApplication.getSingletons(mContext).getDvrStorageStatusManager();
+ mJobService = jobService;
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ private Set<String> getRecordedProgramsDirs() {
+ try (Cursor c = mContentResolver.query(
+ TvContract.RecordedPrograms.CONTENT_URI, mProjection, null, null, null)) {
+ if (c == null) {
+ return null;
+ }
+ Set<String> recordedProgramDirs = new HashSet<>();
+ while (c.moveToNext()) {
+ String packageName = c.getString(0);
+ String dataUriString = c.getString(1);
+ if (dataUriString == null) {
+ continue;
+ }
+ Uri dataUri = Uri.parse(dataUriString);
+ if (!Utils.isInBundledPackageSet(packageName)
+ || dataUri == null || dataUri.getPath() == null
+ || !ContentResolver.SCHEME_FILE.equals(dataUri.getScheme())) {
+ continue;
+ }
+ File recordedProgramDir = new File(dataUri.getPath());
+ try {
+ recordedProgramDirs.add(recordedProgramDir.getCanonicalPath());
+ } catch (IOException | SecurityException e) {
+ }
+ }
+ return recordedProgramDirs;
+ }
+ }
+
+ @Override
+ protected JobParameters[] doInBackground(JobParameters... params) {
+ if (mDvrStorageStatusManager.getDvrStorageStatus()
+ == DvrStorageStatusManager.STORAGE_STATUS_MISSING) {
+ return params;
+ }
+ File dvrRecordingDir = mDvrStorageStatusManager.getRecordingRootDataDirectory();
+ if (dvrRecordingDir == null || !dvrRecordingDir.isDirectory()) {
+ return params;
+ }
+ Set<String> recordedProgramDirs = getRecordedProgramsDirs();
+ if (recordedProgramDirs == null) {
+ return params;
+ }
+ File[] files = dvrRecordingDir.listFiles();
+ if (files == null || files.length == 0) {
+ return params;
+ }
+ for (File recordingDir : files) {
+ try {
+ if (!recordedProgramDirs.contains(recordingDir.getCanonicalPath())) {
+ long lastModified = recordingDir.lastModified();
+ long now = System.currentTimeMillis();
+ 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.
+ Utils.deleteDirOrFile(recordingDir);
+ }
+ }
+ } catch (IOException | SecurityException e) {
+ // would not happen
+ }
+ }
+ return params;
+ }
+
+ @Override
+ protected void onPostExecute(JobParameters[] params) {
+ for (JobParameters param : params) {
+ mJobService.jobFinished(param, false);
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/tuner/tvinput/TunerTvInputService.java b/src/com/android/tv/tuner/tvinput/TunerTvInputService.java
new file mode 100644
index 00000000..684ebdbd
--- /dev/null
+++ b/src/com/android/tv/tuner/tvinput/TunerTvInputService.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.tuner.tvinput;
+
+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.google.android.exoplayer.audio.AudioCapabilities;
+import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
+import com.android.tv.TvApplication;
+import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.tuner.exoplayer.buffer.BufferManager;
+import com.android.tv.tuner.exoplayer.buffer.TrickplayStorageManager;
+import com.android.tv.tuner.util.SystemPropertiesProxy;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.WeakHashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link TunerTvInputService} serves TV channels coming from a tuner device.
+ */
+public class TunerTvInputService extends TvInputService
+ implements AudioCapabilitiesReceiver.Listener{
+ private static final String TAG = "TunerTvInputService";
+ private static final boolean DEBUG = false;
+
+ private static final String MAX_BUFFER_SIZE_KEY = "tv.tuner.buffersize_mbytes";
+ private static final int MAX_BUFFER_SIZE_DEF = 2 * 1024; // 2GB
+ private static final int MIN_BUFFER_SIZE_DEF = 256; // 256MB
+ private static final int DVR_STORAGE_CLEANUP_JOB_ID = 100;
+
+ // WeakContainer for {@link TvInputSessionImpl}
+ private final Set<TunerSession> mTunerSessions = Collections.newSetFromMap(new WeakHashMap<>());
+ private ChannelDataManager mChannelDataManager;
+ private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver;
+ private AudioCapabilities mAudioCapabilities;
+ private BufferManager mBufferManager;
+
+ @Override
+ public void onCreate() {
+ TvApplication.setCurrentRunningProcess(this, false);
+ super.onCreate();
+ if (DEBUG) Log.d(TAG, "onCreate");
+ mChannelDataManager = new ChannelDataManager(getApplicationContext());
+ mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getApplicationContext(), this);
+ mAudioCapabilitiesReceiver.register();
+ mBufferManager = createBufferManager();
+ if (CommonFeatures.DVR.isEnabled(this)) {
+ JobScheduler jobScheduler =
+ (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ JobInfo pendingJob = jobScheduler.getPendingJob(DVR_STORAGE_CLEANUP_JOB_ID);
+ if (pendingJob != null) {
+ // storage cleaning job is already scheduled.
+ } else {
+ JobInfo job = new JobInfo.Builder(DVR_STORAGE_CLEANUP_JOB_ID,
+ new ComponentName(this, TunerStorageCleanUpService.class))
+ .setPersisted(true).setPeriodic(TimeUnit.DAYS.toMillis(1)).build();
+ jobScheduler.schedule(job);
+ }
+ }
+ if (mBufferManager == null) {
+ Log.i(TAG, "Trickplay is disabled");
+ } else {
+ Log.i(TAG, "Trickplay is enabled");
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ if (DEBUG) Log.d(TAG, "onDestroy");
+ super.onDestroy();
+ mChannelDataManager.release();
+ mAudioCapabilitiesReceiver.unregister();
+ if (mBufferManager != null) {
+ mBufferManager.close();
+ }
+ }
+
+ @Override
+ public RecordingSession onCreateRecordingSession(String inputId) {
+ return new TunerRecordingSession(this, inputId, mChannelDataManager);
+ }
+
+ @Override
+ public Session onCreateSession(String inputId) {
+ if (DEBUG) Log.d(TAG, "onCreateSession");
+ try {
+ final TunerSession session = new TunerSession(
+ this, mChannelDataManager, mBufferManager);
+ mTunerSessions.add(session);
+ session.setAudioCapabilities(mAudioCapabilities);
+ session.setOverlayViewEnabled(true);
+ return session;
+ } catch (RuntimeException e) {
+ // There are no available DVB devices.
+ Log.e(TAG, "Creating a session for " + inputId + " failed.", e);
+ return null;
+ }
+ }
+
+ @Override
+ public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
+ mAudioCapabilities = audioCapabilities;
+ for (TunerSession session : mTunerSessions) {
+ if (!session.isReleased()) {
+ session.setAudioCapabilities(audioCapabilities);
+ }
+ }
+ }
+
+ private BufferManager createBufferManager() {
+ int maxBufferSizeMb =
+ SystemPropertiesProxy.getInt(MAX_BUFFER_SIZE_KEY, MAX_BUFFER_SIZE_DEF);
+ if (maxBufferSizeMb >= MIN_BUFFER_SIZE_DEF) {
+ return new BufferManager(
+ new TrickplayStorageManager(getApplicationContext(), getCacheDir(),
+ 1024L * 1024 * maxBufferSizeMb));
+ }
+ return null;
+ }
+
+ public static String getInputId(Context context) {
+ return TvContract.buildInputId(new ComponentName(context, TunerTvInputService.class));
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/util/ByteArrayBuffer.java b/src/com/android/tv/tuner/util/ByteArrayBuffer.java
index ace257cd..da887e7d 100644
--- a/usbtuner/src/com/android/usbtuner/util/ByteArrayBuffer.java
+++ b/src/com/android/tv/tuner/util/ByteArrayBuffer.java
@@ -29,7 +29,7 @@
*
*/
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
/**
* An expandable byte buffer built on byte array.
diff --git a/usbtuner/src/com/android/usbtuner/util/ConvertUtils.java b/src/com/android/tv/tuner/util/ConvertUtils.java
index 76a5fe66..abf18d8c 100644
--- a/usbtuner/src/com/android/usbtuner/util/ConvertUtils.java
+++ b/src/com/android/tv/tuner/util/ConvertUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
/**
* Utility class for converting date and time.
diff --git a/src/com/android/tv/tuner/util/GlobalSettingsUtils.java b/src/com/android/tv/tuner/util/GlobalSettingsUtils.java
new file mode 100644
index 00000000..0cefcbed
--- /dev/null
+++ b/src/com/android/tv/tuner/util/GlobalSettingsUtils.java
@@ -0,0 +1,36 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.provider.Settings;
+
+/**
+ * Utility class that get information of global settings.
+ */
+public class GlobalSettingsUtils {
+ // Since global surround setting is hided, add the related variable here for checking surround
+ // sound setting when the audio is unavailable. Remove this workaround after b/31254857 fixed.
+ private static final String ENCODED_SURROUND_OUTPUT = "encoded_surround_output";
+ public static final int ENCODED_SURROUND_OUTPUT_NEVER = 1;
+
+ private GlobalSettingsUtils () { }
+
+ public static int getEncodedSurroundOutputSettings(Context context) {
+ return Settings.Global.getInt(context.getContentResolver(), ENCODED_SURROUND_OUTPUT, 0);
+ }
+}
diff --git a/usbtuner/src/com/android/usbtuner/util/Ints.java b/src/com/android/tv/tuner/util/Ints.java
index 9a3e719d..0b1be426 100644
--- a/usbtuner/src/com/android/usbtuner/util/Ints.java
+++ b/src/com/android/tv/tuner/util/Ints.java
@@ -1,4 +1,4 @@
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
import java.util.ArrayList;
import java.util.List;
diff --git a/usbtuner/src/com/android/usbtuner/util/StatusTextUtils.java b/src/com/android/tv/tuner/util/StatusTextUtils.java
index 9c7506a3..2633834b 100644
--- a/usbtuner/src/com/android/usbtuner/util/StatusTextUtils.java
+++ b/src/com/android/tv/tuner/util/StatusTextUtils.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
+
+import java.util.Locale;
/**
* Utility class for tuner status messages.
@@ -33,6 +35,8 @@ public class StatusTextUtils {
/**
* Returns tuner status warning message in HTML.
+ *
+ * <p>This is only called for debuging and always shown in english.</p>
*/
public static String getStatusWarningInHTML(long packetsPerSec,
int videoFrameDrop, int bytesInQueue,
@@ -51,17 +55,15 @@ public class StatusTextUtils {
} else {
audioPositionColor = COLOR_GRAY;
}
- buffer.append(String.format("<font color=%s>", audioPositionColor));
+ buffer.append(String.format(Locale.US, "<font color=%s>", audioPositionColor));
buffer.append(
- String.format("audioPositionMs: %d (%d)<br>", audioPositionUs / 1000,
+ String.format(Locale.US, "audioPositionMs: %d (%d)<br>", audioPositionUs / 1000,
audioPositionMsRate));
buffer.append("</font>\n");
buffer.append("<font color=" + COLOR_GRAY + ">");
- buffer.append(
- String.format("audioPtsMs: %d (%d, %d)<br>", audioPtsUs / 1000,
+ buffer.append(String.format(Locale.US, "audioPtsMs: %d (%d, %d)<br>", audioPtsUs / 1000,
audioPtsUsRate / 1000, (audioPtsUs - audioPositionUs) / 1000));
- buffer.append(
- String.format("videoPtsMs: %d (%d, %d)<br>", videoPtsUs / 1000,
+ buffer.append(String.format(Locale.US, "videoPtsMs: %d (%d, %d)<br>", videoPtsUs / 1000,
videoPtsUsRate / 1000, (videoPtsUs - audioPositionUs) / 1000));
buffer.append("</font>\n");
diff --git a/usbtuner/src/com/android/usbtuner/util/StringUtils.java b/src/com/android/tv/tuner/util/StringUtils.java
index 7c24d816..15571e75 100644
--- a/usbtuner/src/com/android/usbtuner/util/StringUtils.java
+++ b/src/com/android/tv/tuner/util/StringUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
/**
* Utility class for handling {@link String}.
diff --git a/usbtuner/src/com/android/usbtuner/util/SystemPropertiesProxy.java b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
index b3ff0abb..62a64361 100644
--- a/usbtuner/src/com/android/usbtuner/util/SystemPropertiesProxy.java
+++ b/src/com/android/tv/tuner/util/SystemPropertiesProxy.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
import android.util.Log;
diff --git a/usbtuner/src/com/android/usbtuner/util/TisConfiguration.java b/src/com/android/tv/tuner/util/TisConfiguration.java
index 1e6b0d8a..ca861d67 100644
--- a/usbtuner/src/com/android/usbtuner/util/TisConfiguration.java
+++ b/src/com/android/tv/tuner/util/TisConfiguration.java
@@ -1,4 +1,4 @@
-package com.android.usbtuner.util;
+package com.android.tv.tuner.util;
import android.content.Context;
diff --git a/src/com/android/tv/tuner/util/TunerInputInfoUtils.java b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
new file mode 100644
index 00000000..5c411f64
--- /dev/null
+++ b/src/com/android/tv/tuner/util/TunerInputInfoUtils.java
@@ -0,0 +1,100 @@
+/*
+ * 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.util;
+
+import android.annotation.TargetApi;
+import android.content.ComponentName;
+import android.content.Context;
+import android.media.tv.TvInputInfo;
+import android.media.tv.TvInputManager;
+import android.os.Build;
+import android.support.annotation.Nullable;
+import android.support.v4.os.BuildCompat;
+import android.util.Log;
+
+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 {
+ private static final String TAG = "TunerInputInfoUtils";
+ private static final boolean DEBUG = false;
+
+ /**
+ * Builds tuner input's info.
+ */
+ @Nullable
+ @TargetApi(Build.VERSION_CODES.N)
+ public static TvInputInfo buildTunerInputInfo(Context context, boolean fromBuiltInTuner) {
+ int numOfDevices = TunerHal.getTunerCount(context);
+ if (numOfDevices == 0) {
+ return null;
+ }
+ TvInputInfo.Builder builder = new TvInputInfo.Builder(context, new ComponentName(context,
+ TunerTvInputService.class));
+ if (fromBuiltInTuner) {
+ builder.setLabel(R.string.bt_app_name);
+ } else {
+ builder.setLabel(R.string.ut_app_name);
+ }
+ try {
+ return builder.setCanRecord(CommonFeatures.DVR.isEnabled(context))
+ .setTunerCount(numOfDevices)
+ .build();
+ } catch (NullPointerException e) {
+ // TunerTvInputService is not enabled.
+ return null;
+ }
+ }
+
+ /**
+ * Updates tuner input's info.
+ *
+ * @param context {@link Context} instance
+ */
+ public static void updateTunerInputInfo(Context context) {
+ if (BuildCompat.isAtLeastN()) {
+ if (DEBUG) Log.d(TAG, "updateTunerInputInfo()");
+ TvInputInfo info = buildTunerInputInfo(context, isBuiltInTuner(context));
+ if (info != null) {
+ ((TvInputManager) context.getSystemService(Context.TV_INPUT_SERVICE))
+ .updateTvInputInfo(info);
+ if (DEBUG) {
+ Log.d(TAG, "TvInputInfo [" + info.loadLabel(context)
+ + "] updated: " + info.toString());
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "Updating tuner input's info failed. Input is not ready yet.");
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns if the current tuner service is for a built-in tuner.
+ *
+ * @param context {@link Context} instance
+ */
+ public static boolean isBuiltInTuner(Context context) {
+ return TunerHal.getTunerType(context) == TunerHal.TUNER_TYPE_BUILT_IN;
+ }
+}
diff --git a/src/com/android/tv/ui/AppLayerTvView.java b/src/com/android/tv/ui/AppLayerTvView.java
index c7b94a15..09acb36b 100644
--- a/src/com/android/tv/ui/AppLayerTvView.java
+++ b/src/com/android/tv/ui/AppLayerTvView.java
@@ -19,6 +19,10 @@ package com.android.tv.ui;
import android.content.Context;
import android.media.tv.TvView;
import android.util.AttributeSet;
+import android.view.SurfaceView;
+import android.view.View;
+
+import com.android.tv.experiments.Experiments;
/**
* A TvView class for application layer when multiple windows are being used in the app.
@@ -46,4 +50,13 @@ public class AppLayerTvView extends TvView {
public boolean hasWindowFocus() {
return true;
}
+
+ @Override
+ public void onViewAdded(View child) {
+ if (child instanceof SurfaceView) {
+ // Note: See b/29118070 for detail.
+ ((SurfaceView) child).setSecure(!Experiments.ENABLE_DEVELOPER_FEATURES.get());
+ }
+ super.onViewAdded(child);
+ }
}
diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java
index a36ba83c..3cf4de83 100644
--- a/src/com/android/tv/ui/ChannelBannerView.java
+++ b/src/com/android/tv/ui/ChannelBannerView.java
@@ -25,6 +25,7 @@ import android.content.Context;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
+import android.media.tv.TvContentRating;
import android.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.net.Uri;
@@ -50,10 +51,14 @@ import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.TvApplication;
+import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.StreamInfo;
+import com.android.tv.dvr.DvrManager;
+import com.android.tv.dvr.ScheduledRecording;
+import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.util.ImageCache;
import com.android.tv.util.ImageLoader;
import com.android.tv.util.ImageLoader.ImageLoaderCallback;
@@ -89,6 +94,8 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
*/
public static final int LOCK_CHANNEL_INFO = 2;
+ private static final int DISPLAYED_CONTENT_RATINGS_COUNT = 3;
+
private static final String EMPTY_STRING = "";
private static Program sNoProgram;
@@ -106,17 +113,21 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
private TextView mChannelNameTextView;
private TextView mProgramTimeTextView;
private ProgressBar mRemainingTimeView;
+ private TextView mRecordingIndicatorView;
private TextView mClosedCaptionTextView;
private TextView mAspectRatioTextView;
private TextView mResolutionTextView;
private TextView mAudioChannelTextView;
+ private TextView[] mContentRatingsTextViews = new TextView[DISPLAYED_CONTENT_RATINGS_COUNT];
private TextView mProgramDescriptionTextView;
private String mProgramDescriptionText;
private View mAnchorView;
private Channel mCurrentChannel;
private Program mLastUpdatedProgram;
- private RecordedProgram mLastUpdatedRecordedProgram;
private final Handler mHandler = new Handler();
+ private final DvrManager mDvrManager;
+ private ContentRatingsManager mContentRatingsManager;
+ private TvContentRating mBlockingContentRating;
private int mLockType;
@@ -147,6 +158,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
private final int mChannelBannerTextColor;
private final int mChannelBannerDimTextColor;
private final int mResizeAnimDuration;
+ private final int mRecordingIconPadding;
private final Interpolator mResizeInterpolator;
private final AnimatorListenerAdapter mResizeAnimatorListener = new AnimatorListenerAdapter() {
@@ -208,10 +220,12 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
R.dimen.channel_banner_channel_logo_margin_start);
mProgramDescriptionTextViewWidth = mResources.getDimensionPixelSize(
R.dimen.channel_banner_program_description_width);
- mChannelBannerTextColor = Utils.getColor(mResources, R.color.channel_banner_text_color);
- mChannelBannerDimTextColor = Utils.getColor(mResources,
- R.color.channel_banner_dim_text_color);
+ mChannelBannerTextColor = mResources.getColor(R.color.channel_banner_text_color, null);
+ mChannelBannerDimTextColor = mResources.getColor(R.color.channel_banner_dim_text_color,
+ null);
mResizeAnimDuration = mResources.getInteger(R.integer.channel_banner_fast_anim_duration);
+ mRecordingIconPadding = mResources.getDimensionPixelOffset(
+ R.dimen.channel_banner_recording_icon_padding);
mResizeInterpolator = AnimationUtils.loadInterpolator(context,
android.R.interpolator.linear_out_slow_in);
@@ -221,6 +235,14 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
mProgramDescriptionFadeOutAnimator = AnimatorInflater.loadAnimator(mMainActivity,
R.animator.channel_banner_program_description_fade_out);
+ if (CommonFeatures.DVR.isEnabled(mMainActivity)) {
+ mDvrManager = TvApplication.getSingletons(mMainActivity).getDvrManager();
+ } else {
+ mDvrManager = null;
+ }
+ mContentRatingsManager = TvApplication.getSingletons(getContext())
+ .getTvInputManagerHelper().getContentRatingsManager();
+
if (sNoProgram == null) {
sNoProgram = new Program.Builder()
.setTitle(context.getString(R.string.channel_banner_no_title))
@@ -266,10 +288,14 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
mChannelNameTextView = (TextView) findViewById(R.id.channel_name);
mProgramTimeTextView = (TextView) findViewById(R.id.program_time_text);
mRemainingTimeView = (ProgressBar) findViewById(R.id.remaining_time);
+ mRecordingIndicatorView = (TextView) findViewById(R.id.recording_indicator);
mClosedCaptionTextView = (TextView) findViewById(R.id.closed_caption);
mAspectRatioTextView = (TextView) findViewById(R.id.aspect_ratio);
mResolutionTextView = (TextView) findViewById(R.id.resolution);
mAudioChannelTextView = (TextView) findViewById(R.id.audio_channel);
+ mContentRatingsTextViews[0] = (TextView) findViewById(R.id.content_ratings_0);
+ mContentRatingsTextViews[1] = (TextView) findViewById(R.id.content_ratings_1);
+ mContentRatingsTextViews[2] = (TextView) findViewById(R.id.content_ratings_2);
mProgramDescriptionTextView = (TextView) findViewById(R.id.program_description);
mAnchorView = findViewById(R.id.anchor);
@@ -335,6 +361,15 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
}
/**
+ * Sets the content rating that blocks the current watched channel for displaying it in the
+ * channel banner.
+ */
+ public void setBlockingContentRating(TvContentRating rating) {
+ mBlockingContentRating = rating;
+ updateProgramRatings(mMainActivity.getCurrentProgram());
+ }
+
+ /**
* Update channel banner view.
*
* @param info A StreamInfo that includes stream information.
@@ -343,8 +378,11 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
public void updateViews(StreamInfo info) {
resetAnimationEffects();
Channel channel = mMainActivity.getCurrentChannel();
- if (!Objects.equals(mCurrentChannel, channel) && isShown()) {
- scheduleHide();
+ if (!Objects.equals(mCurrentChannel, channel)) {
+ mBlockingContentRating = null;
+ if (isShown()) {
+ scheduleHide();
+ }
}
mCurrentChannel = channel;
mChannelView.setVisibility(VISIBLE);
@@ -355,11 +393,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
: null);
updateChannelInfo();
}
- if (mMainActivity.isRecordingPlayback()) {
- updateProgramInfo(mMainActivity.getPlayingRecordedProgram());
- } else {
- updateProgramInfo(mMainActivity.getCurrentProgram());
- }
+ updateProgramInfo(mMainActivity.getCurrentProgram());
}
private void updateStreamInfo(StreamInfo info) {
@@ -380,6 +414,9 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
mAspectRatioTextView.setVisibility(View.GONE);
mResolutionTextView.setVisibility(View.GONE);
mAudioChannelTextView.setVisibility(View.GONE);
+ for (int i = 0; i < DISPLAYED_CONTENT_RATINGS_COUNT; i++) {
+ mContentRatingsTextViews[i].setVisibility(View.GONE);
+ }
}
}
@@ -439,15 +476,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
private String getCurrentInputId() {
Channel channel = mMainActivity.getCurrentChannel();
- if (channel != null) {
- return channel.getInputId();
- } else if (mMainActivity.isRecordingPlayback()) {
- RecordedProgram recordedProgram = mMainActivity.getPlayingRecordedProgram();
- if (recordedProgram != null) {
- return recordedProgram.getInputId();
- }
- }
- return null;
+ return channel != null ? channel.getInputId() : null;
}
private void updateTvInputLogo(Bitmap bitmap) {
@@ -531,7 +560,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
private void updateProgramInfo(Program program) {
if (mLockType == LOCK_CHANNEL_INFO) {
program = sLockedChannelProgram;
- } else if (!Program.isValid(program) || TextUtils.isEmpty(program.getTitle())) {
+ } else if (program == null || !program.isValid() || TextUtils.isEmpty(program.getTitle())) {
program = sNoProgram;
}
@@ -542,10 +571,12 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
updateProgramTextView(program);
}
updateProgramTimeInfo(program);
+ updateRecordingStatus(program);
+ updateProgramRatings(program);
// When the program is changed, but the previous resize animation has not ended yet,
// cancel the animation.
- boolean isProgramChanged = !Objects.equals(mLastUpdatedProgram, program);
+ boolean isProgramChanged = !program.equals(mLastUpdatedProgram);
if (mResizeAnimator != null && isProgramChanged) {
setLastUpdatedProgram(program);
mProgramInfoUpdatePendingByResizing = true;
@@ -568,67 +599,15 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
setLastUpdatedProgram(program);
}
- private void updateProgramInfo(RecordedProgram recordedProgram) {
- if (mLockType == LOCK_CHANNEL_INFO) {
- updateProgramInfo(sLockedChannelProgram);
- return;
- } else if (recordedProgram == null) {
- updateProgramInfo(sNoProgram);
- return;
- }
-
- if (mLastUpdatedRecordedProgram == null
- || !TextUtils.equals(recordedProgram.getTitle(),
- mLastUpdatedRecordedProgram.getTitle())
- || !TextUtils.equals(recordedProgram.getEpisodeDisplayTitle(getContext()),
- mLastUpdatedRecordedProgram.getEpisodeDisplayTitle(getContext()))) {
- updateProgramTextView(recordedProgram);
- }
- updateProgramTimeInfo(recordedProgram);
-
- // When the program is changed, but the previous resize animation has not ended yet,
- // cancel the animation.
- boolean isProgramChanged = !Objects.equals(mLastUpdatedRecordedProgram, recordedProgram);
- if (mResizeAnimator != null && isProgramChanged) {
- setLastUpdatedRecordedProgram(recordedProgram);
- mProgramInfoUpdatePendingByResizing = true;
- mResizeAnimator.cancel();
- } else if (mResizeAnimator == null) {
- if (mLockType != LOCK_NONE
- || TextUtils.isEmpty(recordedProgram.getShortDescription())) {
- mProgramDescriptionTextView.setVisibility(GONE);
- mProgramDescriptionText = "";
- } else {
- mProgramDescriptionTextView.setVisibility(VISIBLE);
- mProgramDescriptionText = recordedProgram.getShortDescription();
- }
- String description = mProgramDescriptionTextView.getText().toString();
- boolean needFadeAnimation = isProgramChanged
- || !description.equals(mProgramDescriptionText);
- updateBannerHeight(needFadeAnimation);
- } else {
- mProgramInfoUpdatePendingByResizing = true;
- }
- setLastUpdatedRecordedProgram(recordedProgram);
- }
-
private void updateProgramTextView(Program program) {
if (program == null) {
return;
}
updateProgramTextView(program == sLockedChannelProgram, program.getTitle(),
- program.getEpisodeTitle(), program.getEpisodeDisplayTitle(getContext()));
- }
-
- private void updateProgramTextView(RecordedProgram recordedProgram) {
- if (recordedProgram == null) {
- return;
- }
- updateProgramTextView(false, recordedProgram.getTitle(), recordedProgram.getEpisodeTitle(),
- recordedProgram.getEpisodeDisplayTitle(getContext()));
+ program.getEpisodeDisplayTitle(getContext()));
}
- private void updateProgramTextView(boolean dimText, String title, String episodeTitle,
+ private void updateProgramTextView(boolean dimText, String title,
String episodeDisplayTitle) {
mProgramTextView.setVisibility(View.VISIBLE);
if (dimText) {
@@ -639,7 +618,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
updateTextView(mProgramTextView,
R.dimen.channel_banner_program_large_text_size,
R.dimen.channel_banner_program_large_margin_top);
- if (TextUtils.isEmpty(episodeTitle)) {
+ if (TextUtils.isEmpty(episodeDisplayTitle)) {
mProgramTextView.setText(title);
} else {
String fullTitle = title + " " + episodeDisplayTitle;
@@ -675,61 +654,119 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
: R.dimen.channel_banner_anchor_two_line_y);
}
+ private void updateProgramRatings(Program program) {
+ if (mBlockingContentRating != null) {
+ mContentRatingsTextViews[0].setText(
+ mContentRatingsManager.getDisplayNameForRating(mBlockingContentRating));
+ mContentRatingsTextViews[0].setVisibility(View.VISIBLE);
+ for (int i = 1; i < DISPLAYED_CONTENT_RATINGS_COUNT; i++) {
+ mContentRatingsTextViews[i].setVisibility(View.GONE);
+ }
+ return;
+ }
+ TvContentRating[] ratings = (program == null) ? null : program.getContentRatings();
+ for (int i = 0; i < DISPLAYED_CONTENT_RATINGS_COUNT; i++) {
+ if (ratings == null || ratings.length <= i) {
+ mContentRatingsTextViews[i].setVisibility(View.GONE);
+ } else {
+ mContentRatingsTextViews[i].setText(
+ mContentRatingsManager.getDisplayNameForRating(ratings[i]));
+ mContentRatingsTextViews[i].setVisibility(View.VISIBLE);
+ }
+ }
+ }
+
private void updateProgramTimeInfo(Program program) {
- long startTime = program.getStartTimeUtcMillis();
- long endTime = program.getEndTimeUtcMillis();
- if (mLockType != LOCK_CHANNEL_INFO && startTime > 0 && endTime > startTime) {
+ long durationMs = program.getDurationMillis();
+ long startTimeMs = program.getStartTimeUtcMillis();
+ long endTimeMs = program.getEndTimeUtcMillis();
+
+ if (mLockType != LOCK_CHANNEL_INFO && durationMs > 0 && startTimeMs > 0) {
mProgramTimeTextView.setVisibility(View.VISIBLE);
mRemainingTimeView.setVisibility(View.VISIBLE);
-
mProgramTimeTextView.setText(Utils.getDurationString(
- getContext(), startTime, endTime, true));
-
- long currTime = mMainActivity.getCurrentPlayingPosition();
- if (currTime <= startTime) {
- mRemainingTimeView.setProgress(0);
- } else if (currTime >= endTime) {
- mRemainingTimeView.setProgress(100);
- } else {
- mRemainingTimeView.setProgress(
- (int) (100 * (currTime - startTime) / (endTime - startTime)));
- }
+ getContext(), startTimeMs, endTimeMs, true));
} else {
mProgramTimeTextView.setVisibility(View.GONE);
mRemainingTimeView.setVisibility(View.GONE);
}
}
- private void updateProgramTimeInfo(RecordedProgram recordedProgram) {
- long durationMs = recordedProgram.getDurationMillis();
- if (mLockType != LOCK_CHANNEL_INFO && durationMs > 0) {
- mProgramTimeTextView.setVisibility(View.VISIBLE);
- mRemainingTimeView.setVisibility(View.VISIBLE);
+ private int getProgressPercent(long currTime, long startTime, long endTime) {
+ if (currTime <= startTime) {
+ return 0;
+ } else if (currTime >= endTime) {
+ return 100;
+ } else {
+ return (int) (100 * (currTime - startTime) / (endTime - startTime));
+ }
+ }
- mProgramTimeTextView.setText(DateUtils.formatElapsedTime(durationMs / 1000));
+ private void updateRecordingStatus(Program program) {
+ if (mDvrManager == null) {
+ updateProgressBarAndRecIcon(program, null);
+ return;
+ }
+ ScheduledRecording currentRecording = (mCurrentChannel == null) ? null
+ : mDvrManager.getCurrentRecording(mCurrentChannel.getId());
+ if (DEBUG) {
+ Log.d(TAG, currentRecording == null ? "No Recording" : "Recording:" + currentRecording);
+ }
+ if (currentRecording != null && isCurrentProgram(currentRecording, program)) {
+ updateProgressBarAndRecIcon(program, currentRecording);
+ } else {
+ updateProgressBarAndRecIcon(program, null);
+ }
+ }
+
+ private void updateProgressBarAndRecIcon(Program program,
+ @Nullable ScheduledRecording recording) {
+ long programStartTime = program.getStartTimeUtcMillis();
+ long programEndTime = program.getEndTimeUtcMillis();
+ long currentPosition = mMainActivity.getCurrentPlayingPosition();
+ updateRecordingIndicator(recording);
+ if (recording != null) {
+ // Recording now. Use recording-style progress bar.
+ mRemainingTimeView.setProgress(getProgressPercent(recording.getStartTimeMs(),
+ programStartTime, programEndTime));
+ mRemainingTimeView.setSecondaryProgress(getProgressPercent(currentPosition,
+ programStartTime, programEndTime));
+ } else {
+ // No recording is going now. Recover progress bar.
+ mRemainingTimeView.setProgress(getProgressPercent(currentPosition,
+ programStartTime, programEndTime));
+ mRemainingTimeView.setSecondaryProgress(0);
+ }
+ }
- long currTimeMs = mMainActivity.getCurrentPlayingPosition();
- if (currTimeMs <= 0) {
- mRemainingTimeView.setProgress(0);
- } else if (currTimeMs >= durationMs) {
- mRemainingTimeView.setProgress(100);
+ private void updateRecordingIndicator(@Nullable ScheduledRecording recording) {
+ if (recording != null) {
+ if (mRemainingTimeView.getVisibility() == View.GONE) {
+ mRecordingIndicatorView.setText(mMainActivity.getResources().getString(
+ R.string.dvr_recording_till_format, DateUtils.formatDateTime(mMainActivity,
+ recording.getEndTimeMs(), DateUtils.FORMAT_SHOW_TIME)));
+ mRecordingIndicatorView.setCompoundDrawablePadding(mRecordingIconPadding);
} else {
- mRemainingTimeView.setProgress((int) (100 * currTimeMs / durationMs));
+ mRecordingIndicatorView.setText("");
+ mRecordingIndicatorView.setCompoundDrawablePadding(0);
}
+ mRecordingIndicatorView.setVisibility(View.VISIBLE);
} else {
- mProgramTimeTextView.setVisibility(View.GONE);
- mRemainingTimeView.setVisibility(View.GONE);
+ mRecordingIndicatorView.setVisibility(View.GONE);
}
}
- private void setLastUpdatedProgram(Program program) {
- mLastUpdatedProgram = program;
- mLastUpdatedRecordedProgram = null;
+ private boolean isCurrentProgram(ScheduledRecording recording, Program program) {
+ long currentPosition = mMainActivity.getCurrentPlayingPosition();
+ return (recording.getType() == ScheduledRecording.TYPE_PROGRAM
+ && recording.getProgramId() == program.getId())
+ || (recording.getType() == ScheduledRecording.TYPE_TIMED
+ && currentPosition >= recording.getStartTimeMs()
+ && currentPosition <= recording.getEndTimeMs());
}
- private void setLastUpdatedRecordedProgram(RecordedProgram recordedProgram) {
- mLastUpdatedProgram = null;
- mLastUpdatedRecordedProgram = recordedProgram;
+ private void setLastUpdatedProgram(Program program) {
+ mLastUpdatedProgram = program;
}
private void updateBannerHeight(boolean needFadeAnimation) {
@@ -788,4 +825,4 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
animator.addListener(mResizeAnimatorListener);
return animator;
}
-}
+} \ No newline at end of file
diff --git a/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java
new file mode 100644
index 00000000..39ec1279
--- /dev/null
+++ b/src/com/android/tv/ui/GuidedActionsStylistWithDivider.java
@@ -0,0 +1,65 @@
+/*
+ * 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.ui;
+
+import android.content.Context;
+import android.support.v17.leanback.app.GuidedStepFragment;
+import android.support.v17.leanback.widget.GuidedAction;
+import android.support.v17.leanback.widget.GuidedActionsStylist;
+
+import com.android.tv.R;
+
+/**
+ * Extended stylist class used for {@link GuidedStepFragment} with divider support.
+ */
+public class GuidedActionsStylistWithDivider extends GuidedActionsStylist {
+ /**
+ * ID used mark a divider.
+ */
+ public static final int ACTION_DIVIDER = -100;
+ private static final int VIEW_TYPE_DIVIDER = 1;
+
+ @Override
+ public int getItemViewType(GuidedAction action) {
+ if (action.getId() == ACTION_DIVIDER) {
+ return VIEW_TYPE_DIVIDER;
+ }
+ return super.getItemViewType(action);
+ }
+
+ @Override
+ public int onProvideItemLayoutId(int viewType) {
+ if (viewType == VIEW_TYPE_DIVIDER) {
+ return R.layout.guided_action_divider;
+ }
+ return super.onProvideItemLayoutId(viewType);
+ }
+
+ /**
+ * Creates a divider for {@link GuidedStepFragment}, targeted fragments must use
+ * {@link GuidedActionsStylistWithDivider} as its actions' stylist for divider to work.
+ */
+ public static GuidedAction createDividerAction(Context context) {
+ return new GuidedAction.Builder(context)
+ .id(ACTION_DIVIDER)
+ .title(null)
+ .description(null)
+ .focusable(false)
+ .infoOnly(true)
+ .build();
+ }
+}
diff --git a/src/com/android/tv/ui/OverlayRootView.java b/src/com/android/tv/ui/OverlayRootView.java
deleted file mode 100644
index f6dc2537..00000000
--- a/src/com/android/tv/ui/OverlayRootView.java
+++ /dev/null
@@ -1,51 +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.ui;
-
-import android.content.Context;
-import android.util.AttributeSet;
-import android.view.KeyEvent;
-import android.widget.FrameLayout;
-
-import com.android.tv.MainActivity;
-
-public class OverlayRootView extends FrameLayout {
-
- private final MainActivity mMainActivity;
-
- public OverlayRootView(Context context) {
- this(context, null, 0, 0);
- }
-
- public OverlayRootView(Context context, AttributeSet attrs) {
- this(context, attrs, 0, 0);
- }
-
- public OverlayRootView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public OverlayRootView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- mMainActivity = (MainActivity) context;
- }
-
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- return mMainActivity.dispatchKeyEvent(event) || super.dispatchKeyEvent(event);
- }
-}
diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java
index 646f9159..5e25ae43 100644
--- a/src/com/android/tv/ui/SelectInputView.java
+++ b/src/com/android/tv/ui/SelectInputView.java
@@ -34,14 +34,13 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
-import com.android.tv.R;
import com.android.tv.ApplicationSingletons;
+import com.android.tv.R;
import com.android.tv.TvApplication;
import com.android.tv.analytics.DurationTimer;
import com.android.tv.analytics.Tracker;
import com.android.tv.data.Channel;
import com.android.tv.util.TvInputManagerHelper;
-import com.android.tv.util.Utils;
import java.util.ArrayList;
import java.util.Collections;
@@ -156,9 +155,9 @@ public class SelectInputView extends VerticalGridView implements
mShowDurationMillis = resources.getInteger(R.integer.select_input_show_duration);
mRippleAnimDurationMillis = resources.getInteger(
R.integer.select_input_ripple_anim_duration);
- mTextColorPrimary = Utils.getColor(resources, R.color.select_input_text_color_primary);
- mTextColorSecondary = Utils.getColor(resources, R.color.select_input_text_color_secondary);
- mTextColorDisabled = Utils.getColor(resources, R.color.select_input_text_color_disabled);
+ mTextColorPrimary = resources.getColor(R.color.select_input_text_color_primary, null);
+ mTextColorSecondary = resources.getColor(R.color.select_input_text_color_secondary, null);
+ mTextColorDisabled = resources.getColor(R.color.select_input_text_color_disabled, null);
mItemViewForMeasure = LayoutInflater.from(context).inflate(
R.layout.select_input_item, this, false);
diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java
index 6d3d62aa..cbe459fb 100644
--- a/src/com/android/tv/ui/TunableTvView.java
+++ b/src/com/android/tv/ui/TunableTvView.java
@@ -20,8 +20,6 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
-import android.content.ContentUris;
import android.content.Context;
import android.content.pm.PackageManager;
import android.media.PlaybackParams;
@@ -35,13 +33,14 @@ import android.media.tv.TvView.TvInputCallback;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.os.Bundle;
import android.support.annotation.IntDef;
+import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
import android.support.v4.os.BuildCompat;
import android.text.TextUtils;
+import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
@@ -53,17 +52,16 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import com.android.tv.ApplicationSingletons;
+import com.android.tv.InputSessionManager;
+import com.android.tv.InputSessionManager.TvViewSession;
import com.android.tv.R;
import com.android.tv.TvApplication;
import com.android.tv.analytics.DurationTimer;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.common.recording.RecordedProgram;
import com.android.tv.data.Channel;
-import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.StreamInfo;
import com.android.tv.data.WatchedHistoryManager;
-import com.android.tv.dvr.DvrDataManager;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.recommendation.NotificationService;
import com.android.tv.util.NetworkUtils;
@@ -73,8 +71,6 @@ import com.android.tv.util.Utils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.List;
public class TunableTvView extends FrameLayout implements StreamInfo {
@@ -82,6 +78,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
private static final String TAG = "TunableTvView";
public static final int VIDEO_UNAVAILABLE_REASON_NOT_TUNED = -1;
+ public static final int VIDEO_UNAVAILABLE_REASON_NO_RESOURCE = -2;
@Retention(RetentionPolicy.SOURCE)
@IntDef({BLOCK_SCREEN_TYPE_NO_UI, BLOCK_SCREEN_TYPE_SHRUNKEN_TV_VIEW, BLOCK_SCREEN_TYPE_NORMAL})
@@ -108,14 +105,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
private static final int FADING_IN = 2;
private static final int FADING_OUT = 3;
- private static final long INVALID_TIME = -1;
-
// It is too small to see the description text without PIP_BLOCK_SCREEN_SCALE_FACTOR.
private static final float PIP_BLOCK_SCREEN_SCALE_FACTOR = 1.2f;
private AppLayerTvView mTvView;
+ private TvViewSession mTvViewSession;
private Channel mCurrentChannel;
- private RecordedProgram mRecordedProgram;
private TvInputManagerHelper mInputManagerHelper;
private ContentRatingsManager mContentRatingsManager;
@Nullable
@@ -149,7 +144,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
@TimeShiftState private int mTimeShiftState = TIME_SHIFT_STATE_NONE;
private TimeShiftListener mTimeShiftListener;
private boolean mTimeShiftAvailable;
- private long mTimeShiftCurrentPositionMs = INVALID_TIME;
+ private long mTimeShiftCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
private final Tracker mTracker;
private final DurationTimer mChannelViewTimer = new DurationTimer();
@@ -175,173 +170,167 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
@BlockScreenType private int mBlockScreenType;
- private final DvrDataManager mDvrDataManager;
- private final ChannelDataManager mChannelDataManager;
+ private final TvInputManagerHelper mInputManager;
private final ConnectivityManager mConnectivityManager;
+ private final InputSessionManager mInputSessionManager;
- private final TvInputCallback mCallback =
- new TvInputCallback() {
- @Override
- public void onConnectionFailed(String inputId) {
- Log.w(TAG, "Failed to bind an input");
- mTracker.sendInputConnectionFailure(inputId);
- Channel channel = mCurrentChannel;
- mCurrentChannel = null;
- mInputInfo = null;
- mCanReceiveInputEvent = false;
- if (mOnTuneListener != null) {
- // If tune is called inside onTuneFailed, mOnTuneListener will be set to
- // a new instance. In order to avoid to clear the new mOnTuneListener,
- // we copy mOnTuneListener to l and clear mOnTuneListener before
- // calling onTuneFailed.
- OnTuneListener listener = mOnTuneListener;
- mOnTuneListener = null;
- listener.onTuneFailed(channel);
- }
- }
+ private final TvInputCallback mCallback = new TvInputCallback() {
+ @Override
+ public void onConnectionFailed(String inputId) {
+ Log.w(TAG, "Failed to bind an input");
+ mTracker.sendInputConnectionFailure(inputId);
+ Channel channel = mCurrentChannel;
+ mCurrentChannel = null;
+ mInputInfo = null;
+ mCanReceiveInputEvent = false;
+ if (mOnTuneListener != null) {
+ // If tune is called inside onTuneFailed, mOnTuneListener will be set to
+ // a new instance. In order to avoid to clear the new mOnTuneListener,
+ // we copy mOnTuneListener to l and clear mOnTuneListener before
+ // calling onTuneFailed.
+ OnTuneListener listener = mOnTuneListener;
+ mOnTuneListener = null;
+ listener.onTuneFailed(channel);
+ }
+ }
- @Override
- public void onDisconnected(String inputId) {
- Log.w(TAG, "Session is released by crash");
- mTracker.sendInputDisconnected(inputId);
- Channel channel = mCurrentChannel;
- mCurrentChannel = null;
- mInputInfo = null;
- mCanReceiveInputEvent = false;
- if (mOnTuneListener != null) {
- OnTuneListener listener = mOnTuneListener;
- mOnTuneListener = null;
- listener.onUnexpectedStop(channel);
- }
- }
+ @Override
+ public void onDisconnected(String inputId) {
+ Log.w(TAG, "Session is released by crash");
+ mTracker.sendInputDisconnected(inputId);
+ Channel channel = mCurrentChannel;
+ mCurrentChannel = null;
+ mInputInfo = null;
+ mCanReceiveInputEvent = false;
+ if (mOnTuneListener != null) {
+ OnTuneListener listener = mOnTuneListener;
+ mOnTuneListener = null;
+ listener.onUnexpectedStop(channel);
+ }
+ }
- @Override
- public void onChannelRetuned(String inputId, Uri channelUri) {
- if (DEBUG) {
- Log.d(TAG, "onChannelRetuned(inputId=" + inputId + ", channelUri="
- + channelUri + ")");
- }
- if (mOnTuneListener != null) {
- mOnTuneListener.onChannelRetuned(channelUri);
- }
- }
+ @Override
+ public void onChannelRetuned(String inputId, Uri channelUri) {
+ if (DEBUG) {
+ Log.d(TAG, "onChannelRetuned(inputId=" + inputId + ", channelUri="
+ + channelUri + ")");
+ }
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onChannelRetuned(channelUri);
+ }
+ }
- @Override
- public void onTracksChanged(String inputId, List<TvTrackInfo> tracks) {
- mHasClosedCaption = false;
- for (TvTrackInfo track : tracks) {
- if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) {
- mHasClosedCaption = true;
- break;
- }
- }
- if (mOnTuneListener != null) {
- mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
- }
+ @Override
+ public void onTracksChanged(String inputId, List<TvTrackInfo> tracks) {
+ mHasClosedCaption = false;
+ for (TvTrackInfo track : tracks) {
+ if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) {
+ mHasClosedCaption = true;
+ break;
}
+ }
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
+ }
+ }
- @Override
- public void onTrackSelected(String inputId, int type, String trackId) {
- if (trackId == null) {
- // A track is unselected.
- if (type == TvTrackInfo.TYPE_VIDEO) {
- mVideoWidth = 0;
- mVideoHeight = 0;
- mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
- mVideoFrameRate = 0f;
- mVideoDisplayAspectRatio = 0f;
- } else if (type == TvTrackInfo.TYPE_AUDIO) {
- mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
- }
- } else {
- List<TvTrackInfo> tracks = getTracks(type);
- boolean trackFound = false;
- if (tracks != null) {
- for (TvTrackInfo track : tracks) {
- if (track.getId().equals(trackId)) {
- if (type == TvTrackInfo.TYPE_VIDEO) {
- mVideoWidth = track.getVideoWidth();
- mVideoHeight = track.getVideoHeight();
- mVideoFormat = Utils.getVideoDefinitionLevelFromSize(
- mVideoWidth, mVideoHeight);
- mVideoFrameRate = track.getVideoFrameRate();
- if (mVideoWidth <= 0 || mVideoHeight <= 0) {
- mVideoDisplayAspectRatio = 0.0f;
- } else if (android.os.Build.VERSION.SDK_INT >=
- android.os.Build.VERSION_CODES.M) {
- float VideoPixelAspectRatio =
- track.getVideoPixelAspectRatio();
- mVideoDisplayAspectRatio = VideoPixelAspectRatio
- * mVideoWidth / mVideoHeight;
- } else {
- mVideoDisplayAspectRatio = mVideoWidth
- / (float) mVideoHeight;
- }
- } else if (type == TvTrackInfo.TYPE_AUDIO) {
- mAudioChannelCount = track.getAudioChannelCount();
- }
- trackFound = true;
- break;
+ @Override
+ public void onTrackSelected(String inputId, int type, String trackId) {
+ if (trackId == null) {
+ // A track is unselected.
+ if (type == TvTrackInfo.TYPE_VIDEO) {
+ mVideoWidth = 0;
+ mVideoHeight = 0;
+ mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
+ mVideoFrameRate = 0f;
+ mVideoDisplayAspectRatio = 0f;
+ } else if (type == TvTrackInfo.TYPE_AUDIO) {
+ mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
+ }
+ } else {
+ List<TvTrackInfo> tracks = getTracks(type);
+ boolean trackFound = false;
+ if (tracks != null) {
+ for (TvTrackInfo track : tracks) {
+ if (track.getId().equals(trackId)) {
+ if (type == TvTrackInfo.TYPE_VIDEO) {
+ mVideoWidth = track.getVideoWidth();
+ mVideoHeight = track.getVideoHeight();
+ mVideoFormat = Utils.getVideoDefinitionLevelFromSize(
+ mVideoWidth, mVideoHeight);
+ mVideoFrameRate = track.getVideoFrameRate();
+ if (mVideoWidth <= 0 || mVideoHeight <= 0) {
+ mVideoDisplayAspectRatio = 0.0f;
+ } else {
+ float VideoPixelAspectRatio =
+ track.getVideoPixelAspectRatio();
+ mVideoDisplayAspectRatio = VideoPixelAspectRatio
+ * mVideoWidth / mVideoHeight;
}
+ } else if (type == TvTrackInfo.TYPE_AUDIO) {
+ mAudioChannelCount = track.getAudioChannelCount();
}
+ trackFound = true;
+ break;
}
- if (!trackFound) {
- Log.w(TAG, "Invalid track ID: " + trackId);
- }
- }
- if (mOnTuneListener != null) {
- mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
}
}
-
- @Override
- public void onVideoAvailable(String inputId) {
- unhideScreenByVideoAvailability();
- if (mOnTuneListener != null) {
- mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
- }
+ if (!trackFound) {
+ Log.w(TAG, "Invalid track ID: " + trackId);
}
+ }
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
+ }
+ }
- @Override
- public void onVideoUnavailable(String inputId, int reason) {
- hideScreenByVideoAvailability(reason);
- if (mOnTuneListener != null) {
- mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
- }
- switch (reason) {
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING:
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN:
- case TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL:
- mTracker.sendChannelVideoUnavailable(mCurrentChannel, reason);
- default:
- // do nothing
- }
- }
+ @Override
+ public void onVideoAvailable(String inputId) {
+ unhideScreenByVideoAvailability();
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
+ }
+ }
- @Override
- public void onContentAllowed(String inputId) {
- mBlockScreenForTuneView.setVisibility(View.GONE);
- unblockScreenByContentRating();
- if (mOnTuneListener != null) {
- mOnTuneListener.onContentAllowed();
- }
- }
+ @Override
+ public void onVideoUnavailable(String inputId, int reason) {
+ hideScreenByVideoAvailability(inputId, reason);
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onStreamInfoChanged(TunableTvView.this);
+ }
+ switch (reason) {
+ case TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING:
+ case TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN:
+ case TvInputManager.VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL:
+ mTracker.sendChannelVideoUnavailable(mCurrentChannel, reason);
+ default:
+ // do nothing
+ }
+ }
- @Override
- public void onContentBlocked(String inputId, TvContentRating rating) {
- blockScreenByContentRating(rating);
- if (mOnTuneListener != null) {
- mOnTuneListener.onContentBlocked();
- }
- }
+ @Override
+ public void onContentAllowed(String inputId) {
+ mBlockScreenForTuneView.setVisibility(View.GONE);
+ unblockScreenByContentRating();
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onContentAllowed();
+ }
+ }
- @Override
- @TargetApi(Build.VERSION_CODES.M)
- public void onTimeShiftStatusChanged(String inputId, int status) {
- boolean available = status == TvInputManager.TIME_SHIFT_STATUS_AVAILABLE;
- setTimeShiftAvailable(available);
- }
- };
+ @Override
+ public void onContentBlocked(String inputId, TvContentRating rating) {
+ blockScreenByContentRating(rating);
+ if (mOnTuneListener != null) {
+ mOnTuneListener.onContentBlocked();
+ }
+ }
+
+ @Override
+ public void onTimeShiftStatusChanged(String inputId, int status) {
+ boolean available = status == TvInputManager.TIME_SHIFT_STATUS_AVAILABLE;
+ setTimeShiftAvailable(available);
+ }
+ };
public TunableTvView(Context context) {
this(context, null);
@@ -360,10 +349,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
inflate(getContext(), R.layout.tunable_tv_view, this);
ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
- mDvrDataManager = CommonFeatures.DVR.isEnabled(context) && BuildCompat.isAtLeastN()
- ? appSingletons.getDvrDataManager()
- : null;
- mChannelDataManager = appSingletons.getChannelDataManager();
+ if (CommonFeatures.DVR.isEnabled(context)) {
+ mInputSessionManager = appSingletons.getInputSessionManager();
+ } else {
+ mInputSessionManager = null;
+ }
+ mInputManager = appSingletons.getTvInputManagerHelper();
mConnectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
mCanModifyParentalControls = PermissionUtils.hasModifyParentalControls(context);
@@ -409,6 +400,11 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
public void initialize(AppLayerTvView tvView, boolean isPip, int screenHeight,
int shrunkenTvViewHeight) {
mTvView = tvView;
+ if (mInputSessionManager != null) {
+ mTvViewSession = mInputSessionManager.createTvViewSession(tvView, this, mCallback);
+ } else {
+ mTvView.setCallback(mCallback);
+ }
mIsPip = isPip;
mScreenHeight = screenHeight;
mShrunkenTvViewHeight = shrunkenTvViewHeight;
@@ -425,6 +421,20 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mStarted = true;
}
+ /**
+ * Warms up the input to reduce the start time.
+ */
+ public void warmUpInput(String inputId, Uri channelUri) {
+ if (!mStarted && inputId != null && channelUri != null) {
+ if (mTvViewSession != null) {
+ mTvViewSession.tune(inputId, channelUri);
+ } else {
+ mTvView.tune(inputId, channelUri);
+ }
+ hideScreenByVideoAvailability(inputId, TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+ }
+ }
+
public void stop() {
if (!mStarted) {
return;
@@ -441,15 +451,42 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
reset();
}
+ /**
+ * Releases the resources.
+ */
+ public void release() {
+ if (mInputSessionManager != null) {
+ mInputSessionManager.releaseTvViewSession(mTvViewSession);
+ mTvViewSession = null;
+ }
+ }
+
+ /**
+ * Reset TV view.
+ */
public void reset() {
- mTvView.reset();
+ resetInternal();
+ hideScreenByVideoAvailability(null, VIDEO_UNAVAILABLE_REASON_NOT_TUNED);
+ }
+
+ /**
+ * Reset TV view to acquire the recording session.
+ */
+ public void resetByRecording() {
+ resetInternal();
+ }
+
+ private void resetInternal() {
+ if (mTvViewSession != null) {
+ mTvViewSession.reset();
+ } else {
+ mTvView.reset();
+ }
mCurrentChannel = null;
- mRecordedProgram = null;
mInputInfo = null;
mCanReceiveInputEvent = false;
mOnTuneListener = null;
setTimeShiftAvailable(false);
- hideScreenByVideoAvailability(VIDEO_UNAVAILABLE_REASON_NOT_TUNED);
}
public void setMain() {
@@ -475,85 +512,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
/**
- * Returns {@code true}, if this view is the recording playback mode.
- */
- public boolean isRecordingPlayback() {
- return mRecordedProgram != null;
- }
-
- /**
- * Returns the recording which is being played right now.
- */
- public RecordedProgram getPlayingRecordedProgram() {
- return mRecordedProgram;
- }
-
- /**
- * Plays a recording.
- */
- public boolean playRecording(Uri recordingUri, OnTuneListener listener) {
- if (!mStarted) {
- throw new IllegalStateException("TvView isn't started");
- }
- if (!CommonFeatures.DVR.isEnabled(getContext()) || !BuildCompat.isAtLeastN()) {
- return false;
- }
- if (DEBUG) Log.d(TAG, "playRecording " + recordingUri);
- long recordingId = ContentUris.parseId(recordingUri);
- mRecordedProgram = mDvrDataManager.getRecordedProgram(recordingId);
- if (mRecordedProgram == null) {
- Log.w(TAG, "No recorded program (Uri=" + recordingUri + ")");
- return false;
- }
- String inputId = mRecordedProgram.getInputId();
- TvInputInfo inputInfo = mInputManagerHelper.getTvInputInfo(inputId);
- if (inputInfo == null) {
- return false;
- }
- mOnTuneListener = listener;
- // mCurrentChannel can be null.
- mCurrentChannel = mChannelDataManager.getChannel(mRecordedProgram.getChannelId());
- // For recording playback, input event should not be sent.
- mCanReceiveInputEvent = false;
- boolean needSurfaceSizeUpdate = false;
- if (!inputInfo.equals(mInputInfo)) {
- mInputInfo = inputInfo;
- if (DEBUG) {
- Log.d(TAG, "Input \'" + mInputInfo.getId() + "\' can receive input event: "
- + mCanReceiveInputEvent);
- }
- needSurfaceSizeUpdate = true;
- }
- mChannelViewTimer.start();
- mVideoWidth = 0;
- mVideoHeight = 0;
- mVideoFormat = StreamInfo.VIDEO_DEFINITION_LEVEL_UNKNOWN;
- mVideoFrameRate = 0f;
- mVideoDisplayAspectRatio = 0f;
- mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
- mHasClosedCaption = false;
- mTvView.setCallback(mCallback);
- mTimeShiftCurrentPositionMs = INVALID_TIME;
- mTvView.setTimeShiftPositionCallback(null);
- setTimeShiftAvailable(false);
- mTvView.timeShiftPlay(inputId, recordingUri);
- if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) {
- // When the input is changed, TvView recreates its SurfaceView internally.
- // So we need to call SurfaceHolder.setFixedSize for the new SurfaceView.
- getSurfaceView().getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight);
- }
- hideScreenByVideoAvailability(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
- unblockScreenByContentRating();
- if (mParentControlEnabled) {
- mBlockScreenForTuneView.setVisibility(View.VISIBLE);
- }
- if (mOnTuneListener != null) {
- mOnTuneListener.onStreamInfoChanged(this);
- }
- return true;
- }
-
- /**
* Tunes to a channel with the {@code channelId}.
*
* @param params extra data to send it to TIS and store the data in TIMS.
@@ -579,7 +537,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
mOnTuneListener = listener;
mCurrentChannel = channel;
- mRecordedProgram = null;
boolean tunedByRecommendation = params != null
&& params.getString(NotificationService.TUNE_PARAMS_RECOMMENDATION_TYPE) != null;
boolean needSurfaceSizeUpdate = false;
@@ -603,20 +560,22 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mVideoDisplayAspectRatio = 0f;
mAudioChannelCount = StreamInfo.AUDIO_CHANNEL_COUNT_UNKNOWN;
mHasClosedCaption = false;
- mTvView.setCallback(mCallback);
- mTimeShiftCurrentPositionMs = INVALID_TIME;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- // To reduce the IPCs, unregister the callback here and register it when necessary.
- mTvView.setTimeShiftPositionCallback(null);
- }
+ mTimeShiftCurrentPositionMs = TvInputManager.TIME_SHIFT_INVALID_TIME;
+ // To reduce the IPCs, unregister the callback here and register it when necessary.
+ mTvView.setTimeShiftPositionCallback(null);
setTimeShiftAvailable(false);
- mTvView.tune(mInputInfo.getId(), mCurrentChannel.getUri(), params);
if (needSurfaceSizeUpdate && mFixedSurfaceWidth > 0 && mFixedSurfaceHeight > 0) {
// When the input is changed, TvView recreates its SurfaceView internally.
// So we need to call SurfaceHolder.setFixedSize for the new SurfaceView.
getSurfaceView().getHolder().setFixedSize(mFixedSurfaceWidth, mFixedSurfaceHeight);
}
- hideScreenByVideoAvailability(TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+ hideScreenByVideoAvailability(mInputInfo.getId(),
+ TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING);
+ if (mTvViewSession != null) {
+ mTvViewSession.tune(channel, params, listener);
+ } else {
+ mTvView.tune(mInputInfo.getId(), mCurrentChannel.getUri(), params);
+ }
unblockScreenByContentRating();
if (channel.isPassthrough()) {
mBlockScreenForTuneView.setVisibility(View.GONE);
@@ -709,17 +668,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
public void unblockContent(TvContentRating rating) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- try {
- Method method = TvView.class.getMethod("requestUnblockContent",
- TvContentRating.class);
- method.invoke(mTvView, rating);
- } catch (NoSuchMethodException|IllegalAccessException|InvocationTargetException e) {
- e.printStackTrace();
- }
- } else {
- mTvView.unblockContent(rating);
- }
+ mTvView.unblockContent(rating);
}
@Override
@@ -811,6 +760,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
/**
* Returns currently blocked content rating. {@code null} if it's not blocked.
*/
+ @Override
public TvContentRating getBlockedContentRating() {
return mBlockedContentRating;
}
@@ -869,11 +819,13 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
|| tvViewLp.gravity != lp.gravity
|| tvViewLp.height != lp.height
|| tvViewLp.width != lp.width) {
- if (lp.topMargin == tvViewLp.topMargin && lp.leftMargin == tvViewLp.leftMargin) {
+ if (lp.topMargin == tvViewLp.topMargin && lp.leftMargin == tvViewLp.leftMargin
+ && !BuildCompat.isAtLeastN()) {
// HACK: If top and left position aren't changed and SurfaceHolder.setFixedSize is
// used, SurfaceView doesn't catch the width and height change. It causes a bug that
// PIP size change isn't shown when PIP is located TOP|LEFT. So we adjust 1 px for
// small size PIP as a workaround.
+ // Note: This framework issue has been fixed from NYC.
tvViewLp.leftMargin = lp.leftMargin + 1;
} else {
tvViewLp.leftMargin = lp.leftMargin;
@@ -889,7 +841,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
@Override
- protected void onVisibilityChanged(View changedView, int visibility) {
+ protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
super.onVisibilityChanged(changedView, visibility);
if (mTvView != null) {
mTvView.setVisibility(visibility);
@@ -1024,7 +976,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
@UiThread
- private void hideScreenByVideoAvailability(int reason) {
+ private void hideScreenByVideoAvailability(String inputId, int reason) {
mVideoAvailable = false;
mVideoUnavailableReason = reason;
if (mInternetCheckTask != null) {
@@ -1050,6 +1002,12 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mute();
break;
case TvInputManager.VIDEO_UNAVAILABLE_REASON_TUNING:
+ mHideScreenView.setVisibility(VISIBLE);
+ mHideScreenView.setImageVisibility(false);
+ mHideScreenView.setText(null);
+ mBufferingSpinnerView.setVisibility(VISIBLE);
+ mute();
+ break;
case VIDEO_UNAVAILABLE_REASON_NOT_TUNED:
mHideScreenView.setVisibility(VISIBLE);
mHideScreenView.setImageVisibility(false);
@@ -1057,6 +1015,13 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mBufferingSpinnerView.setVisibility(GONE);
mute();
break;
+ case VIDEO_UNAVAILABLE_REASON_NO_RESOURCE:
+ mHideScreenView.setVisibility(VISIBLE);
+ mHideScreenView.setImageVisibility(false);
+ mHideScreenView.setText(getTuneConflictMessage(inputId));
+ mBufferingSpinnerView.setVisibility(GONE);
+ mute();
+ break;
case TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN:
default:
mHideScreenView.setVisibility(VISIBLE);
@@ -1072,6 +1037,19 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
}
+ private String getTuneConflictMessage(String inputId) {
+ if (inputId != null) {
+ TvInputInfo input = mInputManager.getTvInputInfo(inputId);
+ Long timeMs = mInputSessionManager.getEarliestRecordingSessionEndTimeMs(inputId);
+ if (timeMs != null) {
+ return getResources().getQuantityString(R.plurals.tvview_msg_input_no_resource,
+ input.getTunerCount(),
+ DateUtils.formatDateTime(getContext(), timeMs, DateUtils.FORMAT_SHOW_TIME));
+ }
+ }
+ return null;
+ }
+
private void unhideScreenByVideoAvailability() {
mVideoAvailable = true;
mHideScreenView.setVisibility(GONE);
@@ -1166,7 +1144,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
private void setTimeShiftAvailable(boolean isTimeShiftAvailable) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M || mTimeShiftAvailable == isTimeShiftAvailable) {
+ if (mTimeShiftAvailable == isTimeShiftAvailable) {
return;
}
mTimeShiftAvailable = isTimeShiftAvailable;
@@ -1201,23 +1179,9 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
/**
- * Returns the current time-shift state. It returns one of {@link #TIME_SHIFT_STATE_NONE},
- * {@link #TIME_SHIFT_STATE_PLAY}, {@link #TIME_SHIFT_STATE_PAUSE},
- * {@link #TIME_SHIFT_STATE_REWIND}, {@link #TIME_SHIFT_STATE_FAST_FORWARD}
- * or {@link #TIME_SHIFT_STATE_PAUSE}.
- */
- @TimeShiftState public int getTimeShiftState() {
- return mTimeShiftState;
- }
-
- /**
* Plays the media, if the current input supports time-shifting.
*/
public void timeshiftPlay() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- return;
- }
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
}
@@ -1231,10 +1195,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
* Pauses the media, if the current input supports time-shifting.
*/
public void timeshiftPause() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- return;
- }
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
}
@@ -1250,9 +1210,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
* @param speed The speed to rewind the media. e.g. 2 for 2x, 3 for 3x and 4 for 4x.
*/
public void timeshiftRewind(int speed) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- } else if (!isTimeShiftAvailable()) {
+ if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
} else {
if (speed <= 0) {
@@ -1271,9 +1229,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
* @param speed The speed to forward the media. e.g. 2 for 2x, 3 for 3x and 4 for 4x.
*/
public void timeshiftFastForward(int speed) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- } else if (!isTimeShiftAvailable()) {
+ if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
} else {
if (speed <= 0) {
@@ -1292,10 +1248,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
* @param timeMs The time in milliseconds to seek to.
*/
public void timeshiftSeekTo(long timeMs) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- return;
- }
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
}
@@ -1306,10 +1258,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
* Returns the current playback position in milliseconds.
*/
public long timeshiftGetCurrentPositionMs() {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.w(TAG, "Time shifting is not supported in this platform.");
- return INVALID_TIME;
- }
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
}
@@ -1332,6 +1280,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
/**
* Called when the record start time has been changed.
+ * This is not called when the recorded programs is played.
*/
public abstract void onRecordStartTimeChanged(long recordStartTimeMs);
}
@@ -1346,7 +1295,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
public abstract void onScreenBlockingChanged(boolean blocked);
}
- public class InternetCheckTask extends AsyncTask<Void, Void, Boolean> {
+ private class InternetCheckTask extends AsyncTask<Void, Void, Boolean> {
@Override
protected Boolean doInBackground(Void... params) {
return NetworkUtils.isNetworkAvailable(mConnectivityManager);
diff --git a/src/com/android/tv/ui/TvOverlayManager.java b/src/com/android/tv/ui/TvOverlayManager.java
index 94f9b0f9..e14b286b 100644
--- a/src/com/android/tv/ui/TvOverlayManager.java
+++ b/src/com/android/tv/ui/TvOverlayManager.java
@@ -21,22 +21,16 @@ import android.app.FragmentManager;
import android.app.FragmentManager.OnBackStackChangedListener;
import android.content.Intent;
import android.media.tv.TvInputInfo;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
-import android.support.v4.os.BuildCompat;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
-import android.view.LayoutInflater;
-import android.view.View;
import android.view.ViewGroup;
-import android.widget.Space;
import com.android.tv.ApplicationSingletons;
import com.android.tv.ChannelTuner;
@@ -66,29 +60,30 @@ import com.android.tv.menu.MenuRowFactory;
import com.android.tv.menu.MenuView;
import com.android.tv.onboarding.NewSourcesFragment;
import com.android.tv.onboarding.SetupSourcesFragment;
-import com.android.tv.onboarding.SetupSourcesFragment.InputSetupRunnable;
import com.android.tv.search.ProgramGuideSearchFragment;
import com.android.tv.ui.TvTransitionManager.SceneType;
import com.android.tv.ui.sidepanel.SettingsFragment;
import com.android.tv.ui.sidepanel.SideFragmentManager;
import com.android.tv.ui.sidepanel.parentalcontrols.RatingsFragment;
+import com.android.tv.util.TvInputManagerHelper;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.HashSet;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
import java.util.Set;
/**
* A class responsible for the life cycle and event handling of the pop-ups over TV view.
*/
-// TODO: Put TvTransitionManager into this class.
@UiThread
public class TvOverlayManager {
private static final String TAG = "TvOverlayManager";
private static final boolean DEBUG = false;
- public static final String INTRO_TRACKER_LABEL = "Intro dialog";
+ private static final String INTRO_TRACKER_LABEL = "Intro dialog";
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true,
@@ -97,7 +92,7 @@ public class TvOverlayManager {
FLAG_HIDE_OVERLAYS_KEEP_SIDE_PANELS, FLAG_HIDE_OVERLAYS_KEEP_SIDE_PANEL_HISTORY,
FLAG_HIDE_OVERLAYS_KEEP_PROGRAM_GUIDE, FLAG_HIDE_OVERLAYS_KEEP_MENU,
FLAG_HIDE_OVERLAYS_KEEP_FRAGMENT})
- public @interface HideOverlayFlag {}
+ private @interface HideOverlayFlag {}
// FLAG_HIDE_OVERLAYs must be bitwise exclusive.
public static final int FLAG_HIDE_OVERLAYS_DEFAULT = 0b000000000;
public static final int FLAG_HIDE_OVERLAYS_WITHOUT_ANIMATION = 0b000000010;
@@ -109,7 +104,7 @@ public class TvOverlayManager {
public static final int FLAG_HIDE_OVERLAYS_KEEP_MENU = 0b010000000;
public static final int FLAG_HIDE_OVERLAYS_KEEP_FRAGMENT = 0b100000000;
- public static final int MSG_OVERLAY_CLOSED = 1000;
+ private static final int MSG_OVERLAY_CLOSED = 1000;
@Retention(RetentionPolicy.SOURCE)
@IntDef(flag = true,
@@ -119,16 +114,51 @@ public class TvOverlayManager {
OVERLAY_TYPE_SCENE_SELECT_INPUT, OVERLAY_TYPE_FRAGMENT})
private @interface TvOverlayType {}
// OVERLAY_TYPEs must be bitwise exclusive.
+ /**
+ * The overlay type which indicates that there are no overlays.
+ */
private static final int OVERLAY_TYPE_NONE = 0b000000000;
+ /**
+ * The overlay type for menu.
+ */
private static final int OVERLAY_TYPE_MENU = 0b000000001;
+ /**
+ * The overlay type for the side fragment.
+ */
private static final int OVERLAY_TYPE_SIDE_FRAGMENT = 0b000000010;
+ /**
+ * The overlay type for dialog fragment.
+ */
private static final int OVERLAY_TYPE_DIALOG = 0b000000100;
+ /**
+ * The overlay type for program guide.
+ */
private static final int OVERLAY_TYPE_GUIDE = 0b000001000;
+ /**
+ * The overlay type for channel banner.
+ */
private static final int OVERLAY_TYPE_SCENE_CHANNEL_BANNER = 0b000010000;
+ /**
+ * The overlay type for input banner.
+ */
private static final int OVERLAY_TYPE_SCENE_INPUT_BANNER = 0b000100000;
+ /**
+ * The overlay type for keypad channel switch view.
+ */
private static final int OVERLAY_TYPE_SCENE_KEYPAD_CHANNEL_SWITCH = 0b001000000;
+ /**
+ * The overlay type for select input view.
+ */
private static final int OVERLAY_TYPE_SCENE_SELECT_INPUT = 0b010000000;
+ /**
+ * The overlay type for fragment other than the side fragment and dialog fragment.
+ */
private static final int OVERLAY_TYPE_FRAGMENT = 0b100000000;
+ // Used for the padded print of the overlay type.
+ private static final int NUM_OVERLAY_TYPES = 9;
+
+ private static final String FRAGMENT_TAG_SETUP_SOURCES = "tag_setup_sources";
+ private static final String FRAGMENT_TAG_NEW_SOURCES = "tag_new_sources";
private static final Set<String> AVAILABLE_DIALOG_TAGS = new HashSet<>();
static {
@@ -144,6 +174,7 @@ public class TvOverlayManager {
private final ChannelTuner mChannelTuner;
private final TvTransitionManager mTransitionManager;
private final ChannelDataManager mChannelDataManager;
+ private final TvInputManagerHelper mInputManager;
private final Menu mMenu;
private final SideFragmentManager mSideFragmentManager;
private final ProgramGuide mProgramGuide;
@@ -152,18 +183,19 @@ public class TvOverlayManager {
private final ProgramGuideSearchFragment mSearchFragment;
private final Tracker mTracker;
private SafeDismissDialogFragment mCurrentDialog;
- private final SetupSourcesFragment mSetupFragment;
private boolean mSetupFragmentActive;
- private final NewSourcesFragment mNewSourcesFragment;
private boolean mNewSourcesFragmentActive;
private final Handler mHandler = new TvOverlayHandler(this);
private @TvOverlayType int mOpenedOverlays;
private final List<Runnable> mPendingActions = new ArrayList<>();
+ private final Queue<PendingDialogAction> mPendingDialogActionQueue = new LinkedList<>();
+
+ private OnBackStackChangedListener mOnBackStackChangedListener;
public TvOverlayManager(MainActivity mainActivity, ChannelTuner channelTuner,
- KeypadChannelSwitchView keypadChannelSwitchView,
+ TunableTvView tvView, KeypadChannelSwitchView keypadChannelSwitchView,
ChannelBannerView channelBannerView, InputBannerView inputBannerView,
SelectInputView selectInputView, ViewGroup sceneContainer,
ProgramGuideSearchFragment searchFragment) {
@@ -171,6 +203,7 @@ public class TvOverlayManager {
mChannelTuner = channelTuner;
ApplicationSingletons singletons = TvApplication.getSingletons(mainActivity);
mChannelDataManager = singletons.getChannelDataManager();
+ mInputManager = singletons.getTvInputManagerHelper();
mKeypadChannelSwitchView = keypadChannelSwitchView;
mSelectInputView = selectInputView;
mSearchFragment = searchFragment;
@@ -180,8 +213,8 @@ public class TvOverlayManager {
mTransitionManager.setListener(new TvTransitionManager.Listener() {
@Override
public void onSceneChanged(int fromScene, int toScene) {
- // Call notifyOverlayOpened first so that the listener can know that a new scene
- // will be opened when the notifyOverlayClosed is called.
+ // Call onOverlayOpened first so that the listener can know that a new scene
+ // will be opened when the onOverlayClosed is called.
if (toScene != TvTransitionManager.SCENE_TYPE_EMPTY) {
onOverlayOpened(convertSceneToOverlayType(toScene));
}
@@ -192,7 +225,7 @@ public class TvOverlayManager {
});
// Menu
MenuView menuView = (MenuView) mainActivity.findViewById(R.id.menu);
- mMenu = new Menu(mainActivity, menuView, new MenuRowFactory(mainActivity),
+ mMenu = new Menu(mainActivity, tvView, menuView, new MenuRowFactory(mainActivity, tvView),
new Menu.OnMenuVisibilityChangeListener() {
@Override
public void onMenuVisibilityChange(boolean visible) {
@@ -203,6 +236,7 @@ public class TvOverlayManager {
}
}
});
+ mMenu.setChannelTuner(mChannelTuner);
// Side Fragment
mSideFragmentManager = new SideFragmentManager(mainActivity,
new Runnable() {
@@ -232,49 +266,49 @@ public class TvOverlayManager {
onOverlayClosed(OVERLAY_TYPE_GUIDE);
}
};
- DvrDataManager dvrDataManager =
- CommonFeatures.DVR.isEnabled(mainActivity) && BuildCompat.isAtLeastN() ? singletons
- .getDvrDataManager() : null;
+ DvrDataManager dvrDataManager = CommonFeatures.DVR.isEnabled(mainActivity)
+ ? singletons.getDvrDataManager() : null;
mProgramGuide = new ProgramGuide(mainActivity, channelTuner,
singletons.getTvInputManagerHelper(), mChannelDataManager,
- singletons.getProgramDataManager(), dvrDataManager, singletons.getTracker(),
- preShowRunnable,
+ singletons.getProgramDataManager(), dvrDataManager,
+ singletons.getDvrScheduleManager(), singletons.getTracker(), preShowRunnable,
postHideRunnable);
- mSetupFragment = new SetupSourcesFragment();
- mSetupFragment.setOnActionClickListener(new OnActionClickListener() {
- @Override
- public void onActionClick(String category, int id) {
- switch (id) {
- case SetupMultiPaneFragment.ACTION_DONE:
- closeSetupFragment(true);
- break;
- case SetupSourcesFragment.ACTION_PLAY_STORE:
- mMainActivity.showMerchantCollection();
- break;
- }
- }
- });
- mSetupFragment.setInputSetupRunnable(new InputSetupRunnable() {
- @Override
- public void runInputSetup(TvInputInfo input) {
- mMainActivity.startSetupActivity(input, true);
- }
- });
- mNewSourcesFragment = new NewSourcesFragment();
- mNewSourcesFragment.setOnActionClickListener(new OnActionClickListener() {
+ mMainActivity.addOnActionClickListener(new OnActionClickListener() {
@Override
- public void onActionClick(String category, int id) {
- switch (id) {
- case NewSourcesFragment.ACTION_SETUP:
- closeNewSourcesFragment(false);
- showSetupFragment();
+ public boolean onActionClick(String category, int id, Bundle params) {
+ switch (category) {
+ case SetupSourcesFragment.ACTION_CATEGORY:
+ switch (id) {
+ case SetupMultiPaneFragment.ACTION_DONE:
+ closeSetupFragment(true);
+ return true;
+ case SetupSourcesFragment.ACTION_ONLINE_STORE:
+ mMainActivity.showMerchantCollection();
+ return true;
+ case SetupSourcesFragment.ACTION_SETUP_INPUT: {
+ String inputId = params.getString(
+ SetupSourcesFragment.ACTION_PARAM_KEY_INPUT_ID);
+ TvInputInfo input = mInputManager.getTvInputInfo(inputId);
+ mMainActivity.startSetupActivity(input, true);
+ return true;
+ }
+ }
break;
- case NewSourcesFragment.ACTION_SKIP:
- // Don't remove the fragment because new fragment will be replaced with
- // this fragment.
- closeNewSourcesFragment(true);
+ case NewSourcesFragment.ACTION_CATEOGRY:
+ switch (id) {
+ case NewSourcesFragment.ACTION_SETUP:
+ closeNewSourcesFragment(false);
+ showSetupFragment();
+ return true;
+ case NewSourcesFragment.ACTION_SKIP:
+ // Don't remove the fragment because new fragment will be replaced
+ // with this fragment.
+ closeNewSourcesFragment(true);
+ return true;
+ }
break;
}
+ return false;
}
});
}
@@ -313,16 +347,29 @@ public class TvOverlayManager {
* Checks whether the setup fragment is active or not.
*/
public boolean isSetupFragmentActive() {
+ // "getSetupSourcesFragment() != null" doesn't return the correct state. That's because,
+ // when we call showSetupFragment(), we need to put off showing the fragment until the side
+ // fragment is closed. Until then, getSetupSourcesFragment() returns null. So we need
+ // to keep additional variable which indicates if showSetupFragment() is called.
return mSetupFragmentActive;
}
+ private Fragment getSetupSourcesFragment() {
+ return mMainActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG_SETUP_SOURCES);
+ }
+
/**
* Checks whether the new sources fragment is active or not.
*/
public boolean isNewSourcesFragmentActive() {
+ // See the comment in "isSetupFragmentActive".
return mNewSourcesFragmentActive;
}
+ private Fragment getNewSourcesFragment() {
+ return mMainActivity.getFragmentManager().findFragmentByTag(FRAGMENT_TAG_NEW_SOURCES);
+ }
+
/**
* Returns the instance of {@link ProgramGuide}.
*/
@@ -373,9 +420,10 @@ public class TvOverlayManager {
return;
}
- Fragment old = mMainActivity.getFragmentManager().findFragmentByTag(tag);
- // Do not show the dialog if the same kind of dialog is already opened.
- if (old != null) {
+ // Do not open two dialogs at the same time.
+ if (mCurrentDialog != null) {
+ mPendingDialogActionQueue.offer(new PendingDialogAction(tag, dialog,
+ keepSidePanelHistory, keepProgramGuide));
return;
}
@@ -389,43 +437,52 @@ public class TvOverlayManager {
}
private void runAfterSideFragmentsAreClosed(final Runnable runnable) {
- final FragmentManager manager = mMainActivity.getFragmentManager();
if (mSideFragmentManager.isSidePanelVisible()) {
- manager.addOnBackStackChangedListener(new OnBackStackChangedListener() {
+ // When the side panel is closing, it closes all the fragments, so the new fragment
+ // should be opened after the side fragment becomes invisible.
+ final FragmentManager manager = mMainActivity.getFragmentManager();
+ mOnBackStackChangedListener = new OnBackStackChangedListener() {
@Override
public void onBackStackChanged() {
if (manager.getBackStackEntryCount() == 0) {
manager.removeOnBackStackChangedListener(this);
+ mOnBackStackChangedListener = null;
runnable.run();
}
}
- });
+ };
+ manager.addOnBackStackChangedListener(mOnBackStackChangedListener);
} else {
runnable.run();
}
}
- private void showFragment(final Fragment fragment) {
+ private void showFragment(final Fragment fragment, final String tag) {
hideOverlays(FLAG_HIDE_OVERLAYS_KEEP_FRAGMENT);
onOverlayOpened(OVERLAY_TYPE_FRAGMENT);
runAfterSideFragmentsAreClosed(new Runnable() {
@Override
public void run() {
+ if (DEBUG) Log.d(TAG, "showFragment(" + fragment + ")");
mMainActivity.getFragmentManager().beginTransaction()
- .replace(R.id.fragment_container, fragment).commit();
+ .replace(R.id.fragment_container, fragment, tag).commit();
}
});
}
- private void closeFragment(Fragment fragmentToRemove) {
+ private void closeFragment(String fragmentTagToRemove) {
+ if (DEBUG) Log.d(TAG, "closeFragment(" + fragmentTagToRemove + ")");
onOverlayClosed(OVERLAY_TYPE_FRAGMENT);
- if (fragmentToRemove != null) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // In L, NPE happens if there is no next fragment when removing or hiding a fragment
- // which has an exit transition. b/22631964
- // A workaround is just replacing with a dummy fragment.
- mMainActivity.getFragmentManager().beginTransaction()
- .replace(R.id.fragment_container, new DummyFragment()).commit();
+ if (fragmentTagToRemove != null) {
+ Fragment fragmentToRemove = mMainActivity.getFragmentManager()
+ .findFragmentByTag(fragmentTagToRemove);
+ if (fragmentToRemove == null) {
+ // If the fragment has not been added to the fragment manager yet, just remove the
+ // listener not to add the fragment. This is needed because the side fragment is
+ // closed asynchronously.
+ mMainActivity.getFragmentManager().removeOnBackStackChangedListener(
+ mOnBackStackChangedListener);
+ mOnBackStackChangedListener = null;
} else {
mMainActivity.getFragmentManager().beginTransaction().remove(fragmentToRemove)
.commit();
@@ -439,11 +496,12 @@ public class TvOverlayManager {
public void showSetupFragment() {
if (DEBUG) Log.d(TAG, "showSetupFragment");
mSetupFragmentActive = true;
- mSetupFragment.enableFragmentTransition(SetupFragment.FRAGMENT_ENTER_TRANSITION
+ SetupSourcesFragment setupFragment = new SetupSourcesFragment();
+ setupFragment.enableFragmentTransition(SetupFragment.FRAGMENT_ENTER_TRANSITION
| SetupFragment.FRAGMENT_EXIT_TRANSITION | SetupFragment.FRAGMENT_RETURN_TRANSITION
| SetupFragment.FRAGMENT_REENTER_TRANSITION);
- mSetupFragment.setFragmentTransition(SetupFragment.FRAGMENT_EXIT_TRANSITION, Gravity.END);
- showFragment(mSetupFragment);
+ setupFragment.setFragmentTransition(SetupFragment.FRAGMENT_EXIT_TRANSITION, Gravity.END);
+ showFragment(setupFragment, FRAGMENT_TAG_SETUP_SOURCES);
}
// Set removeFragment to false only when the new fragment is going to be shown.
@@ -453,8 +511,9 @@ public class TvOverlayManager {
return;
}
mSetupFragmentActive = false;
- closeFragment(removeFragment ? mSetupFragment : null);
+ closeFragment(removeFragment ? FRAGMENT_TAG_SETUP_SOURCES : null);
if (mChannelDataManager.getChannelCount() == 0) {
+ if (DEBUG) Log.d(TAG, "Finishing MainActivity because there are no channels.");
mMainActivity.finish();
}
}
@@ -465,14 +524,17 @@ public class TvOverlayManager {
public void showNewSourcesFragment() {
if (DEBUG) Log.d(TAG, "showNewSourcesFragment");
mNewSourcesFragmentActive = true;
- showFragment(mNewSourcesFragment);
+ showFragment(new NewSourcesFragment(), FRAGMENT_TAG_NEW_SOURCES);
}
// Set removeFragment to false only when the new fragment is going to be shown.
private void closeNewSourcesFragment(boolean removeFragment) {
if (DEBUG) Log.d(TAG, "closeNewSourcesFragment");
+ if (!mNewSourcesFragmentActive) {
+ return;
+ }
mNewSourcesFragmentActive = false;
- closeFragment(removeFragment ? mNewSourcesFragment : null);
+ closeFragment(removeFragment ? FRAGMENT_TAG_NEW_SOURCES : null);
}
/**
@@ -536,7 +598,12 @@ public class TvOverlayManager {
*/
public void onDialogDestroyed() {
mCurrentDialog = null;
- onOverlayClosed(OVERLAY_TYPE_DIALOG);
+ PendingDialogAction action = mPendingDialogActionQueue.poll();
+ if (action == null) {
+ onOverlayClosed(OVERLAY_TYPE_DIALOG);
+ } else {
+ action.run();
+ }
}
/**
@@ -571,18 +638,26 @@ public class TvOverlayManager {
}
mCurrentDialog.dismiss();
}
+ mPendingDialogActionQueue.clear();
mCurrentDialog = null;
}
boolean withAnimation = (flags & FLAG_HIDE_OVERLAYS_WITHOUT_ANIMATION) == 0;
if ((flags & FLAG_HIDE_OVERLAYS_KEEP_FRAGMENT) == 0) {
+ Fragment setupSourcesFragment = getSetupSourcesFragment();
+ Fragment newSourcesFragment = getNewSourcesFragment();
if (mSetupFragmentActive) {
- if (!withAnimation) {
- mSetupFragment.setReturnTransition(null);
- mSetupFragment.setExitTransition(null);
+ if (!withAnimation && setupSourcesFragment != null) {
+ setupSourcesFragment.setReturnTransition(null);
+ setupSourcesFragment.setExitTransition(null);
}
closeSetupFragment(true);
- } else if (mNewSourcesFragmentActive) {
+ }
+ if (mNewSourcesFragmentActive) {
+ if (!withAnimation && newSourcesFragment != null) {
+ newSourcesFragment.setReturnTransition(null);
+ newSourcesFragment.setExitTransition(null);
+ }
closeNewSourcesFragment(true);
}
}
@@ -642,20 +717,18 @@ public class TvOverlayManager {
}
}
- @UiThread
private void onOverlayOpened(@TvOverlayType int overlayType) {
- if (DEBUG) Log.d(TAG, "Overlay opened: 0b" + Integer.toBinaryString(overlayType));
+ if (DEBUG) Log.d(TAG, "Overlay opened: " + toBinaryString(overlayType));
mOpenedOverlays |= overlayType;
- if (DEBUG) Log.d(TAG, "Opened overlays: 0b" + Integer.toBinaryString(mOpenedOverlays));
+ if (DEBUG) Log.d(TAG, "Opened overlays: " + toBinaryString(mOpenedOverlays));
mHandler.removeMessages(MSG_OVERLAY_CLOSED);
mMainActivity.updateKeyInputFocus();
}
- @UiThread
private void onOverlayClosed(@TvOverlayType int overlayType) {
- if (DEBUG) Log.d(TAG, "Overlay closed: 0b" + Integer.toBinaryString(overlayType));
+ if (DEBUG) Log.d(TAG, "Overlay closed: " + toBinaryString(overlayType));
mOpenedOverlays &= ~overlayType;
- if (DEBUG) Log.d(TAG, "Opened overlays: 0b" + Integer.toBinaryString(mOpenedOverlays));
+ if (DEBUG) Log.d(TAG, "Opened overlays: " + toBinaryString(mOpenedOverlays));
mHandler.removeMessages(MSG_OVERLAY_CLOSED);
mMainActivity.updateKeyInputFocus();
// Show the main menu again if there are no pop-ups or banners only.
@@ -676,6 +749,11 @@ public class TvOverlayManager {
}
}
+ private String toBinaryString(int value) {
+ return String.format("0b%" + NUM_OVERLAY_TYPES + "s", Integer.toBinaryString(value))
+ .replace(' ', '0');
+ }
+
private boolean canExecuteCloseAction() {
return mMainActivity.isActivityResumed() && isOnlyBannerOrNoneOpened();
}
@@ -688,7 +766,6 @@ public class TvOverlayManager {
/**
* Runs a given {@code action} after all the overlays are closed.
*/
- @UiThread
public void runAfterOverlaysAreClosed(Runnable action) {
if (canExecuteCloseAction()) {
action.run();
@@ -783,10 +860,12 @@ public class TvOverlayManager {
showMenu(Menu.REASON_PLAY_CONTROLS_FAST_FORWARD);
break;
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
+ case KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD:
timeShiftManager.jumpToPrevious();
showMenu(Menu.REASON_PLAY_CONTROLS_JUMP_TO_PREVIOUS);
break;
case KeyEvent.KEYCODE_MEDIA_NEXT:
+ case KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD:
timeShiftManager.jumpToNext();
showMenu(Menu.REASON_PLAY_CONTROLS_JUMP_TO_NEXT);
break;
@@ -890,13 +969,15 @@ public class TvOverlayManager {
case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
case KeyEvent.KEYCODE_MEDIA_REWIND:
case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
+ case KeyEvent.KEYCODE_MEDIA_SKIP_FORWARD:
+ case KeyEvent.KEYCODE_MEDIA_SKIP_BACKWARD:
return true;
}
return false;
}
private static class TvOverlayHandler extends WeakHandler<TvOverlayManager> {
- public TvOverlayHandler(TvOverlayManager ref) {
+ TvOverlayHandler(TvOverlayManager ref) {
super(ref);
}
@@ -920,16 +1001,22 @@ public class TvOverlayManager {
}
}
- /**
- * Dummny class for the workaround of b/22631964. See {@link #closeFragment}.
- */
- public static class DummyFragment extends Fragment {
- @Override
- public @Nullable View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- final View v = new Space(inflater.getContext());
- v.setVisibility(View.GONE);
- return v;
+ private class PendingDialogAction {
+ private final String mTag;
+ private final SafeDismissDialogFragment mDialog;
+ private final boolean mKeepSidePanelHistory;
+ private final boolean mKeepProgramGuide;
+
+ PendingDialogAction(String tag, SafeDismissDialogFragment dialog,
+ boolean keepSidePanelHistory, boolean keepProgramGuide) {
+ mTag = tag;
+ mDialog = dialog;
+ mKeepSidePanelHistory = keepSidePanelHistory;
+ mKeepProgramGuide = keepProgramGuide;
+ }
+
+ void run() {
+ showDialogFragment(mTag, mDialog, mKeepSidePanelHistory, mKeepProgramGuide);
}
}
}
diff --git a/src/com/android/tv/ui/TvViewUiManager.java b/src/com/android/tv/ui/TvViewUiManager.java
index 5ad89bfa..bf874fc7 100644
--- a/src/com/android/tv/ui/TvViewUiManager.java
+++ b/src/com/android/tv/ui/TvViewUiManager.java
@@ -25,12 +25,14 @@ import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.SuppressLint;
+import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Point;
import android.hardware.display.DisplayManager;
import android.os.Handler;
+import android.os.Message;
import android.preference.PreferenceManager;
import android.util.Log;
import android.util.Property;
@@ -43,11 +45,11 @@ 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.TvOptionsManager;
import com.android.tv.data.DisplayMode;
import com.android.tv.util.TvSettings;
-import com.android.tv.util.Utils;
/**
* The TvViewUiManager is responsible for handling UI layouting and animation of main and PIP
@@ -61,6 +63,8 @@ public class TvViewUiManager {
private static final float DISPLAY_MODE_EPSILON = 0.001f;
private static final float DISPLAY_ASPECT_RATIO_EPSILON = 0.01f;
+ private static final int MSG_SET_LAYOUT_PARAMS = 1000;
+
private final Context mContext;
private final Resources mResources;
private final FrameLayout mContentView;
@@ -80,7 +84,27 @@ public class TvViewUiManager {
private final SharedPreferences mSharedPreferences;
private final TimeInterpolator mLinearOutSlowIn;
private final TimeInterpolator mFastOutLinearIn;
- private final Handler mHandler = new Handler();
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch(msg.what) {
+ case MSG_SET_LAYOUT_PARAMS:
+ FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) msg.obj;
+ if (DEBUG) {
+ Log.d(TAG, "setFixedSize: w=" + layoutParams.width + " h="
+ + layoutParams.height);
+ }
+ mTvView.setLayoutParams(layoutParams);
+ // Smooth PIP size change, we don't change surface size when
+ // isInPictureInPictureMode is true.
+ if (!Features.PICTURE_IN_PICTURE.isEnabled(mContext)
+ || !((Activity) mContext).isInPictureInPictureMode()) {
+ mTvView.setFixedSurfaceSize(layoutParams.width, layoutParams.height);
+ }
+ break;
+ }
+ }
+ };
private int mDisplayMode;
// Used to restore the previous state from ShrunkenTvView state.
private int mTvViewStartMarginBeforeShrunken;
@@ -148,21 +172,16 @@ public class TvViewUiManager {
.getDimensionPixelOffset(R.dimen.pipview_margin_horizontal);
mPipViewTopMargin = mResources.getDimensionPixelOffset(R.dimen.pipview_margin_top);
mPipViewBottomMargin = mResources.getDimensionPixelOffset(R.dimen.pipview_margin_bottom);
- mContentView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- int windowWidth = right - left;
- int windowHeight = bottom - top;
- if (windowWidth > 0 && windowHeight > 0) {
- if (mWindowWidth != windowWidth || mWindowHeight != windowHeight) {
- mWindowWidth = windowWidth;
- mWindowHeight = windowHeight;
- applyDisplayMode(mTvView.getVideoDisplayAspectRatio(), false, true);
- }
- }
+ }
+
+ public void onConfigurationChanged(final int windowWidth, final int windowHeight) {
+ if (windowWidth > 0 && windowHeight > 0) {
+ if (mWindowWidth != windowWidth || mWindowHeight != windowHeight) {
+ mWindowWidth = windowWidth;
+ mWindowHeight = windowHeight;
+ applyDisplayMode(mTvView.getVideoDisplayAspectRatio(), false, true);
}
- });
+ }
}
/**
@@ -514,18 +533,10 @@ public class TvViewUiManager {
// This block is also called when animation ends.
if (isTvViewFullScreen()) {
// When this layout is for full screen, fix the surface size after layout to make
- // resize animation smooth.
- mTvView.post(new Runnable() {
- @Override
- public void run() {
- if (DEBUG) {
- Log.d(TAG, "setFixedSize: w=" + layoutParams.width + " h="
- + layoutParams.height);
- }
- mTvView.setLayoutParams(layoutParams);
- mTvView.setFixedSurfaceSize(layoutParams.width, layoutParams.height);
- }
- });
+ // resize animation smooth. During PIP size change, the multiple messages can be
+ // queued, if we don't remove MSG_SET_LAYOUT_PARAMS.
+ mHandler.removeMessages(MSG_SET_LAYOUT_PARAMS);
+ mHandler.obtainMessage(MSG_SET_LAYOUT_PARAMS, layoutParams).sendToTarget();
} else {
mTvView.setLayoutParams(layoutParams);
}
@@ -715,6 +726,9 @@ public class TvViewUiManager {
private void applyDisplayMode(float videoDisplayAspectRatio, boolean animate,
boolean forceUpdate) {
+ if (videoDisplayAspectRatio <= 0f) {
+ videoDisplayAspectRatio = (float) mWindowWidth / mWindowHeight;
+ }
if (mAppliedDisplayedMode == mDisplayMode
&& mAppliedTvViewStartMargin == mTvViewStartMargin
&& mAppliedTvViewEndMargin == mTvViewEndMargin
@@ -743,11 +757,7 @@ public class TvViewUiManager {
+ availableAreaHeight + ")");
} else {
availableAreaRatio = (double) availableAreaWidth / availableAreaHeight;
- if (videoDisplayAspectRatio <= 0f) {
- videoRatio = (double) mWindowWidth / mWindowHeight;
- } else {
- videoRatio = videoDisplayAspectRatio;
- }
+ videoRatio = videoDisplayAspectRatio;
}
int tvViewFrameTop = (mWindowHeight - availableAreaHeight) / 2;
@@ -764,22 +774,22 @@ public class TvViewUiManager {
if (videoRatio < availableAreaRatio) {
// Y axis will be clipped.
layoutParams.width = availableAreaWidth;
- layoutParams.height = (int) (availableAreaWidth / videoRatio);
+ layoutParams.height = (int) Math.round(availableAreaWidth / videoRatio);
} else {
// X axis will be clipped.
- layoutParams.width = (int) (availableAreaHeight * videoRatio);
+ layoutParams.width = (int) Math.round(availableAreaHeight * videoRatio);
layoutParams.height = availableAreaHeight;
}
break;
case DisplayMode.MODE_NORMAL:
if (videoRatio < availableAreaRatio) {
// X axis has black area.
- layoutParams.width = (int) (availableAreaHeight * videoRatio);
+ layoutParams.width = (int) Math.round(availableAreaHeight * videoRatio);
layoutParams.height = availableAreaHeight;
} else {
// Y axis has black area.
layoutParams.width = availableAreaWidth;
- layoutParams.height = (int) (availableAreaWidth / videoRatio);
+ layoutParams.height = (int) Math.round(availableAreaWidth / videoRatio);
}
break;
}
@@ -791,9 +801,9 @@ public class TvViewUiManager {
// Set marginEnd as well because setTvViewPosition uses both start/end margin.
layoutParams.setMarginEnd(mWindowWidth - layoutParams.width - marginStart);
- setBackgroundColor(Utils.getColor(mResources, isTvViewFullScreen()
- ? R.color.tvactivity_background : R.color.tvactivity_background_on_shrunken_tvview),
- layoutParams, animate);
+ setBackgroundColor(mResources.getColor(isTvViewFullScreen()
+ ? R.color.tvactivity_background : R.color.tvactivity_background_on_shrunken_tvview,
+ null), layoutParams, animate);
setTvViewPosition(layoutParams, tvViewFrame, animate);
// Update the current display mode.
diff --git a/src/com/android/tv/ui/ViewUtils.java b/src/com/android/tv/ui/ViewUtils.java
index 5a853dcd..ac181752 100644
--- a/src/com/android/tv/ui/ViewUtils.java
+++ b/src/com/android/tv/ui/ViewUtils.java
@@ -16,8 +16,11 @@
package com.android.tv.ui;
+import android.animation.Animator;
+import android.animation.ValueAnimator;
import android.util.Log;
import android.view.View;
+import android.view.ViewGroup.LayoutParams;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -42,4 +45,49 @@ public class ViewUtils {
Log.e(TAG, "Fail to call View.setTransitionAlpha", e);
}
}
-}
+
+ /**
+ * Creates an animator in view's height
+ * @param target the {@link view} animator performs on.
+ */
+ public static Animator createHeightAnimator(
+ final View target, int initialHeight, int targetHeight) {
+ ValueAnimator animator = ValueAnimator.ofInt(initialHeight, targetHeight);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ int value = (Integer) animation.getAnimatedValue();
+ if (value == 0) {
+ if (target.getVisibility() != View.GONE) {
+ target.setVisibility(View.GONE);
+ }
+ } else {
+ if (target.getVisibility() != View.VISIBLE) {
+ target.setVisibility(View.VISIBLE);
+ }
+ setLayoutHeight(target, value);
+ }
+ }
+ });
+ return animator;
+ }
+
+ /**
+ * Gets view's layout height.
+ */
+ public static int getLayoutHeight(View view) {
+ LayoutParams layoutParams = view.getLayoutParams();
+ return layoutParams.height;
+ }
+
+ /**
+ * Sets view's layout height.
+ */
+ public static void setLayoutHeight(View view, int height) {
+ LayoutParams layoutParams = view.getLayoutParams();
+ if (height != layoutParams.height) {
+ layoutParams.height = height;
+ view.setLayoutParams(layoutParams);
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
index b52302b6..9cc54ed2 100644
--- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
+++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
@@ -165,8 +165,7 @@ public class CustomizeChannelListFragment extends SideFragment {
if (item instanceof SelectGroupItem) {
SelectGroupItem selectGroupItem = (SelectGroupItem) item;
if (selectGroupItem.mChannelItemsInGroup.size() == 1) {
- ((ChannelItem) selectGroupItem.mChannelItemsInGroup.get(0))
- .mSelectGroupItem = null;
+ selectGroupItem.mChannelItemsInGroup.get(0).mSelectGroupItem = null;
iter.remove();
}
}
diff --git a/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java b/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java
deleted file mode 100644
index 35cc18c2..00000000
--- a/src/com/android/tv/ui/sidepanel/DebugOptionFragment.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.tv.ui.sidepanel;
-
-import com.android.tv.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class DebugOptionFragment extends SideFragment {
- private static final String TRACKER_LABEL = "debug options";
-
- @Override
- protected String getTitle() {
- return getString(R.string.menu_debug_options);
- }
-
- @Override
- public String getTrackerLabel() {
- return TRACKER_LABEL;
- }
-
- @Override
- protected List<Item> getItemList() {
- List<Item> items = new ArrayList<>();
- items.add(new ActionItem(getString(R.string.item_watch_history)) {
- @Override
- protected void onSelected() {
- getMainActivity().getOverlayManager().showRecentlyWatchedDialog();
- }
- });
- return items;
- }
-}
diff --git a/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java
new file mode 100644
index 00000000..0d189cca
--- /dev/null
+++ b/src/com/android/tv/ui/sidepanel/DeveloperOptionFragment.java
@@ -0,0 +1,101 @@
+/*
+ * 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.ui.sidepanel;
+
+import android.accounts.Account;
+import android.app.Activity;
+import android.app.ApplicationErrorReport;
+import android.content.Intent;
+import android.support.annotation.NonNull;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.tv.R;
+import com.android.tv.TvApplication;
+import com.android.tv.common.BuildConfig;
+import com.android.tv.data.epg.EpgFetcher;
+import com.android.tv.experiments.Experiments;
+import com.android.tv.tuner.TunerPreferences;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Options for developers only
+ */
+public class DeveloperOptionFragment extends SideFragment {
+ private static final String TAG = "DeveloperOptionFragment";
+ private static final String TRACKER_LABEL = "debug options";
+
+ @Override
+ protected String getTitle() {
+ return getString(R.string.menu_developer_options);
+ }
+
+ @Override
+ public String getTrackerLabel() {
+ return TRACKER_LABEL;
+ }
+
+ @Override
+ protected List<Item> getItemList() {
+ List<Item> items = new ArrayList<>();
+ if (BuildConfig.ENG) {
+ items.add(new ActionItem(getString(R.string.dev_item_watch_history)) {
+ @Override
+ protected void onSelected() {
+ getMainActivity().getOverlayManager().showRecentlyWatchedDialog();
+ }
+ });
+ }
+ items.add(new ActionItem(getString(R.string.dev_item_send_feedback)) {
+ @Override
+ protected void onSelected() {
+ Intent intent = new Intent(Intent.ACTION_APP_ERROR);
+ ApplicationErrorReport report = new ApplicationErrorReport();
+ report.packageName = report.processName = getContext().getPackageName();
+ report.time = System.currentTimeMillis();
+ report.type = ApplicationErrorReport.TYPE_NONE;
+ intent.putExtra(Intent.EXTRA_BUG_REPORT, report);
+ startActivityForResult(intent, 0);
+ }
+ });
+ items.add(new SwitchItem(getString(R.string.dev_item_store_ts_on),
+ getString(R.string.dev_item_store_ts_off),
+ getString(R.string.dev_item_store_ts_description)) {
+ @Override
+ protected void onUpdate() {
+ super.onUpdate();
+ setChecked(TunerPreferences.getStoreTsStream(getContext()));
+ }
+
+ @Override
+ protected void onSelected() {
+ super.onSelected();
+ TunerPreferences.setStoreTsStream(getContext(), isChecked());
+ }
+ });
+ return items;
+ }
+
+
+ /** True if there is the dev options menu */
+ public static boolean shouldShow() {
+ return Experiments.ENABLE_DEVELOPER_FEATURES.get() || BuildConfig.ENG;
+ }
+
+}
diff --git a/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java b/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java
index b084a115..29792757 100644
--- a/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java
+++ b/src/com/android/tv/ui/sidepanel/DisplayModeFragment.java
@@ -16,7 +16,7 @@
package com.android.tv.ui.sidepanel;
-import android.app.Activity;
+import android.content.Context;
import com.android.tv.R;
import com.android.tv.data.DisplayMode;
@@ -49,8 +49,8 @@ public class DisplayModeFragment extends SideFragment {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
+ public void onAttach(Context context) {
+ super.onAttach(context);
mTvViewUiManager = getMainActivity().getTvViewUiManager();
}
diff --git a/src/com/android/tv/ui/sidepanel/SettingsFragment.java b/src/com/android/tv/ui/sidepanel/SettingsFragment.java
index 6d606014..e8033a22 100644
--- a/src/com/android/tv/ui/sidepanel/SettingsFragment.java
+++ b/src/com/android/tv/ui/sidepanel/SettingsFragment.java
@@ -65,7 +65,7 @@ public class SettingsFragment extends SideFragment {
}
}
- @Override
+ @Override
protected String getTitle() {
return getResources().getString(R.string.side_panel_title_settings);
}
@@ -80,8 +80,8 @@ public class SettingsFragment extends SideFragment {
List<Item> items = new ArrayList<>();
final Item customizeChannelListItem = new SubMenuItem(
getString(R.string.settings_channel_source_item_customize_channels),
- getString(R.string.settings_channel_source_item_customize_channels_description),
- 0, getMainActivity().getOverlayManager().getSideFragmentManager()) {
+ getString(R.string.settings_channel_source_item_customize_channels_description), 0,
+ getMainActivity().getOverlayManager().getSideFragmentManager()) {
@Override
protected SideFragment getFragment() {
return new CustomizeChannelListFragment(mCurrentChannelId);
@@ -102,8 +102,8 @@ public class SettingsFragment extends SideFragment {
customizeChannelListItem.setEnabled(false);
items.add(customizeChannelListItem);
final MainActivity activity = getMainActivity();
- boolean hasNewInput = SetupUtils.getInstance(activity).hasNewInput(
- activity.getTvInputManagerHelper());
+ boolean hasNewInput = SetupUtils.getInstance(activity)
+ .hasNewInput(activity.getTvInputManagerHelper());
items.add(new ActionItem(
getString(R.string.settings_channel_source_item_setup),
hasNewInput ? getString(R.string.settings_channel_source_item_setup_new_inputs)
@@ -115,8 +115,9 @@ public class SettingsFragment extends SideFragment {
}
});
if (PermissionUtils.hasModifyParentalControls(getMainActivity())) {
- items.add(new ActionItem(getString(R.string.settings_parental_controls),
- getString(activity.getParentalControlSettings().isParentalControlsEnabled()
+ items.add(new ActionItem(
+ getString(R.string.settings_parental_controls), getString(
+ activity.getParentalControlSettings().isParentalControlsEnabled()
? R.string.option_toggle_parental_controls_on
: R.string.option_toggle_parental_controls_off)) {
@Override
@@ -131,16 +132,16 @@ public class SettingsFragment extends SideFragment {
@Override
public void done(boolean success) {
if (success) {
- sideFragmentManager.show(new ParentalControlsFragment(),
- false);
+ sideFragmentManager
+ .show(new ParentalControlsFragment(), false);
sideFragmentManager.showSidePanel(true);
} else {
sideFragmentManager.hideAll(false);
}
}
});
- tvActivity.getOverlayManager().showDialogFragment(PinDialogFragment.DIALOG_TAG,
- fragment, true);
+ tvActivity.getOverlayManager()
+ .showDialogFragment(PinDialogFragment.DIALOG_TAG, fragment, true);
}
});
} else {
diff --git a/src/com/android/tv/ui/sidepanel/SideFragment.java b/src/com/android/tv/ui/sidepanel/SideFragment.java
index 8c37f40f..8df56cd2 100644
--- a/src/com/android/tv/ui/sidepanel/SideFragment.java
+++ b/src/com/android/tv/ui/sidepanel/SideFragment.java
@@ -16,7 +16,6 @@
package com.android.tv.ui.sidepanel;
-import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.graphics.drawable.RippleDrawable;
@@ -80,11 +79,11 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel {
}
@Override
- public void onAttach(Activity activity) {
- super.onAttach(activity);
+ public void onAttach(Context context) {
+ super.onAttach(context);
mChannelDataManager = getMainActivity().getChannelDataManager();
mProgramDataManager = getMainActivity().getProgramDataManager();
- mTracker = TvApplication.getSingletons(activity).getTracker();
+ mTracker = TvApplication.getSingletons(context).getTracker();
}
@Override
@@ -236,6 +235,9 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel {
void onSideFragmentViewDestroyed();
}
+ /**
+ * Preloads the view holders.
+ */
public static void preloadRecycledViews(Context context) {
if (sRecycledViewPool != null) {
return;
@@ -253,6 +255,13 @@ public abstract class SideFragment extends Fragment implements HasTrackerLabel {
}
}
+ /**
+ * Releases the pre-loaded view holders.
+ */
+ public static void releasePreloadedRecycledViews() {
+ sRecycledViewPool = null;
+ }
+
private static class ItemAdapter extends RecyclerView.Adapter<ItemAdapter.ViewHolder> {
private final LayoutInflater mLayoutInflater;
private List<Item> mItems;
diff --git a/src/com/android/tv/ui/sidepanel/SideFragmentManager.java b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java
index faccbc66..553cd9d7 100644
--- a/src/com/android/tv/ui/sidepanel/SideFragmentManager.java
+++ b/src/com/android/tv/ui/sidepanel/SideFragmentManager.java
@@ -22,6 +22,7 @@ import android.animation.AnimatorListenerAdapter;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
+import android.os.Handler;
import android.view.View;
import com.android.tv.R;
@@ -42,6 +43,7 @@ public class SideFragmentManager {
private final Animator mShowAnimator;
private final Animator mHideAnimator;
+ private final Handler mHandler = new Handler();
private final Runnable mHideAllRunnable = new Runnable() {
@Override
public void run() {
@@ -154,6 +156,7 @@ public class SideFragmentManager {
}
private void hideAllInternal() {
+ mHandler.removeCallbacksAndMessages(null);
if (mFragmentCount == 0) {
return;
}
@@ -192,8 +195,8 @@ public class SideFragmentManager {
* stack. If you want to empty the back stack, call {@link #hideAll}.
*/
public void hideSidePanel(boolean withAnimation) {
+ mHandler.removeCallbacks(mHideAllRunnable);
if (withAnimation) {
- mPanel.removeCallbacks(mHideAllRunnable);
Animator hideAnimator =
AnimatorInflater.loadAnimator(mActivity, R.animator.side_panel_exit);
hideAnimator.setTarget(mPanel);
@@ -213,9 +216,12 @@ public class SideFragmentManager {
return mPanel.getVisibility() == View.VISIBLE;
}
+ /**
+ * Resets the timer for hiding side fragment.
+ */
public void scheduleHideAll() {
- mPanel.removeCallbacks(mHideAllRunnable);
- mPanel.postDelayed(mHideAllRunnable, mShowDurationMillis);
+ mHandler.removeCallbacks(mHideAllRunnable);
+ mHandler.postDelayed(mHideAllRunnable, mShowDurationMillis);
}
/**
diff --git a/src/com/android/tv/util/AccountHelper.java b/src/com/android/tv/util/AccountHelper.java
new file mode 100644
index 00000000..ece13de1
--- /dev/null
+++ b/src/com/android/tv/util/AccountHelper.java
@@ -0,0 +1,111 @@
+/*
+ * 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;
+
+import android.accounts.Account;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.RemoteException;
+import android.preference.PreferenceManager;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+
+import java.util.Arrays;
+
+/**
+ * Helper methods for getting and selecting a user account.
+ */
+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";
+
+ private final Context mContext;
+ private final SharedPreferences mDefaultPreferences;
+
+ @Nullable
+ private Account mSelectedAccount;
+
+ public AccountHelper(Context context) {
+ mContext = context.getApplicationContext();
+ mDefaultPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
+ }
+
+ /**
+ * Returns the currently selected account or {@code null} if none is selected.
+ */
+ @Nullable
+ public Account getSelectedAccount() {
+ String accountId = mDefaultPreferences.getString(SELECTED_ACCOUNT, null);
+ if (accountId == null) {
+ return null;
+ }
+ if (mSelectedAccount == null || !mSelectedAccount.name.equals((accountId))) {
+ mSelectedAccount = null;
+ for (Account account : getEligibleAccounts()) {
+ if (account.name.equals(accountId)) {
+ mSelectedAccount = account;
+ break;
+ }
+ }
+ }
+ return mSelectedAccount;
+ }
+
+ /**
+ * Returns all eligible accounts .
+ */
+ private Account[] getEligibleAccounts() {
+ return new Account[0];
+ }
+
+ /**
+ * Selects the first account available.
+ *
+ * @return selected account or {@code null} if none is selected.
+ */
+ @Nullable
+ public Account selectFirstAccount() {
+ Account account = getFirstEligibleAccount();
+ if (account != null) {
+ selectAccount(account);
+ }
+ return account;
+ }
+
+ /**
+ * Gets the first account eligible.
+ *
+ * @return first account or {@code null} if none is eligible.
+ */
+ @Nullable
+ public Account getFirstEligibleAccount() {
+ Account[] accounts = getEligibleAccounts();
+ return accounts.length == 0 ? null : accounts[0];
+ }
+
+ /**
+ * Sets the given account as the selected account.
+ */
+ private void selectAccount(Account account) {
+ SharedPreferences defaultPreferences = PreferenceManager
+ .getDefaultSharedPreferences(mContext);
+ defaultPreferences.edit().putString(SELECTED_ACCOUNT, account.name).commit();
+ }
+}
+
diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java
index 7ac293fc..78243642 100644
--- a/src/com/android/tv/util/AsyncDbTask.java
+++ b/src/com/android/tv/util/AsyncDbTask.java
@@ -19,6 +19,7 @@ package com.android.tv.util;
import android.content.ContentResolver;
import android.database.Cursor;
import android.media.tv.TvContract;
+import android.media.tv.TvContract.Programs;
import android.net.Uri;
import android.os.AsyncTask;
import android.support.annotation.MainThread;
@@ -30,6 +31,7 @@ import android.util.Range;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.dvr.RecordedProgram;
import java.util.ArrayList;
import java.util.List;
@@ -52,7 +54,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
private static final String TAG = "AsyncDbTask";
private static final boolean DEBUG = false;
- public static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory(
+ private static final NamedThreadFactory THREAD_FACTORY = new NamedThreadFactory(
AsyncDbTask.class.getSimpleName());
private static final ExecutorService DB_EXECUTOR = Executors
.newSingleThreadExecutor(THREAD_FACTORY);
@@ -160,7 +162,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
@Override
public String toString() {
- return this.getClass().getSimpleName() + "(" + mUri + ")";
+ return this.getClass().getName() + "(" + mUri + ")";
}
}
@@ -172,10 +174,17 @@ public abstract class AsyncDbTask<Params, Progress, Result>
* @param <T> the type of result returned in a list by {@link #onQuery(Cursor)}
*/
public abstract static class AsyncQueryListTask<T> extends AsyncQueryTask<List<T>> {
+ private final CursorFilter mFilter;
public AsyncQueryListTask(ContentResolver contentResolver, Uri uri, String[] projection,
String selection, String[] selectionArgs, String orderBy) {
+ this(contentResolver, uri, projection, selection, selectionArgs, orderBy, null);
+ }
+
+ public AsyncQueryListTask(ContentResolver contentResolver, Uri uri, String[] projection,
+ String selection, String[] selectionArgs, String orderBy, CursorFilter filter) {
super(contentResolver, uri, projection, selection, selectionArgs, orderBy);
+ mFilter = filter;
}
@Override
@@ -186,6 +195,9 @@ public abstract class AsyncDbTask<Params, Progress, Result>
// This is guaranteed to never call onPostExecute because the task is canceled.
return null;
}
+ if (mFilter != null && !mFilter.filter(c)) {
+ continue;
+ }
T t = fromCursor(c);
result.add(t);
}
@@ -273,6 +285,41 @@ public abstract class AsyncDbTask<Params, Progress, Result>
}
/**
+ * Gets an {@link List} of {@link Program}s from {@link TvContract.Programs#CONTENT_URI}.
+ */
+ public abstract static class AsyncProgramQueryTask extends AsyncQueryListTask<Program> {
+ public AsyncProgramQueryTask(ContentResolver contentResolver) {
+ super(contentResolver, Programs.CONTENT_URI, Program.PROJECTION, null, null, null);
+ }
+
+ public AsyncProgramQueryTask(ContentResolver contentResolver, Uri uri, String selection,
+ String[] selectionArgs, String sortOrder, CursorFilter filter) {
+ super(contentResolver, uri, Program.PROJECTION, selection, selectionArgs, sortOrder,
+ filter);
+ }
+
+ @Override
+ protected final Program fromCursor(Cursor c) {
+ return Program.fromCursor(c);
+ }
+ }
+
+ /**
+ * Gets an {@link List} of {@link TvContract.RecordedPrograms}s.
+ */
+ public abstract static class AsyncRecordedProgramQueryTask
+ extends AsyncQueryListTask<RecordedProgram> {
+ public AsyncRecordedProgramQueryTask(ContentResolver contentResolver, Uri uri) {
+ super(contentResolver, uri, RecordedProgram.PROJECTION, null, null, null);
+ }
+
+ @Override
+ protected final RecordedProgram fromCursor(Cursor c) {
+ return RecordedProgram.fromCursor(c);
+ }
+ }
+
+ /**
* Execute the task on the {@link #DB_EXECUTOR} thread.
*/
@SafeVarargs
@@ -286,7 +333,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
* TvContract#buildProgramsUriForChannel(long, long, long)}. If the {@code period} is
* {@code null}, then all the programs is queried.
*/
- public static class LoadProgramsForChannelTask extends AsyncQueryListTask<Program> {
+ public static class LoadProgramsForChannelTask extends AsyncProgramQueryTask {
protected final Range<Long> mPeriod;
protected final long mChannelId;
@@ -296,16 +343,11 @@ public abstract class AsyncDbTask<Params, Progress, Result>
? TvContract.buildProgramsUriForChannel(channelId)
: TvContract.buildProgramsUriForChannel(channelId, period.getLower(),
period.getUpper()),
- Program.PROJECTION, null, null, null);
+ null, null, null, null);
mPeriod = period;
mChannelId = channelId;
}
- @Override
- protected final Program fromCursor(Cursor c) {
- return Program.fromCursor(c);
- }
-
public long getChannelId() {
return mChannelId;
}
@@ -314,4 +356,25 @@ public abstract class AsyncDbTask<Params, Progress, Result>
return mPeriod;
}
}
+
+ /**
+ * Gets a single {@link Program} from {@link TvContract.Programs#CONTENT_URI}.
+ */
+ public static class AsyncQueryProgramTask extends AsyncQueryItemTask<Program> {
+
+ public AsyncQueryProgramTask(ContentResolver contentResolver, long programId) {
+ super(contentResolver, TvContract.buildProgramUri(programId), Program.PROJECTION, null,
+ null, null);
+ }
+
+ @Override
+ protected Program fromCursor(Cursor c) {
+ return Program.fromCursor(c);
+ }
+ }
+
+ /**
+ * An interface which filters the row.
+ */
+ public interface CursorFilter extends Filter<Cursor> { }
}
diff --git a/src/com/android/tv/util/BitmapUtils.java b/src/com/android/tv/util/BitmapUtils.java
index 78b77e65..d45a8dce 100644
--- a/src/com/android/tv/util/BitmapUtils.java
+++ b/src/com/android/tv/util/BitmapUtils.java
@@ -33,6 +33,7 @@ import java.io.BufferedInputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
@@ -84,9 +85,20 @@ public final class BitmapUtils {
return null;
}
+ Uri uri = Uri.parse(uriString).normalizeScheme();
+ boolean isResourceUri = isContentResolverUri(uri);
+ URLConnection urlConnection = null;
InputStream inputStream = null;
try {
- inputStream = new BufferedInputStream(getInputStream(context, uriString));
+ if (isResourceUri) {
+ inputStream = context.getContentResolver().openInputStream(uri);
+ } else {
+ // If the URLConnection is HttpURLConnection, disconnect() should be called
+ // explicitly.
+ urlConnection = getUrlConnection(uriString);
+ inputStream = urlConnection.getInputStream();
+ }
+ inputStream = new BufferedInputStream(inputStream);
inputStream.mark(MARK_READ_LIMIT);
// Check the bitmap dimensions.
@@ -98,13 +110,16 @@ public final class BitmapUtils {
try {
inputStream.reset();
} catch (IOException e) {
- if (DEBUG) {
- Log.i(TAG, "Failed to rewind stream: " + uriString, e);
- }
+ if (DEBUG) Log.i(TAG, "Failed to rewind stream: " + uriString, e);
// Failed to rewind the stream, try to reopen it.
- close(inputStream);
- inputStream = getInputStream(context, uriString);
+ close(inputStream, urlConnection);
+ if (isResourceUri) {
+ inputStream = context.getContentResolver().openInputStream(uri);
+ } else {
+ urlConnection = getUrlConnection(uriString);
+ inputStream = urlConnection.getInputStream();
+ }
}
// Decode the bitmap possibly resizing it.
@@ -126,10 +141,17 @@ public final class BitmapUtils {
Log.e(TAG, "Failed to open stream: " + uriString, e);
return null;
} finally {
- close(inputStream);
+ close(inputStream, urlConnection);
}
}
+ private static URLConnection getUrlConnection(String uriString) throws IOException {
+ URLConnection urlConnection = new URL(uriString).openConnection();
+ urlConnection.setConnectTimeout(CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION);
+ urlConnection.setReadTimeout(READ_TIMEOUT_MS_FOR_URLCONNECTION);
+ return urlConnection;
+ }
+
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth,
int reqHeight) {
return calculateInSampleSize(options.outWidth, options.outHeight, reqWidth, reqHeight);
@@ -142,20 +164,6 @@ public final class BitmapUtils {
return Math.max(1, Integer.highestOneBit(ratio));
}
- private static InputStream getInputStream(Context context, String uriString)
- throws IOException {
- Uri uri = Uri.parse(uriString).normalizeScheme();
- if (isContentResolverUri(uri)) {
- return context.getContentResolver().openInputStream(uri);
- } else {
- // TODO We should disconnect() the URLConnection in order to allow connection reuse.
- URLConnection urlConnection = new URL(uriString).openConnection();
- urlConnection.setConnectTimeout(CONNECTION_TIMEOUT_MS_FOR_URLCONNECTION);
- urlConnection.setReadTimeout(READ_TIMEOUT_MS_FOR_URLCONNECTION);
- return urlConnection.getInputStream();
- }
- }
-
private static boolean isContentResolverUri(Uri uri) {
String scheme = uri.getScheme();
return ContentResolver.SCHEME_CONTENT.equals(scheme)
@@ -163,7 +171,7 @@ public final class BitmapUtils {
|| ContentResolver.SCHEME_FILE.equals(scheme);
}
- private static void close(Closeable closeable) {
+ private static void close(Closeable closeable, URLConnection urlConnection) {
if (closeable != null) {
try {
closeable.close();
@@ -172,6 +180,9 @@ public final class BitmapUtils {
Log.w(TAG,"Error closing " + closeable, e);
}
}
+ if (urlConnection instanceof HttpURLConnection) {
+ ((HttpURLConnection) urlConnection).disconnect();
+ }
}
/**
diff --git a/src/com/android/tv/util/CompositeComparator.java b/src/com/android/tv/util/CompositeComparator.java
new file mode 100644
index 00000000..47cf50fe
--- /dev/null
+++ b/src/com/android/tv/util/CompositeComparator.java
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import java.util.Comparator;
+
+/**
+ * A comparator which runs multiple comparators sequentially.
+ */
+public class CompositeComparator<T> implements Comparator<T> {
+ private final Comparator<T>[] mComparators;
+
+ @SafeVarargs
+ public CompositeComparator(Comparator<T>... comparators) {
+ mComparators = comparators;
+ }
+
+ @Override
+ public int compare(T lhs, T rhs) {
+ for (Comparator<T> comparator : mComparators) {
+ int result = comparator.compare(lhs, rhs);
+ if (result != 0) {
+ return result;
+ }
+ }
+ return 0;
+ }
+}
diff --git a/src/com/android/tv/util/Filter.java b/src/com/android/tv/util/Filter.java
new file mode 100644
index 00000000..d5b356e4
--- /dev/null
+++ b/src/com/android/tv/util/Filter.java
@@ -0,0 +1,27 @@
+/*
+ * 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;
+
+/**
+ * Interface to decide whether an input is filtered out or not.
+ */
+public interface Filter<T> {
+ /**
+ * Returns true, if {@code input} is acceptable.
+ */
+ boolean filter(T input);
+}
diff --git a/src/com/android/tv/util/ImageCache.java b/src/com/android/tv/util/ImageCache.java
index db64d4c9..b413c364 100644
--- a/src/com/android/tv/util/ImageCache.java
+++ b/src/com/android/tv/util/ImageCache.java
@@ -145,6 +145,16 @@ public class ImageCache implements MemoryManageable {
}
/**
+ * Remove from memory cache.
+ *
+ * @param key Unique identifier for which item to remove
+ * @return The previous bitmap mapped by key
+ */
+ public ScaledBitmapInfo remove(String key) {
+ return mMemoryCache.remove(key);
+ }
+
+ /**
* Calculates the memory cache size based on a percentage of the max available VM memory. Eg.
* setting percent to 0.2 would set the memory cache to one fifth of the available memory.
* Throws {@link IllegalArgumentException} if percent is < 0.05 or > .8. memCacheSize is stored
diff --git a/src/com/android/tv/util/ImageLoader.java b/src/com/android/tv/util/ImageLoader.java
index ed0fd54d..04bb478a 100644
--- a/src/com/android/tv/util/ImageLoader.java
+++ b/src/com/android/tv/util/ImageLoader.java
@@ -64,8 +64,7 @@ public final class ImageLoader {
private static final ThreadFactory sThreadFactory = new NamedThreadFactory("ImageLoader");
- private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<Runnable>(
- 128);
+ private static final BlockingQueue<Runnable> sPoolWorkQueue = new LinkedBlockingQueue<>(128);
/**
* An private {@link Executor} that can be used to execute tasks in parallel.
@@ -380,7 +379,7 @@ public final class ImageLoader {
public LoadTvInputLogoTask(Context context, ImageCache cache, TvInputInfo info) {
super(context,
cache,
- info.getId() + "-logo",
+ getTvInputLogoKey(info.getId()),
context.getResources()
.getDimensionPixelSize(R.dimen.channel_banner_input_logo_size),
context.getResources()
@@ -402,6 +401,13 @@ public final class ImageLoader {
}
return BitmapUtils.createScaledBitmapInfo(getKey(), original, mMaxWidth, mMaxHeight);
}
+
+ /**
+ * Returns key of TV input logo.
+ */
+ public static String getTvInputLogoKey(String inputId) {
+ return inputId + "-logo";
+ }
}
private static synchronized Handler getMainHandler() {
diff --git a/src/com/android/tv/util/LocationUtils.java b/src/com/android/tv/util/LocationUtils.java
new file mode 100644
index 00000000..8e3b59e9
--- /dev/null
+++ b/src/com/android/tv/util/LocationUtils.java
@@ -0,0 +1,120 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.location.Address;
+import android.location.Geocoder;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
+import android.os.Bundle;
+import android.util.Log;
+
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * A utility class to get the current location.
+ */
+public class LocationUtils {
+ private static final String TAG = "LocationUtils";
+ private static final boolean DEBUG = false;
+
+ private static Context sApplicationContext;
+ private static Address sAddress;
+ private static IOException sError;
+
+ /**
+ * Checks the current location.
+ */
+ public static synchronized Address getCurrentAddress(Context context) throws IOException,
+ SecurityException {
+ if (sAddress != null) {
+ return sAddress;
+ }
+ if (sError != null) {
+ throw sError;
+ }
+ if (sApplicationContext == null) {
+ sApplicationContext = context.getApplicationContext();
+ }
+ LocationUtilsHelper.startLocationUpdates();
+ return null;
+ }
+
+ private static void updateAddress(Location location) {
+ if (DEBUG) Log.d(TAG, "Updating address with " + location);
+ if (location == null) {
+ return;
+ }
+ Geocoder geocoder = new Geocoder(sApplicationContext, Locale.getDefault());
+ try {
+ List<Address> addresses = geocoder.getFromLocation(
+ location.getLatitude(), location.getLongitude(), 1);
+ if (addresses != null) {
+ sAddress = addresses.get(0);
+ if (DEBUG) Log.d(TAG, "Got " + sAddress);
+ } else {
+ if (DEBUG) Log.d(TAG, "No address returned");
+ }
+ sError = null;
+ } catch (IOException e) {
+ Log.w(TAG, "Error in updating address", e);
+ sError = e;
+ }
+ }
+
+ private LocationUtils() { }
+
+ private static class LocationUtilsHelper {
+ private static final LocationListener LOCATION_LISTENER = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ updateAddress(location);
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) { }
+
+ @Override
+ public void onProviderEnabled(String provider) { }
+
+ @Override
+ public void onProviderDisabled(String provider) { }
+ };
+
+ private static LocationManager sLocationManager;
+
+ public static void startLocationUpdates() {
+ if (sLocationManager == null) {
+ sLocationManager = (LocationManager) sApplicationContext.getSystemService(
+ Context.LOCATION_SERVICE);
+ try {
+ sLocationManager.requestLocationUpdates(
+ LocationManager.NETWORK_PROVIDER, 1000, 10, LOCATION_LISTENER, null);
+ } catch (SecurityException e) {
+ // Enables requesting the location updates again.
+ sLocationManager = null;
+ throw e;
+ }
+ }
+ }
+ }
+}
diff --git a/src/com/android/tv/util/OnboardingUtils.java b/src/com/android/tv/util/OnboardingUtils.java
index 3dcc324d..3040020e 100644
--- a/src/com/android/tv/util/OnboardingUtils.java
+++ b/src/com/android/tv/util/OnboardingUtils.java
@@ -36,12 +36,12 @@ public final class OnboardingUtils {
private static final String PREF_KEY_ONBOARDING_VERSION_CODE = "pref_onbaording_versionCode";
private static final int ONBOARDING_VERSION = 1;
- private static final String MERCHANT_COLLECTION_URL_STRING =
- "TODO: put a market link to show TV input apps";
+ private static final String MERCHANT_COLLECTION_URL_STRING = getMerchantCollectionUrl();
+
/**
- * Intent to show merchant collection in play store.
+ * Intent to show merchant collection in online store.
*/
- public static final Intent PLAY_STORE_INTENT = new Intent(Intent.ACTION_VIEW,
+ public static final Intent ONLINE_STORE_INTENT = new Intent(Intent.ACTION_VIEW,
Uri.parse(MERCHANT_COLLECTION_URL_STRING));
/**
@@ -112,4 +112,11 @@ public final class OnboardingUtils {
return TvApplication.getSingletons(context).getTvInputManagerHelper()
.getTvInputInfos(true, false).size() > 0;
}
+
+ /**
+ * Returns merchant collection URL.
+ */
+ private static String getMerchantCollectionUrl() {
+ return "TODO: add a merchant collection url";
+ }
}
diff --git a/src/com/android/tv/util/PermissionUtils.java b/src/com/android/tv/util/PermissionUtils.java
index f39dba81..453885a4 100644
--- a/src/com/android/tv/util/PermissionUtils.java
+++ b/src/com/android/tv/util/PermissionUtils.java
@@ -2,69 +2,49 @@ package com.android.tv.util;
import android.content.Context;
import android.content.pm.PackageManager;
-import android.os.Build;
/**
* Util class to handle permissions.
*/
public class PermissionUtils {
+ /**
+ * Permission to read the TV listings.
+ */
+ public static final String PERMISSION_READ_TV_LISTINGS = "android.permission.READ_TV_LISTINGS";
+
private static Boolean sHasAccessAllEpgPermission;
private static Boolean sHasAccessWatchedHistoryPermission;
private static Boolean sHasModifyParentalControlsPermission;
public static boolean hasAccessAllEpg(Context context) {
if (sHasAccessAllEpgPermission == null) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- sHasAccessAllEpgPermission = context.checkSelfPermission(
- "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA")
- == PackageManager.PERMISSION_GRANTED;
- } else {
- sHasAccessAllEpgPermission = context.getPackageManager().checkPermission(
- "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA",
- context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
- }
+ sHasAccessAllEpgPermission = context.checkSelfPermission(
+ "com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA")
+ == PackageManager.PERMISSION_GRANTED;
}
return sHasAccessAllEpgPermission;
}
public static boolean hasAccessWatchedHistory(Context context) {
if (sHasAccessWatchedHistoryPermission == null) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- sHasAccessWatchedHistoryPermission = context.checkSelfPermission(
- "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
- == PackageManager.PERMISSION_GRANTED;
- } else {
- sHasAccessWatchedHistoryPermission = context.getPackageManager().checkPermission(
- "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS",
- context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
- }
+ sHasAccessWatchedHistoryPermission = context.checkSelfPermission(
+ "com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS")
+ == PackageManager.PERMISSION_GRANTED;
}
return sHasAccessWatchedHistoryPermission;
}
public static boolean hasModifyParentalControls(Context context) {
if (sHasModifyParentalControlsPermission == null) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- sHasModifyParentalControlsPermission = context.checkSelfPermission(
- "android.permission.MODIFY_PARENTAL_CONTROLS")
- == PackageManager.PERMISSION_GRANTED;
- } else {
- sHasModifyParentalControlsPermission = context.getPackageManager().checkPermission(
- "android.permission.MODIFY_PARENTAL_CONTROLS",
- context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
- }
+ sHasModifyParentalControlsPermission = context.checkSelfPermission(
+ "android.permission.MODIFY_PARENTAL_CONTROLS")
+ == PackageManager.PERMISSION_GRANTED;
}
return sHasModifyParentalControlsPermission;
}
public static boolean hasReadTvListings(Context context) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return context.checkSelfPermission("android.permission.READ_TV_LISTINGS")
- == PackageManager.PERMISSION_GRANTED;
- } else {
- return context.getPackageManager().checkPermission(
- "android.permission.MODIFY_PARENTAL_CONTROLS",
- context.getPackageName()) == PackageManager.PERMISSION_GRANTED;
- }
+ return context.checkSelfPermission(PERMISSION_READ_TV_LISTINGS)
+ == PackageManager.PERMISSION_GRANTED;
}
}
diff --git a/src/com/android/tv/util/PipInputManager.java b/src/com/android/tv/util/PipInputManager.java
index 03bdc681..2c51d5a0 100644
--- a/src/com/android/tv/util/PipInputManager.java
+++ b/src/com/android/tv/util/PipInputManager.java
@@ -149,6 +149,7 @@ public class PipInputManager {
if (mStarted) {
return;
}
+ mStarted = true;
mInputManager.addCallback(mTvInputCallback);
mChannelTuner.addListener(mChannelTunerListener);
initializePipInputList();
@@ -161,6 +162,7 @@ public class PipInputManager {
if (!mStarted) {
return;
}
+ mStarted = false;
mInputManager.removeCallback(mTvInputCallback);
mChannelTuner.removeListener(mChannelTunerListener);
mPipInputMap.clear();
diff --git a/src/com/android/tv/util/RecurringRunner.java b/src/com/android/tv/util/RecurringRunner.java
index 5e65715e..4135bd4e 100644
--- a/src/com/android/tv/util/RecurringRunner.java
+++ b/src/com/android/tv/util/RecurringRunner.java
@@ -52,13 +52,13 @@ public final class RecurringRunner {
mRunnable = runnable;
mOnStopRunnable = onStopRunnable;
mIntervalMs = intervalMs;
- if (DEBUG) Log.i(TAG, "Delaying " + (intervalMs / 1000.0) + " seconds");
mName = runnable.getClass().getCanonicalName();
+ if (DEBUG) Log.i(TAG, " Delaying " + mName + " " + (intervalMs / 1000.0) + " seconds");
mHandler = new Handler(mContext.getMainLooper());
}
public void start() {
- SoftPreconditions.checkState(!mRunning, TAG, "start is called twice.");
+ SoftPreconditions.checkState(!mRunning, TAG, mName + " start is called twice.");
if (mRunning) {
return;
}
@@ -107,7 +107,7 @@ public final class RecurringRunner {
if (!posted) {
Log.w(TAG, "Scheduling a future run of " + mName + " at " + new Date(next) + "failed");
}
- if (DEBUG) Log.i(TAG, "Actual delay is " + (delay / 1000.0) + " seconds.");
+ if (DEBUG) Log.i(TAG, "Actual delay of " + mName + " is " + (delay / 1000.0) + " seconds.");
}
private SharedPreferences getSharedPreferences() {
diff --git a/src/com/android/tv/util/SearchManagerHelper.java b/src/com/android/tv/util/SearchManagerHelper.java
index 5ec1b455..b6e34d7a 100644
--- a/src/com/android/tv/util/SearchManagerHelper.java
+++ b/src/com/android/tv/util/SearchManagerHelper.java
@@ -18,7 +18,6 @@ package com.android.tv.util;
import android.app.SearchManager;
import android.content.Context;
-import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
@@ -52,15 +51,8 @@ public final class SearchManagerHelper {
public void launchAssistAction() {
try {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- SearchManager.class.getDeclaredMethod(
- "launchLegacyAssist", String.class, Integer.TYPE, Bundle.class).invoke(
- mSearchManager, null, UserHandle.myUserId(), null);
- } else {
- SearchManager.class.getDeclaredMethod(
- "launchAssistAction", Integer.TYPE, String.class, Integer.TYPE).invoke(
- mSearchManager, 0, null, UserHandle.myUserId());
- }
+ SearchManager.class.getDeclaredMethod("launchLegacyAssist", String.class, Integer.TYPE,
+ Bundle.class).invoke(mSearchManager, null, UserHandle.myUserId(), null);
} catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException
| InvocationTargetException e) {
Log.e(TAG, "Fail to call SearchManager.launchAssistAction", e);
diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java
index a7d9c423..8223a81c 100644
--- a/src/com/android/tv/util/SetupUtils.java
+++ b/src/com/android/tv/util/SetupUtils.java
@@ -20,10 +20,11 @@ import android.content.ComponentName;
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.media.tv.TvContract;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
-import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
@@ -36,6 +37,9 @@ 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.data.epg.EpgFetcher;
+import com.android.tv.experiments.Experiments;
+import com.android.tv.tuner.tvinput.TunerTvInputService;
import java.util.Collections;
import java.util.HashSet;
@@ -64,23 +68,23 @@ public class SetupUtils {
private final Set<String> mSetUpInputs;
private final Set<String> mRecognizedInputs;
private boolean mIsFirstTune;
- private final String mUsbTunerInputId;
+ private final String mTunerInputId;
private SetupUtils(TvApplication tvApplication) {
mTvApplication = tvApplication;
mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(tvApplication);
mSetUpInputs = new ArraySet<>();
mSetUpInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_SET_UP_INPUTS,
- Collections.<String>emptySet()));
+ Collections.emptySet()));
mKnownInputs = new ArraySet<>();
mKnownInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_KNOWN_INPUTS,
- Collections.<String>emptySet()));
+ Collections.emptySet()));
mRecognizedInputs = new ArraySet<>();
mRecognizedInputs.addAll(mSharedPreferences.getStringSet(PREF_KEY_RECOGNIZED_INPUTS,
mKnownInputs));
mIsFirstTune = mSharedPreferences.getBoolean(PREF_KEY_IS_FIRST_TUNE, true);
- mUsbTunerInputId = TvContract.buildInputId(new ComponentName(tvApplication,
- com.android.usbtuner.tvinput.UsbTunerTvInputService.class));
+ mTunerInputId = TvContract.buildInputId(new ComponentName(tvApplication,
+ TunerTvInputService.class));
}
/**
@@ -264,15 +268,11 @@ public class SetupUtils {
* @param context The Context used for granting permission.
*/
public static void grantEpgPermissionToSetUpPackages(Context context) {
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- // Can't grant permission.
- return;
- }
-
// Find all already-verified packages.
Set<String> setUpPackages = new HashSet<>();
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
- for (String input : sp.getStringSet(PREF_KEY_SET_UP_INPUTS, Collections.<String>emptySet())) {
+ for (String input : sp.getStringSet(PREF_KEY_SET_UP_INPUTS,
+ Collections.<String>emptySet())) {
if (!TextUtils.isEmpty(input)) {
ComponentName componentName = ComponentName.unflattenFromString(input);
if (componentName != null) {
@@ -293,21 +293,18 @@ public class SetupUtils {
* @param packageName The name of the package to give permission.
*/
public static void grantEpgPermission(Context context, String packageName) {
- // TvProvider allows granting of Uri permissions starting from MNC.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (DEBUG) {
- Log.d(TAG, "grantEpgPermission(context=" + context + ", packageName=" + packageName
- + ")");
- }
- try {
- int modeFlags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
- | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
- context.grantUriPermission(packageName, TvContract.Channels.CONTENT_URI, modeFlags);
- context.grantUriPermission(packageName, TvContract.Programs.CONTENT_URI, modeFlags);
- } catch (SecurityException e) {
- Log.e(TAG, "Either TvProvider does not allow granting of Uri permissions or the app"
- + " does not have permission.", e);
- }
+ if (DEBUG) {
+ Log.d(TAG, "grantEpgPermission(context=" + context + ", packageName=" + packageName
+ + ")");
+ }
+ try {
+ int modeFlags = Intent.FLAG_GRANT_WRITE_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
+ context.grantUriPermission(packageName, TvContract.Channels.CONTENT_URI, modeFlags);
+ context.grantUriPermission(packageName, TvContract.Programs.CONTENT_URI, modeFlags);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Either TvProvider does not allow granting of Uri permissions or the app"
+ + " does not have permission.", e);
}
}
@@ -335,17 +332,31 @@ public class SetupUtils {
// A USB tuner device can be temporarily unplugged. We do not remove the USB tuner input
// from the known inputs so that the input won't appear as a new input whenever the user
// plugs in the USB tuner device again.
- removedInputList.remove(mUsbTunerInputId);
+ removedInputList.remove(mTunerInputId);
if (!removedInputList.isEmpty()) {
+ boolean inputPackageDeleted = false;
for (String input : removedInputList) {
- mRecognizedInputs.remove(input);
- mSetUpInputs.remove(input);
- mKnownInputs.remove(input);
+ try {
+ // Just after booting, input list from TvInputManager are not reliable.
+ // So we need to double-check package existence. b/29034900
+ mTvApplication.getPackageManager().getPackageInfo(
+ ComponentName.unflattenFromString(input)
+ .getPackageName(), PackageManager.GET_ACTIVITIES);
+ Log.i(TAG, "TV input (" + input + ") is removed but package is not deleted");
+ } catch (NameNotFoundException e) {
+ Log.i(TAG, "TV input (" + input + ") and its package are removed");
+ mRecognizedInputs.remove(input);
+ mSetUpInputs.remove(input);
+ mKnownInputs.remove(input);
+ inputPackageDeleted = true;
+ }
+ }
+ if (inputPackageDeleted) {
+ mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs)
+ .putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs)
+ .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply();
}
- mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs)
- .putStringSet(PREF_KEY_KNOWN_INPUTS, mKnownInputs)
- .putStringSet(PREF_KEY_RECOGNIZED_INPUTS, mRecognizedInputs).apply();
}
}
@@ -353,7 +364,7 @@ public class SetupUtils {
* Called when an setup is done. Once it is called, {@link #isSetupDone} returns {@code true}
* for {@code inputId}.
*/
- public void onSetupDone(String inputId) {
+ private void onSetupDone(String inputId) {
SoftPreconditions.checkState(inputId != null);
if (DEBUG) Log.d(TAG, "onSetupDone: input=" + inputId);
if (!mRecognizedInputs.contains(inputId)) {
@@ -371,5 +382,13 @@ public class SetupUtils {
mSetUpInputs.add(inputId);
mSharedPreferences.edit().putStringSet(PREF_KEY_SET_UP_INPUTS, mSetUpInputs).apply();
}
+ // Start fetching program guide data for internal tuners.
+ Context context = mTvApplication.getApplicationContext();
+ if (Utils.isInternalTvInput(context, inputId)) {
+ if (context.checkSelfPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION)
+ == PackageManager.PERMISSION_GRANTED && Experiments.CLOUD_EPG.get()) {
+ EpgFetcher.getInstance(context).startImmediately();
+ }
+ }
}
}
diff --git a/src/com/android/tv/util/SystemProperties.java b/src/com/android/tv/util/SystemProperties.java
index 235161b6..e737f233 100644
--- a/src/com/android/tv/util/SystemProperties.java
+++ b/src/com/android/tv/util/SystemProperties.java
@@ -36,12 +36,6 @@ public final class SystemProperties {
"tv_allow_strict_mode", true);
/**
- * Allow Strict death penalty for eng builds.
- */
- public static final BooleanSystemProperty ALLOW_DEATH_PENALTY = new BooleanSystemProperty(
- "tv_allow_death_penalty", true);
-
- /**
* When true {@link android.view.KeyEvent}s are logged. Defaults to false.
*/
public static final BooleanSystemProperty LOG_KEYEVENT = new BooleanSystemProperty(
diff --git a/src/com/android/tv/util/TimeShiftUtils.java b/src/com/android/tv/util/TimeShiftUtils.java
new file mode 100644
index 00000000..238d0e74
--- /dev/null
+++ b/src/com/android/tv/util/TimeShiftUtils.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import java.util.concurrent.TimeUnit;
+
+// TODO: move related functions in TimeShiftManger here.
+/**
+ * A class that includes convenience methods for time shift plays.
+ */
+public class TimeShiftUtils {
+ private static final String TAG = "TimeShiftUtils";
+ private static final boolean DEBUG = false;
+
+ private static final long SHORT_PROGRAM_THRESHOLD_MILLIS = TimeUnit.MINUTES.toMillis(46);
+ private static final int[] SHORT_PROGRAM_SPEED_FACTORS = new int[] {2, 4, 12, 48};
+ private static final int[] LONG_PROGRAM_SPEED_FACTORS = new int[] {2, 8, 32, 128};
+
+ /**
+ * The maximum play speed level support by time shift play. In other words, the valid
+ * speed levels are ranged from 0 to MAX_SPEED_LEVEL (included).
+ */
+ public static final int MAX_SPEED_LEVEL = SHORT_PROGRAM_SPEED_FACTORS.length - 1;
+
+ /**
+ * Returns real speeds used in time shift play. This method is only for fast-forwarding and
+ * rewinding. The normal play speed is not addressed here.
+ *
+ * @param speedLevel the valid value is ranged from 0 to {@link MAX_SPPED_LEVEL}.
+ * @param programDurationMillis the length of program under playing.
+ * @throws IndexOutOfBoundsException if speed level is out of its range.
+ */
+ public static int getPlaybackSpeed(int speedLevel, long programDurationMillis)
+ throws IndexOutOfBoundsException {
+ return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS) ?
+ LONG_PROGRAM_SPEED_FACTORS[speedLevel] : SHORT_PROGRAM_SPEED_FACTORS[speedLevel];
+ }
+
+ /**
+ * Returns the maxium possible play speed according to the program's length.
+ * @param programDurationMillis the length of program under playing.
+ */
+ public static int getMaxPlaybackSpeed(long programDurationMillis) {
+ return (programDurationMillis > SHORT_PROGRAM_THRESHOLD_MILLIS) ?
+ LONG_PROGRAM_SPEED_FACTORS[MAX_SPEED_LEVEL]
+ : SHORT_PROGRAM_SPEED_FACTORS[MAX_SPEED_LEVEL];
+ }
+}
+
diff --git a/src/com/android/tv/util/ToastUtils.java b/src/com/android/tv/util/ToastUtils.java
new file mode 100644
index 00000000..34346b2a
--- /dev/null
+++ b/src/com/android/tv/util/ToastUtils.java
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+import android.content.Context;
+import android.support.annotation.MainThread;
+import android.widget.Toast;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A utility class for the toast message.
+ */
+public class ToastUtils {
+ private static WeakReference<Toast> sToast;
+
+ /**
+ * Shows the toast message after canceling the previous one.
+ */
+ @MainThread
+ public static void show(Context context, CharSequence text, int duration) {
+ if (sToast != null && sToast.get() != null) {
+ sToast.get().cancel();
+ }
+ Toast toast = Toast.makeText(context, text, duration);
+ toast.show();
+ sToast = new WeakReference<>(toast);
+ }
+}
diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java
index b4149637..121f56ed 100644
--- a/src/com/android/tv/util/TvInputManagerHelper.java
+++ b/src/com/android/tv/util/TvInputManagerHelper.java
@@ -26,6 +26,7 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.Log;
+import com.android.tv.Features;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
@@ -37,21 +38,12 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.Set;
public class TvInputManagerHelper {
private static final String TAG = "TvInputManagerHelper";
private static final boolean DEBUG = false;
-
- // 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 HashSet<>();
-
- static {
- BUNDLED_PACKAGE_SET.add("com.android.tv");
- BUNDLED_PACKAGE_SET.add("com.android.usbtuner");
- }
+ private static final String[] PARTNER_TUNER_INPUT_PREFIX_BLACKLIST = {
+ };
private final Context mContext;
private final TvInputManager mTvInputManager;
@@ -62,6 +54,9 @@ public class TvInputManagerHelper {
@Override
public void onInputStateChanged(String inputId, int state) {
if (DEBUG) Log.d(TAG, "onInputStateChanged " + inputId + " state=" + state);
+ if (isInBlackList(inputId)) {
+ return;
+ }
mInputStateMap.put(inputId, state);
for (TvInputCallback callback : mCallbacks) {
callback.onInputStateChanged(inputId, state);
@@ -71,6 +66,9 @@ public class TvInputManagerHelper {
@Override
public void onInputAdded(String inputId) {
if (DEBUG) Log.d(TAG, "onInputAdded " + inputId);
+ if (isInBlackList(inputId)) {
+ return;
+ }
TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
if (info != null) {
mInputMap.put(inputId, info);
@@ -93,16 +91,34 @@ public class TvInputManagerHelper {
for (TvInputCallback callback : mCallbacks) {
callback.onInputRemoved(inputId);
}
+ ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
+ inputId));
}
@Override
public void onInputUpdated(String inputId) {
if (DEBUG) Log.d(TAG, "onInputUpdated " + inputId);
+ if (isInBlackList(inputId)) {
+ return;
+ }
TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
mInputMap.put(inputId, info);
for (TvInputCallback callback : mCallbacks) {
callback.onInputUpdated(inputId);
}
+ ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
+ inputId));
+ }
+
+ @Override
+ public void onTvInputInfoUpdated(TvInputInfo inputInfo) {
+ if (DEBUG) Log.d(TAG, "onTvInputInfoUpdated " + inputInfo);
+ mInputMap.put(inputInfo.getId(), inputInfo);
+ for (TvInputCallback callback : mCallbacks) {
+ callback.onTvInputInfoUpdated(inputInfo);
+ }
+ ImageCache.getInstance().remove(ImageLoader.LoadTvInputLogoTask.getTvInputLogoKey(
+ inputInfo.getId()));
}
};
@@ -134,6 +150,9 @@ public class TvInputManagerHelper {
for (TvInputInfo input : mTvInputManager.getTvInputList()) {
if (DEBUG) Log.d(TAG, "Input detected " + input);
String inputId = input.getId();
+ if (isInBlackList(inputId)) {
+ continue;
+ }
mInputMap.put(inputId, input);
int state = mTvInputManager.getInputState(inputId);
mInputStateMap.put(inputId, state);
@@ -204,9 +223,8 @@ public class TvInputManagerHelper {
* Is the input one known bundled inputs not written by OEM/SOCs.
*/
public boolean isBundledInput(TvInputInfo inputInfo) {
- return inputInfo != null
- && BUNDLED_PACKAGE_SET.contains(
- inputInfo.getServiceInfo().applicationInfo.packageName);
+ return inputInfo != null && Utils.isInBundledPackageSet(inputInfo.getServiceInfo()
+ .applicationInfo.packageName);
}
/**
@@ -236,10 +254,7 @@ public class TvInputManagerHelper {
public boolean hasTvInputInfo(String inputId) {
SoftPreconditions.checkState(mStarted, TAG,
"hasTvInputInfo() called before TvInputManagerHelper was started.");
- if (!mStarted) {
- return false;
- }
- return !TextUtils.isEmpty(inputId) && mInputMap.get(inputId) != null;
+ return mStarted && !TextUtils.isEmpty(inputId) && mInputMap.get(inputId) != null;
}
public TvInputInfo getTvInputInfo(String inputId) {
@@ -306,6 +321,18 @@ public class TvInputManagerHelper {
return mContentRatingsManager;
}
+ private boolean isInBlackList(String inputId) {
+ if (!Features.USE_PARTNER_INPUT_BLACKLIST.isEnabled(mContext)) {
+ return false;
+ }
+ for (String disabledTunerInputPrefix : PARTNER_TUNER_INPUT_PREFIX_BLACKLIST) {
+ if (inputId.contains(disabledTunerInputPrefix)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Default comparator for TvInputInfo.
*
diff --git a/src/com/android/tv/util/TvProviderUriMatcher.java b/src/com/android/tv/util/TvProviderUriMatcher.java
new file mode 100644
index 00000000..749e4aa3
--- /dev/null
+++ b/src/com/android/tv/util/TvProviderUriMatcher.java
@@ -0,0 +1,72 @@
+/*
+ * 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;
+
+import android.content.UriMatcher;
+import android.media.tv.TvContract;
+import android.net.Uri;
+import android.support.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Utility class to aid in matching URIs in TvProvider.
+ */
+public class TvProviderUriMatcher {
+ private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({MATCH_CHANNEL, MATCH_CHANNEL_ID, MATCH_PROGRAM, MATCH_PROGRAM_ID,
+ MATCH_RECORDED_PROGRAM, MATCH_RECORDED_PROGRAM_ID, MATCH_WATCHED_PROGRAM_ID})
+ private @interface TvProviderUriMatchCode {}
+ /** The code for the channels URI. */
+ public static final int MATCH_CHANNEL = 1;
+ /** The code for the channel URI. */
+ public static final int MATCH_CHANNEL_ID = 2;
+ /** The code for the programs URI. */
+ public static final int MATCH_PROGRAM = 3;
+ /** The code for the program URI. */
+ public static final int MATCH_PROGRAM_ID = 4;
+ /** The code for the recorded programs URI. */
+ public static final int MATCH_RECORDED_PROGRAM = 5;
+ /** The code for the recorded program URI. */
+ public static final int MATCH_RECORDED_PROGRAM_ID = 6;
+ /** The code for the watched program URI. */
+ public static final int MATCH_WATCHED_PROGRAM_ID = 7;
+ static {
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "channel", MATCH_CHANNEL);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "channel/#", MATCH_CHANNEL_ID);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "program", MATCH_PROGRAM);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "program/#", MATCH_PROGRAM_ID);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "recorded_program", MATCH_RECORDED_PROGRAM);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "recorded_program/#", MATCH_RECORDED_PROGRAM_ID);
+ URI_MATCHER.addURI(TvContract.AUTHORITY, "watched_program/#", MATCH_WATCHED_PROGRAM_ID);
+ }
+
+ private TvProviderUriMatcher() { }
+
+ /**
+ * Try to match against the path in a url.
+ *
+ * @see UriMatcher#match
+ */
+ @SuppressWarnings("WrongConstant")
+ @TvProviderUriMatchCode public static int match(Uri uri) {
+ return URI_MATCHER.match(uri);
+ }
+}
diff --git a/src/com/android/tv/util/TvSettings.java b/src/com/android/tv/util/TvSettings.java
index 133fdd72..97ff59d6 100644
--- a/src/com/android/tv/util/TvSettings.java
+++ b/src/com/android/tv/util/TvSettings.java
@@ -34,9 +34,6 @@ import java.util.Set;
public final class TvSettings {
private TvSettings() {}
- public static final String PREFS_FILE = "settings";
- public static final String PREF_TV_WATCH_LOGGING_ENABLED = "tv_watch_logging_enabled";
- public static final String PREF_CLOSED_CAPTION_ENABLED = "is_cc_enabled"; // boolean value
public static final String PREF_DISPLAY_MODE = "display_mode"; // int value
public static final String PREF_PIP_LAYOUT = "pip_layout"; // int value
public static final String PREF_PIP_SIZE = "pip_size"; // int value
@@ -49,7 +46,6 @@ public final class TvSettings {
public @interface PipSound {}
public static final int PIP_SOUND_MAIN = 0;
public static final int PIP_SOUND_PIP_WINDOW = PIP_SOUND_MAIN + 1;
- public static final int PIP_SOUND_LAST = PIP_SOUND_PIP_WINDOW;
// PIP layouts
@Retention(RetentionPolicy.SOURCE)
@@ -225,7 +221,7 @@ public final class TvSettings {
private static Set<String> getContentRatingSystemSet(Context context) {
return new HashSet<>(PreferenceManager.getDefaultSharedPreferences(context)
- .getStringSet(PREF_CONTENT_RATING_SYSTEMS, Collections.<String>emptySet()));
+ .getStringSet(PREF_CONTENT_RATING_SYSTEMS, Collections.emptySet()));
}
@ContentRatingLevel
diff --git a/src/com/android/tv/util/TvTrackInfoUtils.java b/src/com/android/tv/util/TvTrackInfoUtils.java
index 3006f963..c004f001 100644
--- a/src/com/android/tv/util/TvTrackInfoUtils.java
+++ b/src/com/android/tv/util/TvTrackInfoUtils.java
@@ -50,8 +50,12 @@ public class TvTrackInfoUtils {
if (rhs == null) {
return 1;
}
- boolean rhsLangMatch = Utils.isEqualLanguage(rhs.getLanguage(), language);
- boolean lhsLangMatch = Utils.isEqualLanguage(lhs.getLanguage(), language);
+ // Assumes {@code null} language matches to any language since it means user hasn't
+ // selected any track before or selected a track without language information.
+ boolean rhsLangMatch = language == null || Utils.isEqualLanguage(rhs.getLanguage(),
+ language);
+ boolean lhsLangMatch = language == null || Utils.isEqualLanguage(lhs.getLanguage(),
+ language);
if (rhsLangMatch) {
if (lhsLangMatch) {
boolean rhsCountMatch = rhs.getAudioChannelCount() == channelCount;
diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java
index a763fe58..99d34431 100644
--- a/src/com/android/tv/util/Utils.java
+++ b/src/com/android/tv/util/Utils.java
@@ -23,35 +23,37 @@ import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.content.res.Resources.Theme;
import android.database.Cursor;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
+import android.media.tv.TvContract.Programs.Genres;
import android.media.tv.TvInputInfo;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
-import android.os.Build;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
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 android.widget.Toast;
+import com.android.tv.ApplicationSingletons;
import com.android.tv.R;
import com.android.tv.TvApplication;
+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 java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
@@ -69,13 +71,17 @@ 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");
+ private static final SimpleDateFormat ISO_8601 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ",
+ Locale.US);
public static final String EXTRA_KEY_KEYCODE = "keycode";
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";
- public static final String EXTRA_KEY_RECORDING_URI = "recording_uri";
+ public static final String EXTRA_KEY_RECORDED_PROGRAM_ID = "recorded_program_id";
+ public static final String EXTRA_KEY_RECORDED_PROGRAM_SEEK_TIME = "recorded_program_seek_time";
+ public static final String EXTRA_KEY_RECORDED_PROGRAM_PIN_CHECKED =
+ "recorded_program_pin_checked";
// Query parameter in the intent of starting MainActivity.
public static final String PARAM_SOURCE = "source";
@@ -87,6 +93,10 @@ public class Utils {
private static final String PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT =
"last_watched_channel_id_for_input_";
private static final String PREF_KEY_LAST_WATCHED_CHANNEL_URI = "last_watched_channel_uri";
+ private static final String PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID =
+ "last_watched_tuner_input_id";
+ private static final String PREF_KEY_RECORDING_FAILED_REASONS =
+ "recording_failed_reasons";
private static final int VIDEO_SD_WIDTH = 704;
private static final int VIDEO_SD_HEIGHT = 480;
@@ -103,6 +113,18 @@ public class Utils {
private static final int AUDIO_CHANNEL_SURROUND_6 = 6;
private static final int AUDIO_CHANNEL_SURROUND_8 = 8;
+ private static final long RECORDING_FAILED_REASON_NONE = 0;
+ 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),
@@ -166,13 +188,34 @@ public class Utils {
throw new IllegalArgumentException("channelId should be equal to or larger than 0");
}
PreferenceManager.getDefaultSharedPreferences(context).edit()
- .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, channelId).apply();
- PreferenceManager.getDefaultSharedPreferences(context).edit()
+ .putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, channelId)
.putLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID_FOR_INPUT + channel.getInputId(),
- channelId).apply();
+ channelId)
+ .putString(PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID, channel.getInputId())
+ .apply();
}
}
+ /**
+ * Sets recording failed reason.
+ */
+ public static void setRecordingFailedReason(Context context, int reason) {
+ long reasons = getRecordingFailedReasons(context) | 0x1 << reason;
+ PreferenceManager.getDefaultSharedPreferences(context).edit()
+ .putLong(PREF_KEY_RECORDING_FAILED_REASONS, reasons)
+ .apply();
+ }
+
+ /**
+ * Clears recording failed reason.
+ */
+ public static void clearRecordingFailedReason(Context context, int reason) {
+ long reasons = getRecordingFailedReasons(context) & ~(0x1 << reason);
+ PreferenceManager.getDefaultSharedPreferences(context).edit()
+ .putLong(PREF_KEY_RECORDING_FAILED_REASONS, reasons)
+ .apply();
+ }
+
public static long getLastWatchedChannelId(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context)
.getLong(PREF_KEY_LAST_WATCHED_CHANNEL_ID, Channel.INVALID_ID);
@@ -189,6 +232,28 @@ public class Utils {
}
/**
+ * Returns the last watched tuner input id.
+ */
+ public static String getLastWatchedTunerInputId(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getString(PREF_KEY_LAST_WATCHED_TUNER_INPUT_ID, null);
+ }
+
+ private static long getRecordingFailedReasons(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context)
+ .getLong(PREF_KEY_RECORDING_FAILED_REASONS,
+ RECORDING_FAILED_REASON_NONE);
+ }
+
+ /**
+ * Checks do recording failed reason exist.
+ */
+ public static boolean hasRecordingFailedReason(Context context, int reason) {
+ long reasons = getRecordingFailedReasons(context);
+ return (reasons & 0x1 << reason) != 0;
+ }
+
+ /**
* Returns {@code true}, if {@code uri} specifies an input, which is usually generated
* from {@link TvContract#buildChannelsUriForInput}.
*/
@@ -286,11 +351,25 @@ public class Utils {
}
@VisibleForTesting
- static String getDurationString(Context context, long baseMillis,
- long startUtcMillis, long endUtcMillis, boolean useShortFormat, int flag) {
- flag |= DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_TIME
+ static String getDurationString(Context context, long baseMillis, long startUtcMillis,
+ long endUtcMillis, boolean useShortFormat, int flag) {
+ return getDurationString(context, startUtcMillis, endUtcMillis,
+ useShortFormat, !isInGivenDay(baseMillis, startUtcMillis), true, flag);
+ }
+
+ /**
+ * Returns duration string according to the time format, may not contain date information.
+ * Note: At least one of showDate and showTime should be true.
+ */
+ public static String getDurationString(Context context, long startUtcMillis, long endUtcMillis,
+ boolean useShortFormat, boolean showDate, boolean showTime, int flag) {
+ flag |= DateUtils.FORMAT_ABBREV_MONTH
| ((useShortFormat) ? DateUtils.FORMAT_NUMERIC_DATE : 0);
- if (!isInGivenDay(baseMillis, startUtcMillis)) {
+ SoftPreconditions.checkArgument(showTime || showDate);
+ if (showTime) {
+ flag |= DateUtils.FORMAT_SHOW_TIME;
+ }
+ if (showDate) {
flag |= DateUtils.FORMAT_SHOW_DATE;
}
if (startUtcMillis != endUtcMillis && useShortFormat) {
@@ -300,13 +379,17 @@ public class Utils {
if (!isInGivenDay(startUtcMillis, endUtcMillis - 1)
&& endUtcMillis - startUtcMillis < TimeUnit.HOURS.toMillis(11)) {
// Do not show date for short format.
- // Extracting a day is needed because {@link DateUtils@formatDateRange}
- // adds date if the duration covers multiple days.
+ // Subtracting one day is needed because {@link DateUtils@formatDateRange}
+ // automatically shows date if the duration covers multiple days.
return DateUtils.formatDateRange(context,
startUtcMillis, endUtcMillis - TimeUnit.DAYS.toMillis(1), flag);
}
}
- return DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis, flag);
+ // Workaround of b/28740989.
+ // Add 1 msec to endUtcMillis to avoid DateUtils' bug with a duration of 12:00AM~12:00AM.
+ String dateRange = DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis, flag);
+ return startUtcMillis == endUtcMillis || dateRange.contains("–") ? dateRange
+ : DateUtils.formatDateRange(context, startUtcMillis, endUtcMillis + 1, flag);
}
@VisibleForTesting
@@ -321,6 +404,39 @@ public class Utils {
== Utils.floorTime(subjectTimeInMillis + offset, DAY_IN_MS);
}
+ /**
+ * Calculate how many days between two milliseconds.
+ */
+ public static int computeDateDifference(long startTimeMs, long endTimeMs) {
+ Calendar calFrom = Calendar.getInstance();
+ Calendar calTo = Calendar.getInstance();
+ calFrom.setTime(new Date(startTimeMs));
+ calTo.setTime(new Date(endTimeMs));
+ resetCalendar(calFrom);
+ resetCalendar(calTo);
+ return (int) ((calTo.getTimeInMillis() - calFrom.getTimeInMillis()) / ONE_DAY_MS);
+ }
+
+ private static void resetCalendar(Calendar cal) {
+ cal.set(Calendar.HOUR_OF_DAY, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ cal.set(Calendar.MILLISECOND, 0);
+ }
+
+ /**
+ * Returns the last millisecond of a day which the millis belongs to.
+ */
+ public static long getLastMillisecondOfDay(long millis) {
+ Calendar calender = Calendar.getInstance();
+ calender.setTime(new Date(millis));
+ calender.set(Calendar.HOUR_OF_DAY, 23);
+ calender.set(Calendar.MINUTE, 59);
+ calender.set(Calendar.SECOND, 59);
+ calender.set(Calendar.MILLISECOND, 999);
+ return calender.getTimeInMillis();
+ }
+
public static String getAspectRatioString(int width, int height) {
if (width == 0 || height == 0) {
return "";
@@ -510,9 +626,27 @@ public class Utils {
/**
* Converts time in milliseconds to a String.
+ *
+ * @param fullFormat {@code true} for returning date string with a full format
+ * (e.g., Mon Aug 15 20:08:35 GMT 2016). {@code false} for a short format,
+ * {e.g., [8/15/16] 8:08 AM}, in which date information would only appears
+ * when the target time is not today.
+ */
+ public static String toTimeString(long timeMillis, boolean fullFormat) {
+ if (fullFormat) {
+ return new Date(timeMillis).toString();
+ } else {
+ long currentTime = System.currentTimeMillis();
+ return (String) DateUtils.formatSameDayTime(timeMillis, System.currentTimeMillis(),
+ SimpleDateFormat.SHORT, SimpleDateFormat.SHORT);
+ }
+ }
+
+ /**
+ * Converts time in milliseconds to a String.
*/
public static String toTimeString(long timeMillis) {
- return new Date(timeMillis).toString();
+ return toTimeString(timeMillis, true);
}
/**
@@ -566,57 +700,7 @@ public class Utils {
* @return index >= 0 && index < collection.size().
*/
public static boolean isIndexValid(@Nullable Collection<?> collection, int index) {
- return collection == null ? false : index >= 0 && index < collection.size();
- }
-
- /**
- * Returns a color integer associated with a particular resource ID.
- *
- * @see #getColor(android.content.res.Resources,int,Theme)
- */
- public static int getColor(Resources res, int id) {
- return getColor(res, id, null);
- }
-
- /**
- * Returns a color integer associated with a particular resource ID.
- *
- * <p>In M version, {@link android.content.res.Resources#getColor(int)} was deprecated and
- * {@link android.content.res.Resources#getColor(int,Theme)} was newly added.
- *
- * @see android.content.res.Resources#getColor(int)
- */
- public static int getColor(Resources res, int id, @Nullable Theme theme) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return res.getColor(id, theme);
- } else {
- return res.getColor(id);
- }
- }
-
- /**
- * Returns a color state list associated with a particular resource ID.
- *
- * @see #getColorStateList(android.content.res.Resources,int,Theme)
- */
- public static ColorStateList getColorStateList(Resources res, int id) {
- return getColorStateList(res, id, null);
- }
-
- /**
- * Returns a color state list associated with a particular resource ID.
- *
- * <p>In M version, {@link android.content.res.Resources#getColorStateList(int)} was deprecated
- * and {@link android.content.res.Resources#getColorStateList(int,Theme)} was newly added.
- *
- * @see android.content.res.Resources#getColorStateList(int)
- */
- public static ColorStateList getColorStateList(Resources res, int id, @Nullable Theme theme) {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- return res.getColorStateList(id, theme);
- } else {
- return res.getColorStateList(id);
- }
+ return collection != null && (index >= 0 && index < collection.size());
}
/**
@@ -632,15 +716,26 @@ public class Utils {
}
/**
+ * Checks where there is any internal TV input.
+ */
+ public static boolean hasInternalTvInputs(Context context, boolean tunerInputOnly) {
+ for (TvInputInfo input : TvApplication.getSingletons(context).getTvInputManagerHelper()
+ .getTvInputInfos(true, tunerInputOnly)) {
+ if (isInternalTvInput(context, input.getId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Returns the internal TV inputs.
*/
public static List<TvInputInfo> getInternalTvInputs(Context context, boolean tunerInputOnly) {
List<TvInputInfo> inputs = new ArrayList<>();
- String contextPackageName = context.getPackageName();
for (TvInputInfo input : TvApplication.getSingletons(context).getTvInputManagerHelper()
.getTvInputInfos(true, tunerInputOnly)) {
- if (contextPackageName.equals(ComponentName.unflattenFromString(input.getId())
- .getPackageName())) {
+ if (isInternalTvInput(context, input.getId())) {
inputs.add(input);
}
}
@@ -656,10 +751,113 @@ public class Utils {
}
/**
- * Shows a toast message to notice that the current feature is a developer feature.
+ * Returns the TV input for the given {@code program}.
+ */
+ @Nullable
+ public static TvInputInfo getTvInputInfoForProgram(Context context, Program program) {
+ if (!Program.isValid(program)) {
+ return null;
+ }
+ return getTvInputInfoForChannelId(context, program.getChannelId());
+ }
+
+ /**
+ * Returns the TV input for the given channel ID.
+ */
+ @Nullable
+ public static TvInputInfo getTvInputInfoForChannelId(Context context, long channelId) {
+ ApplicationSingletons appSingletons = TvApplication.getSingletons(context);
+ Channel channel = appSingletons.getChannelDataManager().getChannel(channelId);
+ if (channel == null) {
+ return null;
+ }
+ return appSingletons.getTvInputManagerHelper().getTvInputInfo(channel.getInputId());
+ }
+
+ /**
+ * Returns the {@link TvInputInfo} for the given input ID.
*/
- public static void showToastMessageForDeveloperFeature(Context context) {
- Toast.makeText(context, "This feature is for developer preview.", Toast.LENGTH_SHORT)
- .show();
+ @Nullable
+ public static TvInputInfo getTvInputInfoForInputId(Context context, String inputId) {
+ 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)) {
+ return null;
+ }
+ return getCanonicalGenreIds(Genres.decode(genres));
+ }
+
+ /**
+ * Returns the canonical genre ID's from the {@code genres}.
+ */
+ public static int[] getCanonicalGenreIds(String[] canonicalGenres) {
+ if (canonicalGenres != null && canonicalGenres.length > 0) {
+ int[] results = new int[canonicalGenres.length];
+ int i = 0;
+ for (String canonicalGenre : canonicalGenres) {
+ int genreId = GenreItems.getId(canonicalGenre);
+ if (genreId == GenreItems.ID_ALL_CHANNELS) {
+ // Skip if the genre is unknown.
+ continue;
+ }
+ results[i++] = genreId;
+ }
+ if (i < canonicalGenres.length) {
+ results = Arrays.copyOf(results, i);
+ }
+ return results;
+ }
+ return null;
+ }
+
+ /**
+ * Returns the canonical genres for database.
+ */
+ public static String getCanonicalGenre(int[] canonicalGenreIds) {
+ if (canonicalGenreIds == null || canonicalGenreIds.length == 0) {
+ return null;
+ }
+ String[] genres = new String[canonicalGenreIds.length];
+ for (int i = 0; i < canonicalGenreIds.length; ++i) {
+ genres[i] = GenreItems.getCanonicalGenre(canonicalGenreIds[i]);
+ }
+ return Genres.encode(genres);
}
}
diff --git a/tests/common/res/drawable-xhdpi/blue.png b/tests/common/res/drawable-xhdpi/blue.png
index dd2044ca..a0c4eced 100644
--- a/tests/common/res/drawable-xhdpi/blue.png
+++ b/tests/common/res/drawable-xhdpi/blue.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/blue_small.png b/tests/common/res/drawable-xhdpi/blue_small.png
index 22394ebb..ae9c9608 100644
--- a/tests/common/res/drawable-xhdpi/blue_small.png
+++ b/tests/common/res/drawable-xhdpi/blue_small.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/crash_test_android_logo.png b/tests/common/res/drawable-xhdpi/crash_test_android_logo.png
index 2442cf04..5d6d5826 100644
--- a/tests/common/res/drawable-xhdpi/crash_test_android_logo.png
+++ b/tests/common/res/drawable-xhdpi/crash_test_android_logo.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/green.png b/tests/common/res/drawable-xhdpi/green.png
index 8306b9c3..54f1319a 100644
--- a/tests/common/res/drawable-xhdpi/green.png
+++ b/tests/common/res/drawable-xhdpi/green.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/green_large.png b/tests/common/res/drawable-xhdpi/green_large.png
index 77bbb231..928c348b 100644
--- a/tests/common/res/drawable-xhdpi/green_large.png
+++ b/tests/common/res/drawable-xhdpi/green_large.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/red.png b/tests/common/res/drawable-xhdpi/red.png
index 89f889b9..4ddd30e3 100644
--- a/tests/common/res/drawable-xhdpi/red.png
+++ b/tests/common/res/drawable-xhdpi/red.png
Binary files differ
diff --git a/tests/common/res/drawable-xhdpi/red_large.png b/tests/common/res/drawable-xhdpi/red_large.png
index c52a1242..58682b15 100644
--- a/tests/common/res/drawable-xhdpi/red_large.png
+++ b/tests/common/res/drawable-xhdpi/red_large.png
Binary files differ
diff --git a/tests/common/src/com/android/tv/MockTvApplication.java b/tests/common/src/com/android/tv/MockTvApplication.java
deleted file mode 100644
index 24c47a6a..00000000
--- a/tests/common/src/com/android/tv/MockTvApplication.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package com.android.tv;
-
-import android.test.mock.MockApplication;
-
-import com.android.tv.analytics.Analytics;
-import com.android.tv.analytics.Tracker;
-import com.android.tv.data.ChannelDataManager;
-import com.android.tv.data.ProgramDataManager;
-import com.android.tv.dvr.DvrDataManager;
-import com.android.tv.dvr.DvrManager;
-import com.android.tv.dvr.DvrSessionManager;
-import com.android.tv.util.TvInputManagerHelper;
-
-/**
- * A mock TV Application used for testing.
- */
-public class MockTvApplication extends MockApplication implements ApplicationSingletons {
- public final ApplicationSingletons mDelegate;
-
- public MockTvApplication(ApplicationSingletons delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public DvrManager getDvrManager() {
- return mDelegate.getDvrManager();
- }
-
- @Override
- public DvrSessionManager getDvrSessionManger() {
- return mDelegate.getDvrSessionManger();
- }
-
- @Override
- public Analytics getAnalytics() {
- return mDelegate.getAnalytics();
- }
-
- @Override
- public Tracker getTracker() {
- return mDelegate.getTracker();
- }
-
- @Override
- public ChannelDataManager getChannelDataManager() {
- return mDelegate.getChannelDataManager();
- }
-
- @Override
- public ProgramDataManager getProgramDataManager() {
- return mDelegate.getProgramDataManager();
- }
-
- @Override
- public DvrDataManager getDvrDataManager() {
- return mDelegate.getDvrDataManager();
- }
-
- @Override
- public TvInputManagerHelper getTvInputManagerHelper() {
- return mDelegate.getTvInputManagerHelper();
- }
-
- @Override
- public MainActivityWrapper getMainActivityWrapper() {
- return mDelegate.getMainActivityWrapper();
- }
-}
diff --git a/tests/common/src/com/android/tv/input/TunerHelper.java b/tests/common/src/com/android/tv/input/TunerHelper.java
new file mode 100644
index 00000000..126d5027
--- /dev/null
+++ b/tests/common/src/com/android/tv/input/TunerHelper.java
@@ -0,0 +1,155 @@
+/*
+ * 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.input;
+
+import android.net.Uri;
+import android.support.annotation.Nullable;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A class to manage fake tuners for the tune and the recording.
+ */
+public class TunerHelper {
+ private static final String TAG = "TunerHelper";
+ private static final boolean DEBUG = false;
+
+ private final List<Tuner> mTuners = new ArrayList<>();
+ private final int mTunerCount;
+
+ public TunerHelper(int tunerCount) {
+ mTunerCount = tunerCount;
+ }
+
+ /**
+ * Checks whether there are available tuners for the recording.
+ */
+ public boolean tunerAvailableForRecording() {
+ if (mTuners.size() < mTunerCount) {
+ return true;
+ }
+ for (Tuner tuner : mTuners) {
+ if (!tuner.recording) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks whether there is available tuner.
+ * If there's available tuner, it is assigned to the channel.
+ */
+ public boolean tune(@Nullable Uri channelUri, boolean forRecording) {
+ if (channelUri == null) {
+ return false;
+ }
+ for (Tuner tuner : mTuners) {
+ // Find available tuner which is used only for the recording.
+ if (tuner.channelUri.equals(channelUri)) {
+ if (!forRecording && !tuner.tuning) {
+ tuner.tuning = true;
+ return true;
+ } else if (forRecording && !tuner.recording) {
+ tuner.recording = true;
+ return true;
+ }
+ }
+ }
+ if (mTuners.size() < mTunerCount) {
+ // Assign new tuner.
+ mTuners.add(new Tuner(channelUri, forRecording));
+ return true;
+ }
+ Log.i(TAG, "No available tuners. tuner count: " + mTunerCount);
+ return false;
+ }
+
+ /**
+ * Releases the tuner which was being used for the tune.
+ */
+ public void stopTune(@Nullable Uri channelUri) {
+ if (channelUri == null) {
+ return;
+ }
+ Tuner candidate = null;
+ Iterator<Tuner> iterator = mTuners.iterator();
+ while (iterator.hasNext()) {
+ Tuner tuner = iterator.next();
+ if (tuner.channelUri.equals(channelUri) && tuner.tuning) {
+ if (tuner.recording) {
+ // A tuner which is used both for the tune and recording is the candidate.
+ candidate = tuner;
+ } else {
+ // Remove the tuner which is used only for the tune.
+ if (DEBUG) Log.d(TAG, "Removed tuner for tune");
+ iterator.remove();
+ return;
+ }
+ }
+ }
+ if (candidate != null) {
+ candidate.tuning = false;
+ }
+ }
+
+ /**
+ * Releases the tuner which was being used for the recording.
+ */
+ public void stopRecording(@Nullable Uri channelUri) {
+ if (channelUri == null) {
+ return;
+ }
+ Tuner candidate = null;
+ Iterator<Tuner> iterator = mTuners.iterator();
+ while (iterator.hasNext()) {
+ Tuner tuner = iterator.next();
+ if (tuner.channelUri.equals(channelUri)) {
+ if (tuner.recording) {
+ if (tuner.tuning) {
+ // A tuner which is used both for the tune and recording is the candidate.
+ candidate = tuner;
+ } else {
+ // Remove the tuner which is used only for the recording.
+ iterator.remove();
+ return;
+ }
+ } else {
+ Log.w(TAG, "Tuner found for " + channelUri + ", but not used for recording");
+ }
+ }
+ }
+ if (candidate != null) {
+ candidate.recording = false;
+ }
+ }
+
+ private static class Tuner {
+ public final Uri channelUri;
+ public boolean tuning;
+ public boolean recording;
+
+ public Tuner (Uri channelUri, boolean forRecording) {
+ this.channelUri = channelUri;
+ this.tuning = !forRecording;
+ this.recording = forRecording;
+ }
+ }
+}
diff --git a/tests/common/src/com/android/tv/testing/ChannelInfo.java b/tests/common/src/com/android/tv/testing/ChannelInfo.java
index 99430461..af1c9891 100644
--- a/tests/common/src/com/android/tv/testing/ChannelInfo.java
+++ b/tests/common/src/com/android/tv/testing/ChannelInfo.java
@@ -42,8 +42,6 @@ public final class ChannelInfo {
* If this is specify for logo, it will be selected randomly including null.
*/
public static final String GENERATE_LOGO = "GEN";
- // If the logo is set to {@link ChannelInfo#GENERATE_LOGO}, pick one randomly from this list.
- private static final int[] LOGOS_RES = {0, R.drawable.crash_test_android_logo};
public static final String[] PROJECTION = {
TvContract.Channels.COLUMN_DISPLAY_NUMBER,
diff --git a/tests/common/src/com/android/tv/testing/ChannelUtils.java b/tests/common/src/com/android/tv/testing/ChannelUtils.java
index e09843a6..bfb766d6 100644
--- a/tests/common/src/com/android/tv/testing/ChannelUtils.java
+++ b/tests/common/src/com/android/tv/testing/ChannelUtils.java
@@ -23,7 +23,6 @@ import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
import android.net.Uri;
import android.os.AsyncTask;
-import android.os.Build;
import android.support.annotation.WorkerThread;
import android.text.TextUtils;
import android.util.Log;
@@ -96,22 +95,20 @@ public class ChannelUtils {
} else {
values.putNull(Channels.COLUMN_VIDEO_FORMAT);
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (!TextUtils.isEmpty(channel.appLinkText)) {
- values.put(Channels.COLUMN_APP_LINK_TEXT, channel.appLinkText);
- }
- if (channel.appLinkColor != 0) {
- values.put(Channels.COLUMN_APP_LINK_COLOR, channel.appLinkColor);
- }
- if (!TextUtils.isEmpty(channel.appLinkPosterArtUri)) {
- values.put(Channels.COLUMN_APP_LINK_POSTER_ART_URI, channel.appLinkPosterArtUri);
- }
- if (!TextUtils.isEmpty(channel.appLinkIconUri)) {
- values.put(Channels.COLUMN_APP_LINK_ICON_URI, channel.appLinkIconUri);
- }
- if (!TextUtils.isEmpty(channel.appLinkIntentUri)) {
- values.put(Channels.COLUMN_APP_LINK_INTENT_URI, channel.appLinkIntentUri);
- }
+ if (!TextUtils.isEmpty(channel.appLinkText)) {
+ values.put(Channels.COLUMN_APP_LINK_TEXT, channel.appLinkText);
+ }
+ if (channel.appLinkColor != 0) {
+ values.put(Channels.COLUMN_APP_LINK_COLOR, channel.appLinkColor);
+ }
+ if (!TextUtils.isEmpty(channel.appLinkPosterArtUri)) {
+ values.put(Channels.COLUMN_APP_LINK_POSTER_ART_URI, channel.appLinkPosterArtUri);
+ }
+ if (!TextUtils.isEmpty(channel.appLinkIconUri)) {
+ values.put(Channels.COLUMN_APP_LINK_ICON_URI, channel.appLinkIconUri);
+ }
+ if (!TextUtils.isEmpty(channel.appLinkIntentUri)) {
+ values.put(Channels.COLUMN_APP_LINK_INTENT_URI, channel.appLinkIntentUri);
}
Long rowId = existingChannelsMap.get(channel.originalNetworkId);
Uri uri;
diff --git a/tests/common/src/com/android/tv/testing/Constants.java b/tests/common/src/com/android/tv/testing/Constants.java
index 83d8d293..4c9cb5fb 100644
--- a/tests/common/src/com/android/tv/testing/Constants.java
+++ b/tests/common/src/com/android/tv/testing/Constants.java
@@ -36,8 +36,6 @@ public final class Constants {
.setVideoFrameRate(50).build();
public static final TvTrackInfo SVGA_VIDEO_TRACK = new TvTrackInfo.Builder(
TvTrackInfo.TYPE_VIDEO, "SVGA Video").setVideoHeight(600).setVideoWidth(800).build();
- public static final TvTrackInfo GENERIC_VIDEO_TRACK = new TvTrackInfo.Builder(
- TvTrackInfo.TYPE_VIDEO, "Generic Video").build();
private Constants() {
}
diff --git a/tests/common/src/com/android/tv/testing/ProgramInfo.java b/tests/common/src/com/android/tv/testing/ProgramInfo.java
index 3f1f30ce..b1aaea6b 100644
--- a/tests/common/src/com/android/tv/testing/ProgramInfo.java
+++ b/tests/common/src/com/android/tv/testing/ProgramInfo.java
@@ -184,7 +184,7 @@ public final class ProgramInfo {
*/
public ProgramInfo build(Context context, int index) {
if (!GEN_TITLE.equals(title)
- && !GEN_EPISODE.equals(episode)
+ && episode == null
&& !GEN_POSTER.equals(posterArtUri)
&& durationMs != GEN_DURATION
&& !GEN_GENRE.equals(genre)) {
@@ -193,8 +193,8 @@ public final class ProgramInfo {
return new ProgramInfo(
GEN_TITLE.equals(title) ? "Title(" + index + ")" : title,
GEN_EPISODE.equals(episode) ? "Episode(" + index + ")" : episode,
- GEN_EPISODE.equals(episode) ? (index % SEASON_MAX + 1) : seasonNumber,
- GEN_EPISODE.equals(episode) ? (index % EPISODE_MAX + 1) : episodeNumber,
+ episode != null ? (index % SEASON_MAX + 1) : seasonNumber,
+ episode != null ? (index % EPISODE_MAX + 1) : episodeNumber,
GEN_POSTER.equals(posterArtUri)
? Utils.getUriStringForResource(context,
POSTER_ARTS_RES[index % POSTER_ARTS_RES.length])
diff --git a/tests/common/src/com/android/tv/testing/ProgramUtils.java b/tests/common/src/com/android/tv/testing/ProgramUtils.java
index 227eb84a..08c6a033 100644
--- a/tests/common/src/com/android/tv/testing/ProgramUtils.java
+++ b/tests/common/src/com/android/tv/testing/ProgramUtils.java
@@ -20,6 +20,7 @@ import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
+import android.database.sqlite.SQLiteException;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Programs;
import android.net.Uri;
@@ -66,8 +67,12 @@ public class ProgramUtils {
ProgramInfo programAt = program.build(context, index++);
values.put(Programs.COLUMN_TITLE, programAt.title);
values.put(Programs.COLUMN_EPISODE_TITLE, programAt.episode);
- values.put(Programs.COLUMN_SEASON_NUMBER, programAt.seasonNumber);
- values.put(Programs.COLUMN_EPISODE_NUMBER, programAt.episodeNumber);
+ if (programAt.seasonNumber != 0) {
+ values.put(Programs.COLUMN_SEASON_NUMBER, programAt.seasonNumber);
+ }
+ if (programAt.episodeNumber != 0) {
+ values.put(Programs.COLUMN_EPISODE_NUMBER, programAt.episodeNumber);
+ }
values.put(Programs.COLUMN_POSTER_ART_URI, programAt.posterArtUri);
values.put(Programs.COLUMN_START_TIME_UTC_MILLIS, timeMs);
values.put(Programs.COLUMN_END_TIME_UTC_MILLIS, timeMs + programAt.durationMs);
@@ -78,8 +83,13 @@ public class ProgramUtils {
if (list.size() >= MAX_DB_INSERT_COUNT_AT_ONCE
|| timeMs >= targetEndTimeMs) {
- context.getContentResolver().bulkInsert(Programs.CONTENT_URI,
- list.toArray(new ContentValues[list.size()]));
+ try {
+ context.getContentResolver().bulkInsert(Programs.CONTENT_URI,
+ list.toArray(new ContentValues[list.size()]));
+ } catch (SQLiteException e) {
+ Log.e(TAG, "Can't insert EPG.", e);
+ return;
+ }
if (DEBUG) Log.d(TAG, "Inserted " + list.size() + " programs for " + channelUri);
list.clear();
}
diff --git a/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java b/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java
index 71af8297..c4c96fed 100644
--- a/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java
+++ b/tests/common/src/com/android/tv/testing/TvContentRatingConstants.java
@@ -33,7 +33,7 @@ public final class TvContentRatingConstants {
public static final TvContentRating CONTENT_RATING_US_TV_Y7_US_TV_FV =
TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_Y7", "US_TV_FV");
- public static String STRING_US_TV_Y7_US_TV_FV = "com.android.tv/US_TV/US_TV_Y7/US_TV_FV";
+ public static final String STRING_US_TV_Y7_US_TV_FV = "com.android.tv/US_TV/US_TV_Y7/US_TV_FV";
/**
* A content rating object.
@@ -45,7 +45,7 @@ public final class TvContentRatingConstants {
public static final TvContentRating CONTENT_RATING_US_TV_MA =
TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_MA");
- public static String STRING_US_TV_MA = "com.android.tv/US_TV/US_TV_MA";
+ public static final String STRING_US_TV_MA = "com.android.tv/US_TV/US_TV_MA";
/**
* A content rating object.
@@ -58,7 +58,4 @@ public final class TvContentRatingConstants {
public static final TvContentRating CONTENT_RATING_US_TV_PG_US_TV_L_US_TV_S =
TvContentRating.createRating("com.android.tv", "US_TV", "US_TV_PG", "US_TV_L",
"US_TV_S");
-
- public static String STRING_US_TV_PG_US_TV_L_US_TV_S
- = "com.android.tv/US_TV/US_TV_Y7/US_TV_L/US_TV_S";
}
diff --git a/tests/common/src/com/android/tv/testing/Utils.java b/tests/common/src/com/android/tv/testing/Utils.java
index 6bc4e24e..66a13466 100644
--- a/tests/common/src/com/android/tv/testing/Utils.java
+++ b/tests/common/src/com/android/tv/testing/Utils.java
@@ -21,12 +21,10 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
-import android.media.tv.TvContentRating;
import android.media.tv.TvInputInfo;
import android.media.tv.TvInputManager;
import android.net.Uri;
import android.os.Looper;
-import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.TvCommonUtils;
@@ -118,9 +116,7 @@ public final class Utils {
Future<?> temp = MainThreadExecutor.getInstance().submit(runnable);
try {
temp.get();
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- } catch (ExecutionException e) {
+ } catch (InterruptedException | ExecutionException e) {
throw new RuntimeException(e);
}
}
diff --git a/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java b/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java
index ab3bb043..b9def95e 100644
--- a/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java
+++ b/tests/common/src/com/android/tv/testing/dvr/RecordingTestUtils.java
@@ -16,7 +16,6 @@
package com.android.tv.testing.dvr;
-import com.android.tv.dvr.DvrDataManagerInMemoryImpl;
import com.android.tv.dvr.ScheduledRecording;
import junit.framework.Assert;
@@ -25,26 +24,38 @@ import junit.framework.Assert;
* Static utils for using {@link ScheduledRecording} in tests.
*/
public final class RecordingTestUtils {
- public static ScheduledRecording createTestRecordingWithIdAndPeriod(long id, long channelId,
- long startTime, long endTime) {
- return ScheduledRecording.builder(startTime, endTime)
+ private static final String INPUT_ID = "input_id";
+ private static final int CHANNEL_ID = 273;
+
+ public static ScheduledRecording createTestRecordingWithIdAndPeriod(long id, String inputId,
+ long channelId, long startTime, long endTime) {
+ return ScheduledRecording.builder(inputId, channelId, startTime, endTime)
.setId(id)
.setChannelId(channelId)
.build();
}
- public static ScheduledRecording createTestRecordingWithPeriod(long channelId, long startTime,
- long endTime) {
- return createTestRecordingWithIdAndPeriod(ScheduledRecording.ID_NOT_SET, channelId,
+ public static ScheduledRecording createTestRecordingWithPeriod(String inputId,
+ long channelId, long startTime, long endTime) {
+ return createTestRecordingWithIdAndPeriod(ScheduledRecording.ID_NOT_SET, inputId, channelId,
startTime, endTime);
}
- public static ScheduledRecording addScheduledRecording(
- DvrDataManagerInMemoryImpl dvrDataManager, long channelId, long startTime,
- long endTime) {
- ScheduledRecording recording = createTestRecordingWithPeriod(channelId, startTime, endTime);
- recording = dvrDataManager.addScheduledRecordingInternal(recording);
- return recording;
+ public static ScheduledRecording createTestRecordingWithPriorityAndPeriod(long channelId,
+ long priority, long startTime, long endTime) {
+ return ScheduledRecording.builder(INPUT_ID, CHANNEL_ID, startTime, endTime)
+ .setChannelId(channelId)
+ .setPriority(priority)
+ .build();
+ }
+
+ public static ScheduledRecording createTestRecordingWithIdAndPriorityAndPeriod(long id,
+ long channelId, long priority, long startTime, long endTime) {
+ return ScheduledRecording.builder(INPUT_ID, CHANNEL_ID, startTime, endTime)
+ .setId(id)
+ .setChannelId(channelId)
+ .setPriority(priority)
+ .build();
}
public static ScheduledRecording normalizePriority(ScheduledRecording orig){
@@ -59,8 +70,8 @@ public final class RecordingTestUtils {
Assert.assertEquals("start time", expected.getStartTimeMs(), actual.getStartTimeMs());
Assert.assertEquals("end time", expected.getEndTimeMs(), actual.getEndTimeMs());
Assert.assertEquals("state", expected.getState(), actual.getState());
- Assert.assertEquals("parent season recording", expected.getParentSeasonRecording(),
- actual.getParentSeasonRecording());
+ Assert.assertEquals("parent series recording", expected.getSeriesRecordingId(),
+ actual.getSeriesRecordingId());
}
private RecordingTestUtils() { }
diff --git a/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java b/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java
index 61939fdb..d8a4aec1 100644
--- a/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/ChannelBannerViewTest.java
@@ -18,8 +18,8 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.R;
import com.android.tv.testing.uihelper.Constants;
diff --git a/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java b/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java
index 27d8824e..e4f612e3 100644
--- a/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/ChannelSourcesTest.java
@@ -17,9 +17,9 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import com.android.tv.R;
import com.android.tv.testing.uihelper.ByResource;
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 b48968ad..48224123 100644
--- a/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/LiveChannelsAppTest.java
@@ -19,9 +19,9 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import com.android.tv.R;
import com.android.tv.testing.testinput.ChannelStateData;
diff --git a/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java b/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java
index 19861c1f..93d14bde 100644
--- a/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/ParentalControlsTest.java
@@ -18,10 +18,10 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.R;
import com.android.tv.testing.uihelper.ByResource;
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 40ccf267..bbc7aa81 100644
--- a/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/PlayControlsRowViewTest.java
@@ -21,10 +21,10 @@ import static com.android.tv.testing.uihelper.Constants.MENU;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.SmallTest;
import android.view.KeyEvent;
import com.android.tv.R;
diff --git a/tests/func/src/com/android/tv/tests/ui/ProgramGuidePerformanceTest.java b/tests/func/src/com/android/tv/tests/ui/ProgramGuidePerformanceTest.java
index 5c09dd61..95921df9 100644
--- a/tests/func/src/com/android/tv/tests/ui/ProgramGuidePerformanceTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/ProgramGuidePerformanceTest.java
@@ -18,8 +18,8 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
import android.os.SystemClock;
+import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
import com.android.tv.R;
diff --git a/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java b/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java
index a018f012..06c76b3b 100644
--- a/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/ProgramGuideTest.java
@@ -18,8 +18,8 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import com.android.tv.guide.ProgramGuide;
import com.android.tv.testing.uihelper.Constants;
diff --git a/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java b/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java
index 413a783e..9bf2ac50 100644
--- a/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java
+++ b/tests/func/src/com/android/tv/tests/ui/TimeoutTest.java
@@ -18,8 +18,8 @@ package com.android.tv.tests.ui;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertHas;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
+import android.support.test.filters.LargeTest;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import com.android.tv.R;
import com.android.tv.testing.uihelper.Constants;
diff --git a/tests/input/AndroidManifest.xml b/tests/input/AndroidManifest.xml
index e02924ea..14491449 100644
--- a/tests/input/AndroidManifest.xml
+++ b/tests/input/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tv.testinput">
- <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="21"/>
+ <uses-sdk android:targetSdkVersion="23" android:minSdkVersion="23"/>
<!-- Required to update or read existing channel and program information in TvProvider. -->
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
diff --git a/tests/input/res/drawable-xhdpi/android_48dp.png b/tests/input/res/drawable-xhdpi/android_48dp.png
index 9ea1cd14..9359abe5 100644
--- a/tests/input/res/drawable-xhdpi/android_48dp.png
+++ b/tests/input/res/drawable-xhdpi/android_48dp.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_1000_logo.png b/tests/input/res/drawable-xhdpi/ch_1000_logo.png
index 1fb2569d..eec6d373 100644
--- a/tests/input/res/drawable-xhdpi/ch_1000_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_1000_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_100_logo.png b/tests/input/res/drawable-xhdpi/ch_100_logo.png
index fd627a6d..3a8b6731 100644
--- a/tests/input/res/drawable-xhdpi/ch_100_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_100_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_101_logo.png b/tests/input/res/drawable-xhdpi/ch_101_logo.png
index 5cb4c11a..2977ef1d 100644
--- a/tests/input/res/drawable-xhdpi/ch_101_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_101_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_102_logo.png b/tests/input/res/drawable-xhdpi/ch_102_logo.png
index b590b2ef..978112e1 100644
--- a/tests/input/res/drawable-xhdpi/ch_102_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_102_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_103_logo.png b/tests/input/res/drawable-xhdpi/ch_103_logo.png
index 3228ec01..ceb1fd6a 100644
--- a/tests/input/res/drawable-xhdpi/ch_103_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_103_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_104_logo.png b/tests/input/res/drawable-xhdpi/ch_104_logo.png
index 17d497cb..c927568d 100644
--- a/tests/input/res/drawable-xhdpi/ch_104_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_104_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_105_logo.png b/tests/input/res/drawable-xhdpi/ch_105_logo.png
index e6282624..8e1be19d 100644
--- a/tests/input/res/drawable-xhdpi/ch_105_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_105_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_106_logo.png b/tests/input/res/drawable-xhdpi/ch_106_logo.png
index 9f7d11c8..a19c9ef8 100644
--- a/tests/input/res/drawable-xhdpi/ch_106_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_106_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_107_logo.png b/tests/input/res/drawable-xhdpi/ch_107_logo.png
index acf25db1..9d36a488 100644
--- a/tests/input/res/drawable-xhdpi/ch_107_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_107_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_108_logo.png b/tests/input/res/drawable-xhdpi/ch_108_logo.png
index a9a0446f..700ae189 100644
--- a/tests/input/res/drawable-xhdpi/ch_108_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_108_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_109_logo.png b/tests/input/res/drawable-xhdpi/ch_109_logo.png
index 6bba9f5a..209e3b47 100644
--- a/tests/input/res/drawable-xhdpi/ch_109_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_109_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_10_logo.png b/tests/input/res/drawable-xhdpi/ch_10_logo.png
index 7f7041ac..76b3a9b2 100644
--- a/tests/input/res/drawable-xhdpi/ch_10_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_10_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_110_logo.png b/tests/input/res/drawable-xhdpi/ch_110_logo.png
index d3f04154..0c0c1920 100644
--- a/tests/input/res/drawable-xhdpi/ch_110_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_110_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_111_logo.png b/tests/input/res/drawable-xhdpi/ch_111_logo.png
index 08a8a272..07c7ee83 100644
--- a/tests/input/res/drawable-xhdpi/ch_111_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_111_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_112_logo.png b/tests/input/res/drawable-xhdpi/ch_112_logo.png
index 46bfd644..1675e54d 100644
--- a/tests/input/res/drawable-xhdpi/ch_112_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_112_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_113_logo.png b/tests/input/res/drawable-xhdpi/ch_113_logo.png
index dfd5bb0e..57cc81ce 100644
--- a/tests/input/res/drawable-xhdpi/ch_113_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_113_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_114_logo.png b/tests/input/res/drawable-xhdpi/ch_114_logo.png
index f5e5b8ec..3d57f201 100644
--- a/tests/input/res/drawable-xhdpi/ch_114_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_114_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_115_logo.png b/tests/input/res/drawable-xhdpi/ch_115_logo.png
index 9c507671..3897f5c9 100644
--- a/tests/input/res/drawable-xhdpi/ch_115_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_115_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_116_logo.png b/tests/input/res/drawable-xhdpi/ch_116_logo.png
index f05f3d55..83a55a67 100644
--- a/tests/input/res/drawable-xhdpi/ch_116_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_116_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_117_logo.png b/tests/input/res/drawable-xhdpi/ch_117_logo.png
index 0d4d0164..4b4eccf0 100644
--- a/tests/input/res/drawable-xhdpi/ch_117_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_117_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_118_logo.png b/tests/input/res/drawable-xhdpi/ch_118_logo.png
index 6c4aaea0..4a682f67 100644
--- a/tests/input/res/drawable-xhdpi/ch_118_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_118_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_119_logo.png b/tests/input/res/drawable-xhdpi/ch_119_logo.png
index 4f7c9584..2a2aed5e 100644
--- a/tests/input/res/drawable-xhdpi/ch_119_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_119_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_11_logo.png b/tests/input/res/drawable-xhdpi/ch_11_logo.png
index 94cd25aa..62268929 100644
--- a/tests/input/res/drawable-xhdpi/ch_11_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_11_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_120_logo.png b/tests/input/res/drawable-xhdpi/ch_120_logo.png
index d8f5c667..46c5f97a 100644
--- a/tests/input/res/drawable-xhdpi/ch_120_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_120_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_121_logo.png b/tests/input/res/drawable-xhdpi/ch_121_logo.png
index 5e0c64ea..650bd3e4 100644
--- a/tests/input/res/drawable-xhdpi/ch_121_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_121_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_122_logo.png b/tests/input/res/drawable-xhdpi/ch_122_logo.png
index 8e36412a..5a3c5d7b 100644
--- a/tests/input/res/drawable-xhdpi/ch_122_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_122_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_123_logo.png b/tests/input/res/drawable-xhdpi/ch_123_logo.png
index 0ab2f45f..ade9ab29 100644
--- a/tests/input/res/drawable-xhdpi/ch_123_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_123_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_124_logo.png b/tests/input/res/drawable-xhdpi/ch_124_logo.png
index 5f3ae948..62d15c06 100644
--- a/tests/input/res/drawable-xhdpi/ch_124_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_124_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_125_logo.png b/tests/input/res/drawable-xhdpi/ch_125_logo.png
index e3b0614d..34af08a9 100644
--- a/tests/input/res/drawable-xhdpi/ch_125_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_125_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_126_logo.png b/tests/input/res/drawable-xhdpi/ch_126_logo.png
index d9ef549f..8d10d163 100644
--- a/tests/input/res/drawable-xhdpi/ch_126_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_126_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_127_logo.png b/tests/input/res/drawable-xhdpi/ch_127_logo.png
index 46630a6d..428f8e0d 100644
--- a/tests/input/res/drawable-xhdpi/ch_127_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_127_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_128_logo.png b/tests/input/res/drawable-xhdpi/ch_128_logo.png
index fa0cd533..536e04fa 100644
--- a/tests/input/res/drawable-xhdpi/ch_128_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_128_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_129_logo.png b/tests/input/res/drawable-xhdpi/ch_129_logo.png
index a169cf1b..79fc8dc8 100644
--- a/tests/input/res/drawable-xhdpi/ch_129_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_129_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_12_logo.png b/tests/input/res/drawable-xhdpi/ch_12_logo.png
index aafcc88e..5f155f41 100644
--- a/tests/input/res/drawable-xhdpi/ch_12_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_12_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_130_logo.png b/tests/input/res/drawable-xhdpi/ch_130_logo.png
index e575b055..b2bc041f 100644
--- a/tests/input/res/drawable-xhdpi/ch_130_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_130_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_131_logo.png b/tests/input/res/drawable-xhdpi/ch_131_logo.png
index d711d0fb..06081906 100644
--- a/tests/input/res/drawable-xhdpi/ch_131_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_131_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_132_logo.png b/tests/input/res/drawable-xhdpi/ch_132_logo.png
index cb9b097e..18a0bdef 100644
--- a/tests/input/res/drawable-xhdpi/ch_132_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_132_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_133_logo.png b/tests/input/res/drawable-xhdpi/ch_133_logo.png
index 855328ac..312027b2 100644
--- a/tests/input/res/drawable-xhdpi/ch_133_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_133_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_134_logo.png b/tests/input/res/drawable-xhdpi/ch_134_logo.png
index 2c5086e8..c551922e 100644
--- a/tests/input/res/drawable-xhdpi/ch_134_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_134_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_135_logo.png b/tests/input/res/drawable-xhdpi/ch_135_logo.png
index ed914baa..64d7b889 100644
--- a/tests/input/res/drawable-xhdpi/ch_135_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_135_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_136_logo.png b/tests/input/res/drawable-xhdpi/ch_136_logo.png
index 923462c0..31021239 100644
--- a/tests/input/res/drawable-xhdpi/ch_136_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_136_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_137_logo.png b/tests/input/res/drawable-xhdpi/ch_137_logo.png
index 28e5a4af..a7f8cfb8 100644
--- a/tests/input/res/drawable-xhdpi/ch_137_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_137_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_138_logo.png b/tests/input/res/drawable-xhdpi/ch_138_logo.png
index 677cfaab..981425f0 100644
--- a/tests/input/res/drawable-xhdpi/ch_138_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_138_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_139_logo.png b/tests/input/res/drawable-xhdpi/ch_139_logo.png
index 2d343ea4..03170e5e 100644
--- a/tests/input/res/drawable-xhdpi/ch_139_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_139_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_13_logo.png b/tests/input/res/drawable-xhdpi/ch_13_logo.png
index b54a709f..817922f8 100644
--- a/tests/input/res/drawable-xhdpi/ch_13_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_13_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_140_logo.png b/tests/input/res/drawable-xhdpi/ch_140_logo.png
index b109d1cf..f26cf917 100644
--- a/tests/input/res/drawable-xhdpi/ch_140_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_140_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_141_logo.png b/tests/input/res/drawable-xhdpi/ch_141_logo.png
index 7541a9de..0064d436 100644
--- a/tests/input/res/drawable-xhdpi/ch_141_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_141_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_142_logo.png b/tests/input/res/drawable-xhdpi/ch_142_logo.png
index 0f333da5..1d28785e 100644
--- a/tests/input/res/drawable-xhdpi/ch_142_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_142_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_143_logo.png b/tests/input/res/drawable-xhdpi/ch_143_logo.png
index dc437d8e..6f6bb7ea 100644
--- a/tests/input/res/drawable-xhdpi/ch_143_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_143_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_144_logo.png b/tests/input/res/drawable-xhdpi/ch_144_logo.png
index 5f0d01c1..afa678cc 100644
--- a/tests/input/res/drawable-xhdpi/ch_144_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_144_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_145_logo.png b/tests/input/res/drawable-xhdpi/ch_145_logo.png
index 9bba8991..0e989ba5 100644
--- a/tests/input/res/drawable-xhdpi/ch_145_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_145_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_146_logo.png b/tests/input/res/drawable-xhdpi/ch_146_logo.png
index badc014b..4ee0082c 100644
--- a/tests/input/res/drawable-xhdpi/ch_146_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_146_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_147_logo.png b/tests/input/res/drawable-xhdpi/ch_147_logo.png
index 0f8449e2..ddcc91dd 100644
--- a/tests/input/res/drawable-xhdpi/ch_147_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_147_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_148_logo.png b/tests/input/res/drawable-xhdpi/ch_148_logo.png
index 49c7f238..c7f0c42a 100644
--- a/tests/input/res/drawable-xhdpi/ch_148_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_148_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_149_logo.png b/tests/input/res/drawable-xhdpi/ch_149_logo.png
index b05d9511..f2d38ace 100644
--- a/tests/input/res/drawable-xhdpi/ch_149_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_149_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_14_logo.png b/tests/input/res/drawable-xhdpi/ch_14_logo.png
index b053d12a..f66db228 100644
--- a/tests/input/res/drawable-xhdpi/ch_14_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_14_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_150_logo.png b/tests/input/res/drawable-xhdpi/ch_150_logo.png
index 435b113d..6efad527 100644
--- a/tests/input/res/drawable-xhdpi/ch_150_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_150_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_151_logo.png b/tests/input/res/drawable-xhdpi/ch_151_logo.png
index e572bf4f..b37e11ea 100644
--- a/tests/input/res/drawable-xhdpi/ch_151_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_151_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_152_logo.png b/tests/input/res/drawable-xhdpi/ch_152_logo.png
index 2df1a6b1..81f872a5 100644
--- a/tests/input/res/drawable-xhdpi/ch_152_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_152_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_153_logo.png b/tests/input/res/drawable-xhdpi/ch_153_logo.png
index 71a4ac20..e564739d 100644
--- a/tests/input/res/drawable-xhdpi/ch_153_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_153_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_154_logo.png b/tests/input/res/drawable-xhdpi/ch_154_logo.png
index 559f52e6..331498e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_154_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_154_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_155_logo.png b/tests/input/res/drawable-xhdpi/ch_155_logo.png
index c61f7f00..da8c34d4 100644
--- a/tests/input/res/drawable-xhdpi/ch_155_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_155_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_156_logo.png b/tests/input/res/drawable-xhdpi/ch_156_logo.png
index b98c6788..5ca6d550 100644
--- a/tests/input/res/drawable-xhdpi/ch_156_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_156_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_157_logo.png b/tests/input/res/drawable-xhdpi/ch_157_logo.png
index e0cad6c8..460ece79 100644
--- a/tests/input/res/drawable-xhdpi/ch_157_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_157_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_158_logo.png b/tests/input/res/drawable-xhdpi/ch_158_logo.png
index 30dad457..8d11e42e 100644
--- a/tests/input/res/drawable-xhdpi/ch_158_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_158_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_159_logo.png b/tests/input/res/drawable-xhdpi/ch_159_logo.png
index 64c1577f..a10cf881 100644
--- a/tests/input/res/drawable-xhdpi/ch_159_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_159_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_15_logo.png b/tests/input/res/drawable-xhdpi/ch_15_logo.png
index bc7133aa..ae4fc936 100644
--- a/tests/input/res/drawable-xhdpi/ch_15_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_15_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_160_logo.png b/tests/input/res/drawable-xhdpi/ch_160_logo.png
index 97333899..c219ea72 100644
--- a/tests/input/res/drawable-xhdpi/ch_160_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_160_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_161_logo.png b/tests/input/res/drawable-xhdpi/ch_161_logo.png
index 1749aeeb..2b13ad83 100644
--- a/tests/input/res/drawable-xhdpi/ch_161_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_161_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_162_logo.png b/tests/input/res/drawable-xhdpi/ch_162_logo.png
index ef7466c0..11bfadca 100644
--- a/tests/input/res/drawable-xhdpi/ch_162_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_162_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_163_logo.png b/tests/input/res/drawable-xhdpi/ch_163_logo.png
index ceabbd01..9c41b03a 100644
--- a/tests/input/res/drawable-xhdpi/ch_163_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_163_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_164_logo.png b/tests/input/res/drawable-xhdpi/ch_164_logo.png
index 89ab660b..ec4a101e 100644
--- a/tests/input/res/drawable-xhdpi/ch_164_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_164_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_165_logo.png b/tests/input/res/drawable-xhdpi/ch_165_logo.png
index b8c5020a..1aceac38 100644
--- a/tests/input/res/drawable-xhdpi/ch_165_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_165_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_166_logo.png b/tests/input/res/drawable-xhdpi/ch_166_logo.png
index 81929866..f731014f 100644
--- a/tests/input/res/drawable-xhdpi/ch_166_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_166_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_167_logo.png b/tests/input/res/drawable-xhdpi/ch_167_logo.png
index dc2de092..08c82fbf 100644
--- a/tests/input/res/drawable-xhdpi/ch_167_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_167_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_168_logo.png b/tests/input/res/drawable-xhdpi/ch_168_logo.png
index d02097f5..0c5707bc 100644
--- a/tests/input/res/drawable-xhdpi/ch_168_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_168_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_169_logo.png b/tests/input/res/drawable-xhdpi/ch_169_logo.png
index afb0b63c..a9710cec 100644
--- a/tests/input/res/drawable-xhdpi/ch_169_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_169_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_16_logo.png b/tests/input/res/drawable-xhdpi/ch_16_logo.png
index 27df7079..76aee2de 100644
--- a/tests/input/res/drawable-xhdpi/ch_16_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_16_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_170_logo.png b/tests/input/res/drawable-xhdpi/ch_170_logo.png
index 2e33612c..1bf43fa7 100644
--- a/tests/input/res/drawable-xhdpi/ch_170_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_170_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_171_logo.png b/tests/input/res/drawable-xhdpi/ch_171_logo.png
index 730bbdaf..8c6d6fde 100644
--- a/tests/input/res/drawable-xhdpi/ch_171_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_171_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_172_logo.png b/tests/input/res/drawable-xhdpi/ch_172_logo.png
index 5af80238..13d73ec7 100644
--- a/tests/input/res/drawable-xhdpi/ch_172_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_172_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_173_logo.png b/tests/input/res/drawable-xhdpi/ch_173_logo.png
index 367d53e7..2423b0ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_173_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_173_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_174_logo.png b/tests/input/res/drawable-xhdpi/ch_174_logo.png
index 0b562ae0..2f752dce 100644
--- a/tests/input/res/drawable-xhdpi/ch_174_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_174_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_175_logo.png b/tests/input/res/drawable-xhdpi/ch_175_logo.png
index 4265d9fc..ffe3b45e 100644
--- a/tests/input/res/drawable-xhdpi/ch_175_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_175_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_176_logo.png b/tests/input/res/drawable-xhdpi/ch_176_logo.png
index ccaeda9d..d35592de 100644
--- a/tests/input/res/drawable-xhdpi/ch_176_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_176_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_177_logo.png b/tests/input/res/drawable-xhdpi/ch_177_logo.png
index 5710e37e..c50df44f 100644
--- a/tests/input/res/drawable-xhdpi/ch_177_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_177_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_178_logo.png b/tests/input/res/drawable-xhdpi/ch_178_logo.png
index 0d6e2300..22539784 100644
--- a/tests/input/res/drawable-xhdpi/ch_178_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_178_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_179_logo.png b/tests/input/res/drawable-xhdpi/ch_179_logo.png
index a974eaba..a2c1946b 100644
--- a/tests/input/res/drawable-xhdpi/ch_179_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_179_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_17_logo.png b/tests/input/res/drawable-xhdpi/ch_17_logo.png
index 0a12c236..0189498f 100644
--- a/tests/input/res/drawable-xhdpi/ch_17_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_17_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_180_logo.png b/tests/input/res/drawable-xhdpi/ch_180_logo.png
index fa0bf275..9c72f2ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_180_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_180_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_181_logo.png b/tests/input/res/drawable-xhdpi/ch_181_logo.png
index fb29917b..23610936 100644
--- a/tests/input/res/drawable-xhdpi/ch_181_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_181_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_182_logo.png b/tests/input/res/drawable-xhdpi/ch_182_logo.png
index 4120522e..c36bc811 100644
--- a/tests/input/res/drawable-xhdpi/ch_182_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_182_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_183_logo.png b/tests/input/res/drawable-xhdpi/ch_183_logo.png
index 72bcc596..e0e75a41 100644
--- a/tests/input/res/drawable-xhdpi/ch_183_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_183_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_184_logo.png b/tests/input/res/drawable-xhdpi/ch_184_logo.png
index b007b58f..334598f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_184_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_184_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_185_logo.png b/tests/input/res/drawable-xhdpi/ch_185_logo.png
index e1e0cc00..6891720d 100644
--- a/tests/input/res/drawable-xhdpi/ch_185_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_185_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_186_logo.png b/tests/input/res/drawable-xhdpi/ch_186_logo.png
index 646d1ca1..58fc146a 100644
--- a/tests/input/res/drawable-xhdpi/ch_186_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_186_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_187_logo.png b/tests/input/res/drawable-xhdpi/ch_187_logo.png
index 6e4d3de5..6d4f46fc 100644
--- a/tests/input/res/drawable-xhdpi/ch_187_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_187_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_188_logo.png b/tests/input/res/drawable-xhdpi/ch_188_logo.png
index cf25ed3c..96fc401c 100644
--- a/tests/input/res/drawable-xhdpi/ch_188_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_188_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_189_logo.png b/tests/input/res/drawable-xhdpi/ch_189_logo.png
index 54fbefb6..93dd4050 100644
--- a/tests/input/res/drawable-xhdpi/ch_189_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_189_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_18_logo.png b/tests/input/res/drawable-xhdpi/ch_18_logo.png
index 26d7c79b..2025821b 100644
--- a/tests/input/res/drawable-xhdpi/ch_18_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_18_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_190_logo.png b/tests/input/res/drawable-xhdpi/ch_190_logo.png
index dcfecac0..ea257681 100644
--- a/tests/input/res/drawable-xhdpi/ch_190_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_190_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_191_logo.png b/tests/input/res/drawable-xhdpi/ch_191_logo.png
index b45f2491..2ac4c189 100644
--- a/tests/input/res/drawable-xhdpi/ch_191_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_191_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_192_logo.png b/tests/input/res/drawable-xhdpi/ch_192_logo.png
index 4f884b8c..14728cd3 100644
--- a/tests/input/res/drawable-xhdpi/ch_192_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_192_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_193_logo.png b/tests/input/res/drawable-xhdpi/ch_193_logo.png
index c321ba96..dbbf2a1f 100644
--- a/tests/input/res/drawable-xhdpi/ch_193_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_193_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_194_logo.png b/tests/input/res/drawable-xhdpi/ch_194_logo.png
index 47fa3348..aabcefda 100644
--- a/tests/input/res/drawable-xhdpi/ch_194_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_194_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_195_logo.png b/tests/input/res/drawable-xhdpi/ch_195_logo.png
index e91b9d9b..e0158d09 100644
--- a/tests/input/res/drawable-xhdpi/ch_195_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_195_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_196_logo.png b/tests/input/res/drawable-xhdpi/ch_196_logo.png
index 43e9d3a6..a1087785 100644
--- a/tests/input/res/drawable-xhdpi/ch_196_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_196_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_197_logo.png b/tests/input/res/drawable-xhdpi/ch_197_logo.png
index 21fb6ad5..5644e83c 100644
--- a/tests/input/res/drawable-xhdpi/ch_197_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_197_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_198_logo.png b/tests/input/res/drawable-xhdpi/ch_198_logo.png
index 5626d6c5..c06acf55 100644
--- a/tests/input/res/drawable-xhdpi/ch_198_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_198_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_199_logo.png b/tests/input/res/drawable-xhdpi/ch_199_logo.png
index 493bb6bb..6d5ec3ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_199_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_199_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_19_logo.png b/tests/input/res/drawable-xhdpi/ch_19_logo.png
index ac3eb0a2..5e729625 100644
--- a/tests/input/res/drawable-xhdpi/ch_19_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_19_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_1_logo.png b/tests/input/res/drawable-xhdpi/ch_1_logo.png
index 79824607..0a39d154 100644
--- a/tests/input/res/drawable-xhdpi/ch_1_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_1_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_200_logo.png b/tests/input/res/drawable-xhdpi/ch_200_logo.png
index 1b36f263..7999b2f6 100644
--- a/tests/input/res/drawable-xhdpi/ch_200_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_200_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_201_logo.png b/tests/input/res/drawable-xhdpi/ch_201_logo.png
index 2aae3a45..68c868e9 100644
--- a/tests/input/res/drawable-xhdpi/ch_201_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_201_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_202_logo.png b/tests/input/res/drawable-xhdpi/ch_202_logo.png
index 2f4d7ff9..abd838fa 100644
--- a/tests/input/res/drawable-xhdpi/ch_202_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_202_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_203_logo.png b/tests/input/res/drawable-xhdpi/ch_203_logo.png
index 467dd943..f91c34cc 100644
--- a/tests/input/res/drawable-xhdpi/ch_203_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_203_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_204_logo.png b/tests/input/res/drawable-xhdpi/ch_204_logo.png
index 9046979b..8e8582c6 100644
--- a/tests/input/res/drawable-xhdpi/ch_204_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_204_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_205_logo.png b/tests/input/res/drawable-xhdpi/ch_205_logo.png
index ad27bb8a..4e3f4d94 100644
--- a/tests/input/res/drawable-xhdpi/ch_205_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_205_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_206_logo.png b/tests/input/res/drawable-xhdpi/ch_206_logo.png
index 06a4a65f..584bb98c 100644
--- a/tests/input/res/drawable-xhdpi/ch_206_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_206_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_207_logo.png b/tests/input/res/drawable-xhdpi/ch_207_logo.png
index 9bcbca6e..e6b2748e 100644
--- a/tests/input/res/drawable-xhdpi/ch_207_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_207_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_208_logo.png b/tests/input/res/drawable-xhdpi/ch_208_logo.png
index 737145c5..5a18dcad 100644
--- a/tests/input/res/drawable-xhdpi/ch_208_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_208_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_209_logo.png b/tests/input/res/drawable-xhdpi/ch_209_logo.png
index 73f5b15f..c4de3050 100644
--- a/tests/input/res/drawable-xhdpi/ch_209_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_209_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_20_logo.png b/tests/input/res/drawable-xhdpi/ch_20_logo.png
index 8bf17352..6b4d6104 100644
--- a/tests/input/res/drawable-xhdpi/ch_20_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_20_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_210_logo.png b/tests/input/res/drawable-xhdpi/ch_210_logo.png
index cfc35f2e..e4eed085 100644
--- a/tests/input/res/drawable-xhdpi/ch_210_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_210_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_211_logo.png b/tests/input/res/drawable-xhdpi/ch_211_logo.png
index 42a32d17..d5881047 100644
--- a/tests/input/res/drawable-xhdpi/ch_211_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_211_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_212_logo.png b/tests/input/res/drawable-xhdpi/ch_212_logo.png
index 3deeb0ff..c849f6f2 100644
--- a/tests/input/res/drawable-xhdpi/ch_212_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_212_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_213_logo.png b/tests/input/res/drawable-xhdpi/ch_213_logo.png
index 21f15ffb..92def1c5 100644
--- a/tests/input/res/drawable-xhdpi/ch_213_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_213_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_214_logo.png b/tests/input/res/drawable-xhdpi/ch_214_logo.png
index 327bf5c2..51f749fd 100644
--- a/tests/input/res/drawable-xhdpi/ch_214_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_214_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_215_logo.png b/tests/input/res/drawable-xhdpi/ch_215_logo.png
index 8f70a773..5425aaad 100644
--- a/tests/input/res/drawable-xhdpi/ch_215_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_215_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_216_logo.png b/tests/input/res/drawable-xhdpi/ch_216_logo.png
index 4db98a3b..53fed3c2 100644
--- a/tests/input/res/drawable-xhdpi/ch_216_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_216_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_217_logo.png b/tests/input/res/drawable-xhdpi/ch_217_logo.png
index a5be7a53..d253f9cd 100644
--- a/tests/input/res/drawable-xhdpi/ch_217_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_217_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_218_logo.png b/tests/input/res/drawable-xhdpi/ch_218_logo.png
index 9a407691..3c7b0698 100644
--- a/tests/input/res/drawable-xhdpi/ch_218_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_218_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_219_logo.png b/tests/input/res/drawable-xhdpi/ch_219_logo.png
index dd3947ec..7b96dd6e 100644
--- a/tests/input/res/drawable-xhdpi/ch_219_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_219_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_21_logo.png b/tests/input/res/drawable-xhdpi/ch_21_logo.png
index bd177b27..f2848346 100644
--- a/tests/input/res/drawable-xhdpi/ch_21_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_21_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_220_logo.png b/tests/input/res/drawable-xhdpi/ch_220_logo.png
index 53bdd383..f9d20884 100644
--- a/tests/input/res/drawable-xhdpi/ch_220_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_220_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_221_logo.png b/tests/input/res/drawable-xhdpi/ch_221_logo.png
index 1134ef84..9213142d 100644
--- a/tests/input/res/drawable-xhdpi/ch_221_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_221_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_222_logo.png b/tests/input/res/drawable-xhdpi/ch_222_logo.png
index 227a9d5e..66cb9a8b 100644
--- a/tests/input/res/drawable-xhdpi/ch_222_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_222_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_223_logo.png b/tests/input/res/drawable-xhdpi/ch_223_logo.png
index b99511d6..11a44724 100644
--- a/tests/input/res/drawable-xhdpi/ch_223_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_223_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_224_logo.png b/tests/input/res/drawable-xhdpi/ch_224_logo.png
index 5a6d4410..cdba6bf5 100644
--- a/tests/input/res/drawable-xhdpi/ch_224_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_224_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_225_logo.png b/tests/input/res/drawable-xhdpi/ch_225_logo.png
index 5562344f..e9416bfd 100644
--- a/tests/input/res/drawable-xhdpi/ch_225_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_225_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_226_logo.png b/tests/input/res/drawable-xhdpi/ch_226_logo.png
index 8588c73c..88792532 100644
--- a/tests/input/res/drawable-xhdpi/ch_226_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_226_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_227_logo.png b/tests/input/res/drawable-xhdpi/ch_227_logo.png
index 2c97997b..7ae8205b 100644
--- a/tests/input/res/drawable-xhdpi/ch_227_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_227_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_228_logo.png b/tests/input/res/drawable-xhdpi/ch_228_logo.png
index f0d2829e..718d93e2 100644
--- a/tests/input/res/drawable-xhdpi/ch_228_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_228_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_229_logo.png b/tests/input/res/drawable-xhdpi/ch_229_logo.png
index d83db934..eb4f9129 100644
--- a/tests/input/res/drawable-xhdpi/ch_229_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_229_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_22_logo.png b/tests/input/res/drawable-xhdpi/ch_22_logo.png
index 517f8205..9aa987d1 100644
--- a/tests/input/res/drawable-xhdpi/ch_22_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_22_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_230_logo.png b/tests/input/res/drawable-xhdpi/ch_230_logo.png
index a143b9b6..a1bb57d3 100644
--- a/tests/input/res/drawable-xhdpi/ch_230_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_230_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_231_logo.png b/tests/input/res/drawable-xhdpi/ch_231_logo.png
index 099a451e..e748e868 100644
--- a/tests/input/res/drawable-xhdpi/ch_231_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_231_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_232_logo.png b/tests/input/res/drawable-xhdpi/ch_232_logo.png
index f674e86c..5d4f1d69 100644
--- a/tests/input/res/drawable-xhdpi/ch_232_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_232_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_233_logo.png b/tests/input/res/drawable-xhdpi/ch_233_logo.png
index e2ad8ed5..7ff780ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_233_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_233_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_234_logo.png b/tests/input/res/drawable-xhdpi/ch_234_logo.png
index a24d0a80..a4e10dfb 100644
--- a/tests/input/res/drawable-xhdpi/ch_234_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_234_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_235_logo.png b/tests/input/res/drawable-xhdpi/ch_235_logo.png
index d9122ba4..c318ac0b 100644
--- a/tests/input/res/drawable-xhdpi/ch_235_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_235_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_236_logo.png b/tests/input/res/drawable-xhdpi/ch_236_logo.png
index 4726b5c6..2ab86fd6 100644
--- a/tests/input/res/drawable-xhdpi/ch_236_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_236_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_237_logo.png b/tests/input/res/drawable-xhdpi/ch_237_logo.png
index 91e0e172..04fa9d61 100644
--- a/tests/input/res/drawable-xhdpi/ch_237_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_237_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_238_logo.png b/tests/input/res/drawable-xhdpi/ch_238_logo.png
index a18f8152..6649b9db 100644
--- a/tests/input/res/drawable-xhdpi/ch_238_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_238_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_239_logo.png b/tests/input/res/drawable-xhdpi/ch_239_logo.png
index 04baed0b..6eaf887d 100644
--- a/tests/input/res/drawable-xhdpi/ch_239_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_239_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_23_logo.png b/tests/input/res/drawable-xhdpi/ch_23_logo.png
index b4c2f91e..c3dcf172 100644
--- a/tests/input/res/drawable-xhdpi/ch_23_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_23_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_240_logo.png b/tests/input/res/drawable-xhdpi/ch_240_logo.png
index 76998dfb..50d0d0df 100644
--- a/tests/input/res/drawable-xhdpi/ch_240_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_240_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_241_logo.png b/tests/input/res/drawable-xhdpi/ch_241_logo.png
index a033502e..779d53b5 100644
--- a/tests/input/res/drawable-xhdpi/ch_241_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_241_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_242_logo.png b/tests/input/res/drawable-xhdpi/ch_242_logo.png
index 877fb101..717aaae5 100644
--- a/tests/input/res/drawable-xhdpi/ch_242_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_242_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_243_logo.png b/tests/input/res/drawable-xhdpi/ch_243_logo.png
index d7f4e8d1..fd04b2a2 100644
--- a/tests/input/res/drawable-xhdpi/ch_243_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_243_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_244_logo.png b/tests/input/res/drawable-xhdpi/ch_244_logo.png
index 8494f5dc..d8b1b710 100644
--- a/tests/input/res/drawable-xhdpi/ch_244_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_244_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_245_logo.png b/tests/input/res/drawable-xhdpi/ch_245_logo.png
index 24a3614b..3a08f595 100644
--- a/tests/input/res/drawable-xhdpi/ch_245_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_245_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_246_logo.png b/tests/input/res/drawable-xhdpi/ch_246_logo.png
index 1fb507f0..404bd8f0 100644
--- a/tests/input/res/drawable-xhdpi/ch_246_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_246_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_247_logo.png b/tests/input/res/drawable-xhdpi/ch_247_logo.png
index 79cc5d9d..46ee0163 100644
--- a/tests/input/res/drawable-xhdpi/ch_247_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_247_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_248_logo.png b/tests/input/res/drawable-xhdpi/ch_248_logo.png
index 9e30777a..ebfeb6d8 100644
--- a/tests/input/res/drawable-xhdpi/ch_248_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_248_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_249_logo.png b/tests/input/res/drawable-xhdpi/ch_249_logo.png
index 65961a99..f49dc8c4 100644
--- a/tests/input/res/drawable-xhdpi/ch_249_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_249_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_24_logo.png b/tests/input/res/drawable-xhdpi/ch_24_logo.png
index 5cd4932d..8fda8dcc 100644
--- a/tests/input/res/drawable-xhdpi/ch_24_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_24_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_250_logo.png b/tests/input/res/drawable-xhdpi/ch_250_logo.png
index 0a5fb825..3c464624 100644
--- a/tests/input/res/drawable-xhdpi/ch_250_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_250_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_251_logo.png b/tests/input/res/drawable-xhdpi/ch_251_logo.png
index 972a7ae2..58f3f7d2 100644
--- a/tests/input/res/drawable-xhdpi/ch_251_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_251_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_252_logo.png b/tests/input/res/drawable-xhdpi/ch_252_logo.png
index 91a464db..f0284549 100644
--- a/tests/input/res/drawable-xhdpi/ch_252_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_252_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_253_logo.png b/tests/input/res/drawable-xhdpi/ch_253_logo.png
index 7a96f676..47a8f91d 100644
--- a/tests/input/res/drawable-xhdpi/ch_253_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_253_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_254_logo.png b/tests/input/res/drawable-xhdpi/ch_254_logo.png
index 20b690b1..e2505fc0 100644
--- a/tests/input/res/drawable-xhdpi/ch_254_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_254_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_255_logo.png b/tests/input/res/drawable-xhdpi/ch_255_logo.png
index 2db8df71..55e7116b 100644
--- a/tests/input/res/drawable-xhdpi/ch_255_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_255_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_256_logo.png b/tests/input/res/drawable-xhdpi/ch_256_logo.png
index f16050e5..d31964ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_256_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_256_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_257_logo.png b/tests/input/res/drawable-xhdpi/ch_257_logo.png
index e796edfc..cf850f90 100644
--- a/tests/input/res/drawable-xhdpi/ch_257_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_257_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_258_logo.png b/tests/input/res/drawable-xhdpi/ch_258_logo.png
index dc949df7..148d0ee4 100644
--- a/tests/input/res/drawable-xhdpi/ch_258_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_258_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_259_logo.png b/tests/input/res/drawable-xhdpi/ch_259_logo.png
index 95e11e65..aa84697d 100644
--- a/tests/input/res/drawable-xhdpi/ch_259_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_259_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_25_logo.png b/tests/input/res/drawable-xhdpi/ch_25_logo.png
index 39959a8b..401e785e 100644
--- a/tests/input/res/drawable-xhdpi/ch_25_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_25_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_260_logo.png b/tests/input/res/drawable-xhdpi/ch_260_logo.png
index 4184495a..dc4f67f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_260_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_260_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_261_logo.png b/tests/input/res/drawable-xhdpi/ch_261_logo.png
index 530644ea..dfbecb37 100644
--- a/tests/input/res/drawable-xhdpi/ch_261_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_261_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_262_logo.png b/tests/input/res/drawable-xhdpi/ch_262_logo.png
index 27de42c0..2fa3185b 100644
--- a/tests/input/res/drawable-xhdpi/ch_262_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_262_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_263_logo.png b/tests/input/res/drawable-xhdpi/ch_263_logo.png
index 8606e576..d1e84b38 100644
--- a/tests/input/res/drawable-xhdpi/ch_263_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_263_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_264_logo.png b/tests/input/res/drawable-xhdpi/ch_264_logo.png
index 2b35de28..3f52decb 100644
--- a/tests/input/res/drawable-xhdpi/ch_264_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_264_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_265_logo.png b/tests/input/res/drawable-xhdpi/ch_265_logo.png
index b205acb3..f60c362a 100644
--- a/tests/input/res/drawable-xhdpi/ch_265_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_265_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_266_logo.png b/tests/input/res/drawable-xhdpi/ch_266_logo.png
index f4b87fe6..94dc4463 100644
--- a/tests/input/res/drawable-xhdpi/ch_266_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_266_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_267_logo.png b/tests/input/res/drawable-xhdpi/ch_267_logo.png
index 39f406e6..48ac79ed 100644
--- a/tests/input/res/drawable-xhdpi/ch_267_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_267_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_268_logo.png b/tests/input/res/drawable-xhdpi/ch_268_logo.png
index 36794586..b6f1ad64 100644
--- a/tests/input/res/drawable-xhdpi/ch_268_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_268_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_269_logo.png b/tests/input/res/drawable-xhdpi/ch_269_logo.png
index 813d85f7..0d98d378 100644
--- a/tests/input/res/drawable-xhdpi/ch_269_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_269_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_26_logo.png b/tests/input/res/drawable-xhdpi/ch_26_logo.png
index cf1212f3..a8835e4a 100644
--- a/tests/input/res/drawable-xhdpi/ch_26_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_26_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_270_logo.png b/tests/input/res/drawable-xhdpi/ch_270_logo.png
index f21a39fb..27a0aead 100644
--- a/tests/input/res/drawable-xhdpi/ch_270_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_270_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_271_logo.png b/tests/input/res/drawable-xhdpi/ch_271_logo.png
index 0aac87e8..7fa6feb3 100644
--- a/tests/input/res/drawable-xhdpi/ch_271_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_271_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_272_logo.png b/tests/input/res/drawable-xhdpi/ch_272_logo.png
index 74466267..af7e34e6 100644
--- a/tests/input/res/drawable-xhdpi/ch_272_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_272_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_273_logo.png b/tests/input/res/drawable-xhdpi/ch_273_logo.png
index ef2d379a..a8a041af 100644
--- a/tests/input/res/drawable-xhdpi/ch_273_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_273_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_274_logo.png b/tests/input/res/drawable-xhdpi/ch_274_logo.png
index 8c1cb1b8..0f498f23 100644
--- a/tests/input/res/drawable-xhdpi/ch_274_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_274_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_275_logo.png b/tests/input/res/drawable-xhdpi/ch_275_logo.png
index a3e2b915..d598fb35 100644
--- a/tests/input/res/drawable-xhdpi/ch_275_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_275_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_276_logo.png b/tests/input/res/drawable-xhdpi/ch_276_logo.png
index cbcab727..7cbac69a 100644
--- a/tests/input/res/drawable-xhdpi/ch_276_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_276_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_277_logo.png b/tests/input/res/drawable-xhdpi/ch_277_logo.png
index a291b95b..70a7f3ea 100644
--- a/tests/input/res/drawable-xhdpi/ch_277_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_277_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_278_logo.png b/tests/input/res/drawable-xhdpi/ch_278_logo.png
index 03fc4154..fcb332a5 100644
--- a/tests/input/res/drawable-xhdpi/ch_278_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_278_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_279_logo.png b/tests/input/res/drawable-xhdpi/ch_279_logo.png
index 6d64901e..a95b4a96 100644
--- a/tests/input/res/drawable-xhdpi/ch_279_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_279_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_27_logo.png b/tests/input/res/drawable-xhdpi/ch_27_logo.png
index a9b23816..138b7dc8 100644
--- a/tests/input/res/drawable-xhdpi/ch_27_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_27_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_280_logo.png b/tests/input/res/drawable-xhdpi/ch_280_logo.png
index c01599d4..2f862b39 100644
--- a/tests/input/res/drawable-xhdpi/ch_280_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_280_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_281_logo.png b/tests/input/res/drawable-xhdpi/ch_281_logo.png
index 5015b975..6d888d16 100644
--- a/tests/input/res/drawable-xhdpi/ch_281_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_281_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_282_logo.png b/tests/input/res/drawable-xhdpi/ch_282_logo.png
index 9ddb94c4..81db1656 100644
--- a/tests/input/res/drawable-xhdpi/ch_282_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_282_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_283_logo.png b/tests/input/res/drawable-xhdpi/ch_283_logo.png
index b72a1fb4..4933bc3c 100644
--- a/tests/input/res/drawable-xhdpi/ch_283_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_283_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_284_logo.png b/tests/input/res/drawable-xhdpi/ch_284_logo.png
index 3c9358b3..b4880b8b 100644
--- a/tests/input/res/drawable-xhdpi/ch_284_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_284_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_285_logo.png b/tests/input/res/drawable-xhdpi/ch_285_logo.png
index 5c661286..eea6175e 100644
--- a/tests/input/res/drawable-xhdpi/ch_285_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_285_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_286_logo.png b/tests/input/res/drawable-xhdpi/ch_286_logo.png
index 156693b0..d2b5b5bd 100644
--- a/tests/input/res/drawable-xhdpi/ch_286_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_286_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_287_logo.png b/tests/input/res/drawable-xhdpi/ch_287_logo.png
index cd835f37..f374d9d0 100644
--- a/tests/input/res/drawable-xhdpi/ch_287_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_287_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_288_logo.png b/tests/input/res/drawable-xhdpi/ch_288_logo.png
index fa207e55..16072cfa 100644
--- a/tests/input/res/drawable-xhdpi/ch_288_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_288_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_289_logo.png b/tests/input/res/drawable-xhdpi/ch_289_logo.png
index f3a8c5a7..b76c2f48 100644
--- a/tests/input/res/drawable-xhdpi/ch_289_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_289_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_28_logo.png b/tests/input/res/drawable-xhdpi/ch_28_logo.png
index 6c45dd1f..284301b0 100644
--- a/tests/input/res/drawable-xhdpi/ch_28_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_28_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_290_logo.png b/tests/input/res/drawable-xhdpi/ch_290_logo.png
index 9f106cb5..2778664f 100644
--- a/tests/input/res/drawable-xhdpi/ch_290_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_290_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_291_logo.png b/tests/input/res/drawable-xhdpi/ch_291_logo.png
index 88fbeadb..52da29f6 100644
--- a/tests/input/res/drawable-xhdpi/ch_291_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_291_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_292_logo.png b/tests/input/res/drawable-xhdpi/ch_292_logo.png
index 7d3f6cd9..a1d8e6f8 100644
--- a/tests/input/res/drawable-xhdpi/ch_292_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_292_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_293_logo.png b/tests/input/res/drawable-xhdpi/ch_293_logo.png
index 5e78c871..74020c30 100644
--- a/tests/input/res/drawable-xhdpi/ch_293_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_293_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_294_logo.png b/tests/input/res/drawable-xhdpi/ch_294_logo.png
index 78c99725..49d72b5d 100644
--- a/tests/input/res/drawable-xhdpi/ch_294_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_294_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_295_logo.png b/tests/input/res/drawable-xhdpi/ch_295_logo.png
index f7eaa8ed..cae47aeb 100644
--- a/tests/input/res/drawable-xhdpi/ch_295_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_295_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_296_logo.png b/tests/input/res/drawable-xhdpi/ch_296_logo.png
index eb062b9b..4b38d480 100644
--- a/tests/input/res/drawable-xhdpi/ch_296_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_296_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_297_logo.png b/tests/input/res/drawable-xhdpi/ch_297_logo.png
index 9eedeb10..3edd15d0 100644
--- a/tests/input/res/drawable-xhdpi/ch_297_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_297_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_298_logo.png b/tests/input/res/drawable-xhdpi/ch_298_logo.png
index 44565ee1..cb472f31 100644
--- a/tests/input/res/drawable-xhdpi/ch_298_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_298_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_299_logo.png b/tests/input/res/drawable-xhdpi/ch_299_logo.png
index 12f2a234..b672881e 100644
--- a/tests/input/res/drawable-xhdpi/ch_299_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_299_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_29_logo.png b/tests/input/res/drawable-xhdpi/ch_29_logo.png
index 87c282db..9f1c523f 100644
--- a/tests/input/res/drawable-xhdpi/ch_29_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_29_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_2_logo.png b/tests/input/res/drawable-xhdpi/ch_2_logo.png
index 47bf5543..d6887b05 100644
--- a/tests/input/res/drawable-xhdpi/ch_2_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_2_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_300_logo.png b/tests/input/res/drawable-xhdpi/ch_300_logo.png
index f34993d0..9b842d77 100644
--- a/tests/input/res/drawable-xhdpi/ch_300_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_300_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_301_logo.png b/tests/input/res/drawable-xhdpi/ch_301_logo.png
index 8362be93..4c7fda85 100644
--- a/tests/input/res/drawable-xhdpi/ch_301_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_301_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_302_logo.png b/tests/input/res/drawable-xhdpi/ch_302_logo.png
index d59cdddd..e39f5acb 100644
--- a/tests/input/res/drawable-xhdpi/ch_302_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_302_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_303_logo.png b/tests/input/res/drawable-xhdpi/ch_303_logo.png
index 3aa9dca8..78f057f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_303_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_303_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_304_logo.png b/tests/input/res/drawable-xhdpi/ch_304_logo.png
index 154abfc6..b8a68630 100644
--- a/tests/input/res/drawable-xhdpi/ch_304_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_304_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_305_logo.png b/tests/input/res/drawable-xhdpi/ch_305_logo.png
index dd6e809d..7f698610 100644
--- a/tests/input/res/drawable-xhdpi/ch_305_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_305_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_306_logo.png b/tests/input/res/drawable-xhdpi/ch_306_logo.png
index 906ba315..0458b383 100644
--- a/tests/input/res/drawable-xhdpi/ch_306_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_306_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_307_logo.png b/tests/input/res/drawable-xhdpi/ch_307_logo.png
index 9031296c..f2a35cd5 100644
--- a/tests/input/res/drawable-xhdpi/ch_307_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_307_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_308_logo.png b/tests/input/res/drawable-xhdpi/ch_308_logo.png
index 2d388b4b..49d2b4b3 100644
--- a/tests/input/res/drawable-xhdpi/ch_308_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_308_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_309_logo.png b/tests/input/res/drawable-xhdpi/ch_309_logo.png
index 8deddd0b..81da237b 100644
--- a/tests/input/res/drawable-xhdpi/ch_309_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_309_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_30_logo.png b/tests/input/res/drawable-xhdpi/ch_30_logo.png
index 84947048..72db9c52 100644
--- a/tests/input/res/drawable-xhdpi/ch_30_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_30_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_310_logo.png b/tests/input/res/drawable-xhdpi/ch_310_logo.png
index 5ca898d7..901a9113 100644
--- a/tests/input/res/drawable-xhdpi/ch_310_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_310_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_311_logo.png b/tests/input/res/drawable-xhdpi/ch_311_logo.png
index ceda180c..0aa3b284 100644
--- a/tests/input/res/drawable-xhdpi/ch_311_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_311_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_312_logo.png b/tests/input/res/drawable-xhdpi/ch_312_logo.png
index d149b0d6..0cfead7e 100644
--- a/tests/input/res/drawable-xhdpi/ch_312_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_312_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_313_logo.png b/tests/input/res/drawable-xhdpi/ch_313_logo.png
index e8cde0d4..b552c871 100644
--- a/tests/input/res/drawable-xhdpi/ch_313_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_313_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_314_logo.png b/tests/input/res/drawable-xhdpi/ch_314_logo.png
index cab79a1a..354ab843 100644
--- a/tests/input/res/drawable-xhdpi/ch_314_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_314_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_315_logo.png b/tests/input/res/drawable-xhdpi/ch_315_logo.png
index de0229e1..2db60cca 100644
--- a/tests/input/res/drawable-xhdpi/ch_315_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_315_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_316_logo.png b/tests/input/res/drawable-xhdpi/ch_316_logo.png
index 21e074b3..da4d32a3 100644
--- a/tests/input/res/drawable-xhdpi/ch_316_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_316_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_317_logo.png b/tests/input/res/drawable-xhdpi/ch_317_logo.png
index a9a0e604..d344ef36 100644
--- a/tests/input/res/drawable-xhdpi/ch_317_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_317_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_318_logo.png b/tests/input/res/drawable-xhdpi/ch_318_logo.png
index fbdb3ab0..9150c2b1 100644
--- a/tests/input/res/drawable-xhdpi/ch_318_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_318_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_319_logo.png b/tests/input/res/drawable-xhdpi/ch_319_logo.png
index 9d23ae89..4b1b7c9d 100644
--- a/tests/input/res/drawable-xhdpi/ch_319_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_319_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_31_logo.png b/tests/input/res/drawable-xhdpi/ch_31_logo.png
index cf6f865e..5386601d 100644
--- a/tests/input/res/drawable-xhdpi/ch_31_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_31_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_320_logo.png b/tests/input/res/drawable-xhdpi/ch_320_logo.png
index 4dd5c201..4efe21d4 100644
--- a/tests/input/res/drawable-xhdpi/ch_320_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_320_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_321_logo.png b/tests/input/res/drawable-xhdpi/ch_321_logo.png
index cc0bf527..d523277d 100644
--- a/tests/input/res/drawable-xhdpi/ch_321_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_321_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_322_logo.png b/tests/input/res/drawable-xhdpi/ch_322_logo.png
index 5b2e3e2b..cf2500dc 100644
--- a/tests/input/res/drawable-xhdpi/ch_322_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_322_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_323_logo.png b/tests/input/res/drawable-xhdpi/ch_323_logo.png
index 213d10ff..e838c0c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_323_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_323_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_324_logo.png b/tests/input/res/drawable-xhdpi/ch_324_logo.png
index 81bea5cc..cc0cf6d2 100644
--- a/tests/input/res/drawable-xhdpi/ch_324_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_324_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_325_logo.png b/tests/input/res/drawable-xhdpi/ch_325_logo.png
index 811da30e..adfda884 100644
--- a/tests/input/res/drawable-xhdpi/ch_325_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_325_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_326_logo.png b/tests/input/res/drawable-xhdpi/ch_326_logo.png
index 157dbb19..434d2cd6 100644
--- a/tests/input/res/drawable-xhdpi/ch_326_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_326_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_327_logo.png b/tests/input/res/drawable-xhdpi/ch_327_logo.png
index 57808898..0a7f0b95 100644
--- a/tests/input/res/drawable-xhdpi/ch_327_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_327_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_328_logo.png b/tests/input/res/drawable-xhdpi/ch_328_logo.png
index 1f95d3de..77129370 100644
--- a/tests/input/res/drawable-xhdpi/ch_328_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_328_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_329_logo.png b/tests/input/res/drawable-xhdpi/ch_329_logo.png
index 6eaf15a9..9ff0a89f 100644
--- a/tests/input/res/drawable-xhdpi/ch_329_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_329_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_32_logo.png b/tests/input/res/drawable-xhdpi/ch_32_logo.png
index 6618debe..39351ac1 100644
--- a/tests/input/res/drawable-xhdpi/ch_32_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_32_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_330_logo.png b/tests/input/res/drawable-xhdpi/ch_330_logo.png
index 936053a7..54adc2e7 100644
--- a/tests/input/res/drawable-xhdpi/ch_330_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_330_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_331_logo.png b/tests/input/res/drawable-xhdpi/ch_331_logo.png
index fa04e972..6c29286f 100644
--- a/tests/input/res/drawable-xhdpi/ch_331_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_331_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_332_logo.png b/tests/input/res/drawable-xhdpi/ch_332_logo.png
index 29621c61..ccab9144 100644
--- a/tests/input/res/drawable-xhdpi/ch_332_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_332_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_333_logo.png b/tests/input/res/drawable-xhdpi/ch_333_logo.png
index 4ff2396a..a35ce116 100644
--- a/tests/input/res/drawable-xhdpi/ch_333_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_333_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_334_logo.png b/tests/input/res/drawable-xhdpi/ch_334_logo.png
index 2222f42a..a191d804 100644
--- a/tests/input/res/drawable-xhdpi/ch_334_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_334_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_335_logo.png b/tests/input/res/drawable-xhdpi/ch_335_logo.png
index 138761b1..a5680b24 100644
--- a/tests/input/res/drawable-xhdpi/ch_335_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_335_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_336_logo.png b/tests/input/res/drawable-xhdpi/ch_336_logo.png
index 082c376f..42292bf8 100644
--- a/tests/input/res/drawable-xhdpi/ch_336_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_336_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_337_logo.png b/tests/input/res/drawable-xhdpi/ch_337_logo.png
index 3841ffc3..d231fca3 100644
--- a/tests/input/res/drawable-xhdpi/ch_337_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_337_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_338_logo.png b/tests/input/res/drawable-xhdpi/ch_338_logo.png
index 597524ce..000988ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_338_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_338_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_339_logo.png b/tests/input/res/drawable-xhdpi/ch_339_logo.png
index 635bd339..3150c92c 100644
--- a/tests/input/res/drawable-xhdpi/ch_339_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_339_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_33_logo.png b/tests/input/res/drawable-xhdpi/ch_33_logo.png
index 28faf971..4931e205 100644
--- a/tests/input/res/drawable-xhdpi/ch_33_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_33_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_340_logo.png b/tests/input/res/drawable-xhdpi/ch_340_logo.png
index 84d8ca2b..d35d772e 100644
--- a/tests/input/res/drawable-xhdpi/ch_340_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_340_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_341_logo.png b/tests/input/res/drawable-xhdpi/ch_341_logo.png
index 0f8bf318..3ad19a0b 100644
--- a/tests/input/res/drawable-xhdpi/ch_341_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_341_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_342_logo.png b/tests/input/res/drawable-xhdpi/ch_342_logo.png
index dcfe9b8c..8d6cad2c 100644
--- a/tests/input/res/drawable-xhdpi/ch_342_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_342_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_343_logo.png b/tests/input/res/drawable-xhdpi/ch_343_logo.png
index 8d534621..6e16dc96 100644
--- a/tests/input/res/drawable-xhdpi/ch_343_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_343_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_344_logo.png b/tests/input/res/drawable-xhdpi/ch_344_logo.png
index cb9b5f29..e66c5a19 100644
--- a/tests/input/res/drawable-xhdpi/ch_344_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_344_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_345_logo.png b/tests/input/res/drawable-xhdpi/ch_345_logo.png
index ec566640..ed451fde 100644
--- a/tests/input/res/drawable-xhdpi/ch_345_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_345_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_346_logo.png b/tests/input/res/drawable-xhdpi/ch_346_logo.png
index ad013b18..31059671 100644
--- a/tests/input/res/drawable-xhdpi/ch_346_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_346_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_347_logo.png b/tests/input/res/drawable-xhdpi/ch_347_logo.png
index ae979990..65ee51eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_347_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_347_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_348_logo.png b/tests/input/res/drawable-xhdpi/ch_348_logo.png
index 94ef1d40..54e9cca7 100644
--- a/tests/input/res/drawable-xhdpi/ch_348_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_348_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_349_logo.png b/tests/input/res/drawable-xhdpi/ch_349_logo.png
index 6b9eae58..7a11ae34 100644
--- a/tests/input/res/drawable-xhdpi/ch_349_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_349_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_34_logo.png b/tests/input/res/drawable-xhdpi/ch_34_logo.png
index ffe43d5b..27a217e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_34_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_34_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_350_logo.png b/tests/input/res/drawable-xhdpi/ch_350_logo.png
index 5f764eb2..5c486ab7 100644
--- a/tests/input/res/drawable-xhdpi/ch_350_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_350_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_351_logo.png b/tests/input/res/drawable-xhdpi/ch_351_logo.png
index 1eff168b..17fff276 100644
--- a/tests/input/res/drawable-xhdpi/ch_351_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_351_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_352_logo.png b/tests/input/res/drawable-xhdpi/ch_352_logo.png
index 666784d6..2d9c412c 100644
--- a/tests/input/res/drawable-xhdpi/ch_352_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_352_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_353_logo.png b/tests/input/res/drawable-xhdpi/ch_353_logo.png
index d0db848d..38c76b38 100644
--- a/tests/input/res/drawable-xhdpi/ch_353_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_353_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_354_logo.png b/tests/input/res/drawable-xhdpi/ch_354_logo.png
index e4b4016a..8ea7d467 100644
--- a/tests/input/res/drawable-xhdpi/ch_354_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_354_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_355_logo.png b/tests/input/res/drawable-xhdpi/ch_355_logo.png
index 25061a42..0c94dcf6 100644
--- a/tests/input/res/drawable-xhdpi/ch_355_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_355_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_356_logo.png b/tests/input/res/drawable-xhdpi/ch_356_logo.png
index d7d2be0a..3f2b288a 100644
--- a/tests/input/res/drawable-xhdpi/ch_356_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_356_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_357_logo.png b/tests/input/res/drawable-xhdpi/ch_357_logo.png
index d8b991ea..63d43c31 100644
--- a/tests/input/res/drawable-xhdpi/ch_357_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_357_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_358_logo.png b/tests/input/res/drawable-xhdpi/ch_358_logo.png
index cc9babf0..1f5771fe 100644
--- a/tests/input/res/drawable-xhdpi/ch_358_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_358_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_359_logo.png b/tests/input/res/drawable-xhdpi/ch_359_logo.png
index 649e2bb1..7a4114bd 100644
--- a/tests/input/res/drawable-xhdpi/ch_359_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_359_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_35_logo.png b/tests/input/res/drawable-xhdpi/ch_35_logo.png
index 2c0cdee6..af2cae5d 100644
--- a/tests/input/res/drawable-xhdpi/ch_35_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_35_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_360_logo.png b/tests/input/res/drawable-xhdpi/ch_360_logo.png
index 3a026c6f..4e49a1f9 100644
--- a/tests/input/res/drawable-xhdpi/ch_360_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_360_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_361_logo.png b/tests/input/res/drawable-xhdpi/ch_361_logo.png
index f4bc741c..43b16ac6 100644
--- a/tests/input/res/drawable-xhdpi/ch_361_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_361_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_362_logo.png b/tests/input/res/drawable-xhdpi/ch_362_logo.png
index 36ed58de..efb32dab 100644
--- a/tests/input/res/drawable-xhdpi/ch_362_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_362_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_363_logo.png b/tests/input/res/drawable-xhdpi/ch_363_logo.png
index 121e8b89..c59eb0b3 100644
--- a/tests/input/res/drawable-xhdpi/ch_363_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_363_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_364_logo.png b/tests/input/res/drawable-xhdpi/ch_364_logo.png
index 27e6b9ec..9d649d47 100644
--- a/tests/input/res/drawable-xhdpi/ch_364_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_364_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_365_logo.png b/tests/input/res/drawable-xhdpi/ch_365_logo.png
index fb7839f0..96cae282 100644
--- a/tests/input/res/drawable-xhdpi/ch_365_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_365_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_366_logo.png b/tests/input/res/drawable-xhdpi/ch_366_logo.png
index a85568ae..3c3a5cf6 100644
--- a/tests/input/res/drawable-xhdpi/ch_366_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_366_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_367_logo.png b/tests/input/res/drawable-xhdpi/ch_367_logo.png
index 7eb14267..7467625a 100644
--- a/tests/input/res/drawable-xhdpi/ch_367_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_367_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_368_logo.png b/tests/input/res/drawable-xhdpi/ch_368_logo.png
index 9023261f..adb62ffc 100644
--- a/tests/input/res/drawable-xhdpi/ch_368_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_368_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_369_logo.png b/tests/input/res/drawable-xhdpi/ch_369_logo.png
index 07124c27..773f6c5c 100644
--- a/tests/input/res/drawable-xhdpi/ch_369_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_369_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_36_logo.png b/tests/input/res/drawable-xhdpi/ch_36_logo.png
index 66e59fcd..4580833f 100644
--- a/tests/input/res/drawable-xhdpi/ch_36_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_36_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_370_logo.png b/tests/input/res/drawable-xhdpi/ch_370_logo.png
index b2d0f4c1..d60583bc 100644
--- a/tests/input/res/drawable-xhdpi/ch_370_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_370_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_371_logo.png b/tests/input/res/drawable-xhdpi/ch_371_logo.png
index fe685db9..91958a07 100644
--- a/tests/input/res/drawable-xhdpi/ch_371_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_371_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_372_logo.png b/tests/input/res/drawable-xhdpi/ch_372_logo.png
index a083c6cd..4b2d757c 100644
--- a/tests/input/res/drawable-xhdpi/ch_372_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_372_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_373_logo.png b/tests/input/res/drawable-xhdpi/ch_373_logo.png
index 152bc6ce..f8aae527 100644
--- a/tests/input/res/drawable-xhdpi/ch_373_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_373_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_374_logo.png b/tests/input/res/drawable-xhdpi/ch_374_logo.png
index c0469e26..3549da94 100644
--- a/tests/input/res/drawable-xhdpi/ch_374_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_374_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_375_logo.png b/tests/input/res/drawable-xhdpi/ch_375_logo.png
index 0f1f4c2a..c19806e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_375_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_375_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_376_logo.png b/tests/input/res/drawable-xhdpi/ch_376_logo.png
index 503c39ad..86144b73 100644
--- a/tests/input/res/drawable-xhdpi/ch_376_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_376_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_377_logo.png b/tests/input/res/drawable-xhdpi/ch_377_logo.png
index 1a16efea..74f693c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_377_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_377_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_378_logo.png b/tests/input/res/drawable-xhdpi/ch_378_logo.png
index e23ddd77..40253dab 100644
--- a/tests/input/res/drawable-xhdpi/ch_378_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_378_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_379_logo.png b/tests/input/res/drawable-xhdpi/ch_379_logo.png
index ec6fa2dc..5459058f 100644
--- a/tests/input/res/drawable-xhdpi/ch_379_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_379_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_37_logo.png b/tests/input/res/drawable-xhdpi/ch_37_logo.png
index 6d0f27f3..7fce3b4d 100644
--- a/tests/input/res/drawable-xhdpi/ch_37_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_37_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_380_logo.png b/tests/input/res/drawable-xhdpi/ch_380_logo.png
index 31d2fafa..a47a40d8 100644
--- a/tests/input/res/drawable-xhdpi/ch_380_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_380_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_381_logo.png b/tests/input/res/drawable-xhdpi/ch_381_logo.png
index e7efb1c8..7059114c 100644
--- a/tests/input/res/drawable-xhdpi/ch_381_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_381_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_382_logo.png b/tests/input/res/drawable-xhdpi/ch_382_logo.png
index ee082821..a61201a5 100644
--- a/tests/input/res/drawable-xhdpi/ch_382_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_382_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_383_logo.png b/tests/input/res/drawable-xhdpi/ch_383_logo.png
index f9f69248..c126d6e3 100644
--- a/tests/input/res/drawable-xhdpi/ch_383_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_383_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_384_logo.png b/tests/input/res/drawable-xhdpi/ch_384_logo.png
index 1096faa8..0bd5f454 100644
--- a/tests/input/res/drawable-xhdpi/ch_384_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_384_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_385_logo.png b/tests/input/res/drawable-xhdpi/ch_385_logo.png
index cd0b9db4..864ff5c6 100644
--- a/tests/input/res/drawable-xhdpi/ch_385_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_385_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_386_logo.png b/tests/input/res/drawable-xhdpi/ch_386_logo.png
index 0b9fe16d..643db67a 100644
--- a/tests/input/res/drawable-xhdpi/ch_386_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_386_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_387_logo.png b/tests/input/res/drawable-xhdpi/ch_387_logo.png
index 45d0d225..206ec14f 100644
--- a/tests/input/res/drawable-xhdpi/ch_387_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_387_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_388_logo.png b/tests/input/res/drawable-xhdpi/ch_388_logo.png
index 8bcce1b4..37c9dbae 100644
--- a/tests/input/res/drawable-xhdpi/ch_388_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_388_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_389_logo.png b/tests/input/res/drawable-xhdpi/ch_389_logo.png
index a0251351..958ffb63 100644
--- a/tests/input/res/drawable-xhdpi/ch_389_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_389_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_38_logo.png b/tests/input/res/drawable-xhdpi/ch_38_logo.png
index 0e2539de..6e864bf8 100644
--- a/tests/input/res/drawable-xhdpi/ch_38_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_38_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_390_logo.png b/tests/input/res/drawable-xhdpi/ch_390_logo.png
index dbc5a19d..a5a6547e 100644
--- a/tests/input/res/drawable-xhdpi/ch_390_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_390_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_391_logo.png b/tests/input/res/drawable-xhdpi/ch_391_logo.png
index b0a7f9ca..0d1c076b 100644
--- a/tests/input/res/drawable-xhdpi/ch_391_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_391_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_392_logo.png b/tests/input/res/drawable-xhdpi/ch_392_logo.png
index 1a303e63..25e3a87a 100644
--- a/tests/input/res/drawable-xhdpi/ch_392_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_392_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_393_logo.png b/tests/input/res/drawable-xhdpi/ch_393_logo.png
index 69f7e765..92ebefe2 100644
--- a/tests/input/res/drawable-xhdpi/ch_393_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_393_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_394_logo.png b/tests/input/res/drawable-xhdpi/ch_394_logo.png
index c1e08355..b220319a 100644
--- a/tests/input/res/drawable-xhdpi/ch_394_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_394_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_395_logo.png b/tests/input/res/drawable-xhdpi/ch_395_logo.png
index c8df82e2..29df3f8f 100644
--- a/tests/input/res/drawable-xhdpi/ch_395_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_395_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_396_logo.png b/tests/input/res/drawable-xhdpi/ch_396_logo.png
index 61fa2b7b..f1e6f983 100644
--- a/tests/input/res/drawable-xhdpi/ch_396_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_396_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_397_logo.png b/tests/input/res/drawable-xhdpi/ch_397_logo.png
index 01bea3af..7f44d63c 100644
--- a/tests/input/res/drawable-xhdpi/ch_397_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_397_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_398_logo.png b/tests/input/res/drawable-xhdpi/ch_398_logo.png
index c6f3c193..03b14271 100644
--- a/tests/input/res/drawable-xhdpi/ch_398_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_398_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_399_logo.png b/tests/input/res/drawable-xhdpi/ch_399_logo.png
index 036cb786..a15aaa4e 100644
--- a/tests/input/res/drawable-xhdpi/ch_399_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_399_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_39_logo.png b/tests/input/res/drawable-xhdpi/ch_39_logo.png
index 3b719c30..633a1172 100644
--- a/tests/input/res/drawable-xhdpi/ch_39_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_39_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_3_logo.png b/tests/input/res/drawable-xhdpi/ch_3_logo.png
index b0e29425..9c921385 100644
--- a/tests/input/res/drawable-xhdpi/ch_3_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_3_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_400_logo.png b/tests/input/res/drawable-xhdpi/ch_400_logo.png
index 8680df86..15442662 100644
--- a/tests/input/res/drawable-xhdpi/ch_400_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_400_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_401_logo.png b/tests/input/res/drawable-xhdpi/ch_401_logo.png
index 987dd616..c4d06916 100644
--- a/tests/input/res/drawable-xhdpi/ch_401_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_401_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_402_logo.png b/tests/input/res/drawable-xhdpi/ch_402_logo.png
index 00c6d6fe..b8719f32 100644
--- a/tests/input/res/drawable-xhdpi/ch_402_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_402_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_403_logo.png b/tests/input/res/drawable-xhdpi/ch_403_logo.png
index 2929a7bd..054b98b7 100644
--- a/tests/input/res/drawable-xhdpi/ch_403_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_403_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_404_logo.png b/tests/input/res/drawable-xhdpi/ch_404_logo.png
index eae3f461..64566990 100644
--- a/tests/input/res/drawable-xhdpi/ch_404_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_404_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_405_logo.png b/tests/input/res/drawable-xhdpi/ch_405_logo.png
index 8672cb0f..2ceab3fb 100644
--- a/tests/input/res/drawable-xhdpi/ch_405_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_405_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_406_logo.png b/tests/input/res/drawable-xhdpi/ch_406_logo.png
index cbd69f3e..f7557109 100644
--- a/tests/input/res/drawable-xhdpi/ch_406_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_406_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_407_logo.png b/tests/input/res/drawable-xhdpi/ch_407_logo.png
index 003b3e42..8228e1c5 100644
--- a/tests/input/res/drawable-xhdpi/ch_407_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_407_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_408_logo.png b/tests/input/res/drawable-xhdpi/ch_408_logo.png
index 1b2a0dc5..d9c09b85 100644
--- a/tests/input/res/drawable-xhdpi/ch_408_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_408_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_409_logo.png b/tests/input/res/drawable-xhdpi/ch_409_logo.png
index 1d4dd21e..fd2b76e5 100644
--- a/tests/input/res/drawable-xhdpi/ch_409_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_409_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_40_logo.png b/tests/input/res/drawable-xhdpi/ch_40_logo.png
index 1e0c8720..63600168 100644
--- a/tests/input/res/drawable-xhdpi/ch_40_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_40_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_410_logo.png b/tests/input/res/drawable-xhdpi/ch_410_logo.png
index 49bec68d..8b05de2e 100644
--- a/tests/input/res/drawable-xhdpi/ch_410_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_410_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_411_logo.png b/tests/input/res/drawable-xhdpi/ch_411_logo.png
index e002d190..7306991e 100644
--- a/tests/input/res/drawable-xhdpi/ch_411_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_411_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_412_logo.png b/tests/input/res/drawable-xhdpi/ch_412_logo.png
index f2add1e1..55964214 100644
--- a/tests/input/res/drawable-xhdpi/ch_412_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_412_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_413_logo.png b/tests/input/res/drawable-xhdpi/ch_413_logo.png
index 4c400c26..c744901d 100644
--- a/tests/input/res/drawable-xhdpi/ch_413_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_413_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_414_logo.png b/tests/input/res/drawable-xhdpi/ch_414_logo.png
index 3119a703..304dc7da 100644
--- a/tests/input/res/drawable-xhdpi/ch_414_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_414_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_415_logo.png b/tests/input/res/drawable-xhdpi/ch_415_logo.png
index 9f634433..1a9b1f19 100644
--- a/tests/input/res/drawable-xhdpi/ch_415_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_415_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_416_logo.png b/tests/input/res/drawable-xhdpi/ch_416_logo.png
index a0bf863a..53318edf 100644
--- a/tests/input/res/drawable-xhdpi/ch_416_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_416_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_417_logo.png b/tests/input/res/drawable-xhdpi/ch_417_logo.png
index a475f405..763bad1b 100644
--- a/tests/input/res/drawable-xhdpi/ch_417_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_417_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_418_logo.png b/tests/input/res/drawable-xhdpi/ch_418_logo.png
index 1c8b9af4..afa06409 100644
--- a/tests/input/res/drawable-xhdpi/ch_418_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_418_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_419_logo.png b/tests/input/res/drawable-xhdpi/ch_419_logo.png
index e0e3aeec..4741b659 100644
--- a/tests/input/res/drawable-xhdpi/ch_419_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_419_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_41_logo.png b/tests/input/res/drawable-xhdpi/ch_41_logo.png
index a3e80d91..6002ae31 100644
--- a/tests/input/res/drawable-xhdpi/ch_41_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_41_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_420_logo.png b/tests/input/res/drawable-xhdpi/ch_420_logo.png
index a34ce714..22a72aec 100644
--- a/tests/input/res/drawable-xhdpi/ch_420_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_420_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_421_logo.png b/tests/input/res/drawable-xhdpi/ch_421_logo.png
index a6539075..f4c301dd 100644
--- a/tests/input/res/drawable-xhdpi/ch_421_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_421_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_422_logo.png b/tests/input/res/drawable-xhdpi/ch_422_logo.png
index 4eb3189a..e70d59ac 100644
--- a/tests/input/res/drawable-xhdpi/ch_422_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_422_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_423_logo.png b/tests/input/res/drawable-xhdpi/ch_423_logo.png
index 8d83bd46..a4c96fbd 100644
--- a/tests/input/res/drawable-xhdpi/ch_423_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_423_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_424_logo.png b/tests/input/res/drawable-xhdpi/ch_424_logo.png
index 3eed5fa1..9dc1713e 100644
--- a/tests/input/res/drawable-xhdpi/ch_424_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_424_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_425_logo.png b/tests/input/res/drawable-xhdpi/ch_425_logo.png
index 2ffca333..a79e8f5c 100644
--- a/tests/input/res/drawable-xhdpi/ch_425_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_425_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_426_logo.png b/tests/input/res/drawable-xhdpi/ch_426_logo.png
index 5a9ee457..34bcbef0 100644
--- a/tests/input/res/drawable-xhdpi/ch_426_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_426_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_427_logo.png b/tests/input/res/drawable-xhdpi/ch_427_logo.png
index 28ebd5dd..6133494d 100644
--- a/tests/input/res/drawable-xhdpi/ch_427_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_427_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_428_logo.png b/tests/input/res/drawable-xhdpi/ch_428_logo.png
index 68769207..d91391a4 100644
--- a/tests/input/res/drawable-xhdpi/ch_428_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_428_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_429_logo.png b/tests/input/res/drawable-xhdpi/ch_429_logo.png
index c8b71730..f24a64f9 100644
--- a/tests/input/res/drawable-xhdpi/ch_429_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_429_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_42_logo.png b/tests/input/res/drawable-xhdpi/ch_42_logo.png
index 806d0186..c2f641c0 100644
--- a/tests/input/res/drawable-xhdpi/ch_42_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_42_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_430_logo.png b/tests/input/res/drawable-xhdpi/ch_430_logo.png
index be69f765..e656d6da 100644
--- a/tests/input/res/drawable-xhdpi/ch_430_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_430_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_431_logo.png b/tests/input/res/drawable-xhdpi/ch_431_logo.png
index 23869ee5..4827d71d 100644
--- a/tests/input/res/drawable-xhdpi/ch_431_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_431_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_432_logo.png b/tests/input/res/drawable-xhdpi/ch_432_logo.png
index 023f2467..bb5493e2 100644
--- a/tests/input/res/drawable-xhdpi/ch_432_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_432_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_433_logo.png b/tests/input/res/drawable-xhdpi/ch_433_logo.png
index 4d089a91..f777f36a 100644
--- a/tests/input/res/drawable-xhdpi/ch_433_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_433_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_434_logo.png b/tests/input/res/drawable-xhdpi/ch_434_logo.png
index 80be3347..f342df85 100644
--- a/tests/input/res/drawable-xhdpi/ch_434_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_434_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_435_logo.png b/tests/input/res/drawable-xhdpi/ch_435_logo.png
index ee68a104..70667e7a 100644
--- a/tests/input/res/drawable-xhdpi/ch_435_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_435_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_436_logo.png b/tests/input/res/drawable-xhdpi/ch_436_logo.png
index 1cbecf67..1895a238 100644
--- a/tests/input/res/drawable-xhdpi/ch_436_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_436_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_437_logo.png b/tests/input/res/drawable-xhdpi/ch_437_logo.png
index 86f0051d..9b6b335b 100644
--- a/tests/input/res/drawable-xhdpi/ch_437_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_437_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_438_logo.png b/tests/input/res/drawable-xhdpi/ch_438_logo.png
index 68e96389..5070cdb1 100644
--- a/tests/input/res/drawable-xhdpi/ch_438_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_438_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_439_logo.png b/tests/input/res/drawable-xhdpi/ch_439_logo.png
index 6cb790f7..adcad27b 100644
--- a/tests/input/res/drawable-xhdpi/ch_439_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_439_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_43_logo.png b/tests/input/res/drawable-xhdpi/ch_43_logo.png
index 20aaff1b..5ea7d814 100644
--- a/tests/input/res/drawable-xhdpi/ch_43_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_43_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_440_logo.png b/tests/input/res/drawable-xhdpi/ch_440_logo.png
index ff8a9967..0b1f76c6 100644
--- a/tests/input/res/drawable-xhdpi/ch_440_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_440_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_441_logo.png b/tests/input/res/drawable-xhdpi/ch_441_logo.png
index 691bdb1f..65870b6e 100644
--- a/tests/input/res/drawable-xhdpi/ch_441_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_441_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_442_logo.png b/tests/input/res/drawable-xhdpi/ch_442_logo.png
index c2180054..9812a1cb 100644
--- a/tests/input/res/drawable-xhdpi/ch_442_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_442_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_443_logo.png b/tests/input/res/drawable-xhdpi/ch_443_logo.png
index 865b0101..d539f5c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_443_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_443_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_444_logo.png b/tests/input/res/drawable-xhdpi/ch_444_logo.png
index ed770663..fbf615d9 100644
--- a/tests/input/res/drawable-xhdpi/ch_444_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_444_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_445_logo.png b/tests/input/res/drawable-xhdpi/ch_445_logo.png
index 1d8c4996..440085aa 100644
--- a/tests/input/res/drawable-xhdpi/ch_445_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_445_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_446_logo.png b/tests/input/res/drawable-xhdpi/ch_446_logo.png
index 1fc1b386..d26f1c37 100644
--- a/tests/input/res/drawable-xhdpi/ch_446_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_446_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_447_logo.png b/tests/input/res/drawable-xhdpi/ch_447_logo.png
index 59a8adc8..0967878d 100644
--- a/tests/input/res/drawable-xhdpi/ch_447_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_447_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_448_logo.png b/tests/input/res/drawable-xhdpi/ch_448_logo.png
index 820d61f9..b979c062 100644
--- a/tests/input/res/drawable-xhdpi/ch_448_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_448_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_449_logo.png b/tests/input/res/drawable-xhdpi/ch_449_logo.png
index 94a1a70f..2232b90e 100644
--- a/tests/input/res/drawable-xhdpi/ch_449_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_449_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_44_logo.png b/tests/input/res/drawable-xhdpi/ch_44_logo.png
index 409b5df4..be6cbd3b 100644
--- a/tests/input/res/drawable-xhdpi/ch_44_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_44_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_450_logo.png b/tests/input/res/drawable-xhdpi/ch_450_logo.png
index bdcd5bdb..8e25df9a 100644
--- a/tests/input/res/drawable-xhdpi/ch_450_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_450_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_451_logo.png b/tests/input/res/drawable-xhdpi/ch_451_logo.png
index 4339f74c..c744e56e 100644
--- a/tests/input/res/drawable-xhdpi/ch_451_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_451_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_452_logo.png b/tests/input/res/drawable-xhdpi/ch_452_logo.png
index b7a403fa..050b0196 100644
--- a/tests/input/res/drawable-xhdpi/ch_452_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_452_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_453_logo.png b/tests/input/res/drawable-xhdpi/ch_453_logo.png
index 4e234270..4ccdbf14 100644
--- a/tests/input/res/drawable-xhdpi/ch_453_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_453_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_454_logo.png b/tests/input/res/drawable-xhdpi/ch_454_logo.png
index 4873c1ec..10aa3779 100644
--- a/tests/input/res/drawable-xhdpi/ch_454_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_454_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_455_logo.png b/tests/input/res/drawable-xhdpi/ch_455_logo.png
index 2c7dcffe..7b607a6c 100644
--- a/tests/input/res/drawable-xhdpi/ch_455_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_455_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_456_logo.png b/tests/input/res/drawable-xhdpi/ch_456_logo.png
index 05a2db14..f2d57066 100644
--- a/tests/input/res/drawable-xhdpi/ch_456_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_456_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_457_logo.png b/tests/input/res/drawable-xhdpi/ch_457_logo.png
index 7772b418..483e5912 100644
--- a/tests/input/res/drawable-xhdpi/ch_457_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_457_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_458_logo.png b/tests/input/res/drawable-xhdpi/ch_458_logo.png
index e44d6c92..447d5942 100644
--- a/tests/input/res/drawable-xhdpi/ch_458_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_458_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_459_logo.png b/tests/input/res/drawable-xhdpi/ch_459_logo.png
index a946b148..80d6c5b6 100644
--- a/tests/input/res/drawable-xhdpi/ch_459_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_459_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_45_logo.png b/tests/input/res/drawable-xhdpi/ch_45_logo.png
index fc725dbf..0db467c8 100644
--- a/tests/input/res/drawable-xhdpi/ch_45_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_45_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_460_logo.png b/tests/input/res/drawable-xhdpi/ch_460_logo.png
index bb19236d..22d785cb 100644
--- a/tests/input/res/drawable-xhdpi/ch_460_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_460_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_461_logo.png b/tests/input/res/drawable-xhdpi/ch_461_logo.png
index be531cf0..658a1046 100644
--- a/tests/input/res/drawable-xhdpi/ch_461_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_461_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_462_logo.png b/tests/input/res/drawable-xhdpi/ch_462_logo.png
index c7568f3e..dd0c5d14 100644
--- a/tests/input/res/drawable-xhdpi/ch_462_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_462_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_463_logo.png b/tests/input/res/drawable-xhdpi/ch_463_logo.png
index 3ac05577..7b72b915 100644
--- a/tests/input/res/drawable-xhdpi/ch_463_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_463_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_464_logo.png b/tests/input/res/drawable-xhdpi/ch_464_logo.png
index 35d263e2..cc15444c 100644
--- a/tests/input/res/drawable-xhdpi/ch_464_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_464_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_465_logo.png b/tests/input/res/drawable-xhdpi/ch_465_logo.png
index 44e94fa8..a17cb719 100644
--- a/tests/input/res/drawable-xhdpi/ch_465_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_465_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_466_logo.png b/tests/input/res/drawable-xhdpi/ch_466_logo.png
index 453b1085..604644f4 100644
--- a/tests/input/res/drawable-xhdpi/ch_466_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_466_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_467_logo.png b/tests/input/res/drawable-xhdpi/ch_467_logo.png
index c1577d0f..4c74b50d 100644
--- a/tests/input/res/drawable-xhdpi/ch_467_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_467_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_468_logo.png b/tests/input/res/drawable-xhdpi/ch_468_logo.png
index 11238603..8e329206 100644
--- a/tests/input/res/drawable-xhdpi/ch_468_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_468_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_469_logo.png b/tests/input/res/drawable-xhdpi/ch_469_logo.png
index e0373ea6..14a1d99e 100644
--- a/tests/input/res/drawable-xhdpi/ch_469_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_469_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_46_logo.png b/tests/input/res/drawable-xhdpi/ch_46_logo.png
index 0c9b740e..f9d83ea9 100644
--- a/tests/input/res/drawable-xhdpi/ch_46_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_46_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_470_logo.png b/tests/input/res/drawable-xhdpi/ch_470_logo.png
index aa04ce40..567e879a 100644
--- a/tests/input/res/drawable-xhdpi/ch_470_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_470_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_471_logo.png b/tests/input/res/drawable-xhdpi/ch_471_logo.png
index b2793a22..4a128a0e 100644
--- a/tests/input/res/drawable-xhdpi/ch_471_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_471_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_472_logo.png b/tests/input/res/drawable-xhdpi/ch_472_logo.png
index d00ea6a4..f00d1cb0 100644
--- a/tests/input/res/drawable-xhdpi/ch_472_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_472_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_473_logo.png b/tests/input/res/drawable-xhdpi/ch_473_logo.png
index 9fcb5c65..ee7bbfc9 100644
--- a/tests/input/res/drawable-xhdpi/ch_473_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_473_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_474_logo.png b/tests/input/res/drawable-xhdpi/ch_474_logo.png
index 8e13450c..a1b7e0eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_474_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_474_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_475_logo.png b/tests/input/res/drawable-xhdpi/ch_475_logo.png
index ebb96f74..14db7abe 100644
--- a/tests/input/res/drawable-xhdpi/ch_475_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_475_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_476_logo.png b/tests/input/res/drawable-xhdpi/ch_476_logo.png
index 39a81c4b..89c71e80 100644
--- a/tests/input/res/drawable-xhdpi/ch_476_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_476_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_477_logo.png b/tests/input/res/drawable-xhdpi/ch_477_logo.png
index 48ec00de..60509130 100644
--- a/tests/input/res/drawable-xhdpi/ch_477_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_477_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_478_logo.png b/tests/input/res/drawable-xhdpi/ch_478_logo.png
index b6e08715..a2c3069b 100644
--- a/tests/input/res/drawable-xhdpi/ch_478_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_478_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_479_logo.png b/tests/input/res/drawable-xhdpi/ch_479_logo.png
index 5d964709..2be6ae4f 100644
--- a/tests/input/res/drawable-xhdpi/ch_479_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_479_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_47_logo.png b/tests/input/res/drawable-xhdpi/ch_47_logo.png
index b4aee717..ed4b464a 100644
--- a/tests/input/res/drawable-xhdpi/ch_47_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_47_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_480_logo.png b/tests/input/res/drawable-xhdpi/ch_480_logo.png
index 708ab0cb..f2a2d6fa 100644
--- a/tests/input/res/drawable-xhdpi/ch_480_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_480_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_481_logo.png b/tests/input/res/drawable-xhdpi/ch_481_logo.png
index 019de9d6..b71fcfa8 100644
--- a/tests/input/res/drawable-xhdpi/ch_481_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_481_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_482_logo.png b/tests/input/res/drawable-xhdpi/ch_482_logo.png
index 1399a206..8d317e47 100644
--- a/tests/input/res/drawable-xhdpi/ch_482_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_482_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_483_logo.png b/tests/input/res/drawable-xhdpi/ch_483_logo.png
index cca5aef0..ea417f9e 100644
--- a/tests/input/res/drawable-xhdpi/ch_483_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_483_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_484_logo.png b/tests/input/res/drawable-xhdpi/ch_484_logo.png
index 5c2fd6b2..b46584a4 100644
--- a/tests/input/res/drawable-xhdpi/ch_484_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_484_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_485_logo.png b/tests/input/res/drawable-xhdpi/ch_485_logo.png
index 7e239c2b..3564dcd5 100644
--- a/tests/input/res/drawable-xhdpi/ch_485_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_485_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_486_logo.png b/tests/input/res/drawable-xhdpi/ch_486_logo.png
index 7b26dc96..8227575f 100644
--- a/tests/input/res/drawable-xhdpi/ch_486_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_486_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_487_logo.png b/tests/input/res/drawable-xhdpi/ch_487_logo.png
index 24c5f25b..edb15bee 100644
--- a/tests/input/res/drawable-xhdpi/ch_487_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_487_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_488_logo.png b/tests/input/res/drawable-xhdpi/ch_488_logo.png
index ca4c76fc..f358d335 100644
--- a/tests/input/res/drawable-xhdpi/ch_488_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_488_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_489_logo.png b/tests/input/res/drawable-xhdpi/ch_489_logo.png
index a139bbc4..5122c67e 100644
--- a/tests/input/res/drawable-xhdpi/ch_489_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_489_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_48_logo.png b/tests/input/res/drawable-xhdpi/ch_48_logo.png
index 28e01441..e1be7313 100644
--- a/tests/input/res/drawable-xhdpi/ch_48_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_48_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_490_logo.png b/tests/input/res/drawable-xhdpi/ch_490_logo.png
index 25634d4f..1901d995 100644
--- a/tests/input/res/drawable-xhdpi/ch_490_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_490_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_491_logo.png b/tests/input/res/drawable-xhdpi/ch_491_logo.png
index fa5b6d3f..04b0a021 100644
--- a/tests/input/res/drawable-xhdpi/ch_491_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_491_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_492_logo.png b/tests/input/res/drawable-xhdpi/ch_492_logo.png
index ce5443fd..b18dea9b 100644
--- a/tests/input/res/drawable-xhdpi/ch_492_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_492_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_493_logo.png b/tests/input/res/drawable-xhdpi/ch_493_logo.png
index 717787cf..19044655 100644
--- a/tests/input/res/drawable-xhdpi/ch_493_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_493_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_494_logo.png b/tests/input/res/drawable-xhdpi/ch_494_logo.png
index 46d78ffb..b5b0f76c 100644
--- a/tests/input/res/drawable-xhdpi/ch_494_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_494_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_495_logo.png b/tests/input/res/drawable-xhdpi/ch_495_logo.png
index d55b34df..6124dc83 100644
--- a/tests/input/res/drawable-xhdpi/ch_495_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_495_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_496_logo.png b/tests/input/res/drawable-xhdpi/ch_496_logo.png
index 85fc1f89..6b0e472b 100644
--- a/tests/input/res/drawable-xhdpi/ch_496_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_496_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_497_logo.png b/tests/input/res/drawable-xhdpi/ch_497_logo.png
index c4e9843d..31fcd048 100644
--- a/tests/input/res/drawable-xhdpi/ch_497_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_497_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_498_logo.png b/tests/input/res/drawable-xhdpi/ch_498_logo.png
index 1b027ad4..472c09b6 100644
--- a/tests/input/res/drawable-xhdpi/ch_498_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_498_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_499_logo.png b/tests/input/res/drawable-xhdpi/ch_499_logo.png
index 25464c7a..2d653f61 100644
--- a/tests/input/res/drawable-xhdpi/ch_499_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_499_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_49_logo.png b/tests/input/res/drawable-xhdpi/ch_49_logo.png
index 979d7a16..46bc774d 100644
--- a/tests/input/res/drawable-xhdpi/ch_49_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_49_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_4_logo.png b/tests/input/res/drawable-xhdpi/ch_4_logo.png
index bdcba74f..d5e6517c 100644
--- a/tests/input/res/drawable-xhdpi/ch_4_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_4_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_500_logo.png b/tests/input/res/drawable-xhdpi/ch_500_logo.png
index c7666c60..ecfa17ec 100644
--- a/tests/input/res/drawable-xhdpi/ch_500_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_500_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_501_logo.png b/tests/input/res/drawable-xhdpi/ch_501_logo.png
index f3902ad6..0c81a787 100644
--- a/tests/input/res/drawable-xhdpi/ch_501_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_501_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_502_logo.png b/tests/input/res/drawable-xhdpi/ch_502_logo.png
index 6d3d3a56..5dd20644 100644
--- a/tests/input/res/drawable-xhdpi/ch_502_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_502_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_503_logo.png b/tests/input/res/drawable-xhdpi/ch_503_logo.png
index 8e729042..a48ec52d 100644
--- a/tests/input/res/drawable-xhdpi/ch_503_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_503_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_504_logo.png b/tests/input/res/drawable-xhdpi/ch_504_logo.png
index 72347b6e..999a641e 100644
--- a/tests/input/res/drawable-xhdpi/ch_504_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_504_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_505_logo.png b/tests/input/res/drawable-xhdpi/ch_505_logo.png
index c50cce8c..d7c600e4 100644
--- a/tests/input/res/drawable-xhdpi/ch_505_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_505_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_506_logo.png b/tests/input/res/drawable-xhdpi/ch_506_logo.png
index a56cbe5d..ac80e6dd 100644
--- a/tests/input/res/drawable-xhdpi/ch_506_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_506_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_507_logo.png b/tests/input/res/drawable-xhdpi/ch_507_logo.png
index f5dbb30f..c4d434f8 100644
--- a/tests/input/res/drawable-xhdpi/ch_507_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_507_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_508_logo.png b/tests/input/res/drawable-xhdpi/ch_508_logo.png
index 62ed0c19..35330059 100644
--- a/tests/input/res/drawable-xhdpi/ch_508_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_508_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_509_logo.png b/tests/input/res/drawable-xhdpi/ch_509_logo.png
index 513444a0..2077eac5 100644
--- a/tests/input/res/drawable-xhdpi/ch_509_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_509_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_50_logo.png b/tests/input/res/drawable-xhdpi/ch_50_logo.png
index 8d347d77..901373e6 100644
--- a/tests/input/res/drawable-xhdpi/ch_50_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_50_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_510_logo.png b/tests/input/res/drawable-xhdpi/ch_510_logo.png
index ebf5f565..469bf77d 100644
--- a/tests/input/res/drawable-xhdpi/ch_510_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_510_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_511_logo.png b/tests/input/res/drawable-xhdpi/ch_511_logo.png
index 3a062b08..80d727bb 100644
--- a/tests/input/res/drawable-xhdpi/ch_511_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_511_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_512_logo.png b/tests/input/res/drawable-xhdpi/ch_512_logo.png
index 1660c8fe..37ba7e2b 100644
--- a/tests/input/res/drawable-xhdpi/ch_512_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_512_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_513_logo.png b/tests/input/res/drawable-xhdpi/ch_513_logo.png
index 24a4ac12..ef7c4f2a 100644
--- a/tests/input/res/drawable-xhdpi/ch_513_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_513_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_514_logo.png b/tests/input/res/drawable-xhdpi/ch_514_logo.png
index 83b7c4ce..450f5963 100644
--- a/tests/input/res/drawable-xhdpi/ch_514_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_514_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_515_logo.png b/tests/input/res/drawable-xhdpi/ch_515_logo.png
index dcd64054..6533b2fd 100644
--- a/tests/input/res/drawable-xhdpi/ch_515_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_515_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_516_logo.png b/tests/input/res/drawable-xhdpi/ch_516_logo.png
index 20f6f8f2..08cd2f0d 100644
--- a/tests/input/res/drawable-xhdpi/ch_516_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_516_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_517_logo.png b/tests/input/res/drawable-xhdpi/ch_517_logo.png
index 9630234e..1935d709 100644
--- a/tests/input/res/drawable-xhdpi/ch_517_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_517_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_518_logo.png b/tests/input/res/drawable-xhdpi/ch_518_logo.png
index 65f85a37..806fbbbf 100644
--- a/tests/input/res/drawable-xhdpi/ch_518_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_518_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_519_logo.png b/tests/input/res/drawable-xhdpi/ch_519_logo.png
index c963ef2a..938bb559 100644
--- a/tests/input/res/drawable-xhdpi/ch_519_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_519_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_51_logo.png b/tests/input/res/drawable-xhdpi/ch_51_logo.png
index ecf8f5d5..07a5f4ad 100644
--- a/tests/input/res/drawable-xhdpi/ch_51_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_51_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_520_logo.png b/tests/input/res/drawable-xhdpi/ch_520_logo.png
index b6ad9b49..7f9f68b2 100644
--- a/tests/input/res/drawable-xhdpi/ch_520_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_520_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_521_logo.png b/tests/input/res/drawable-xhdpi/ch_521_logo.png
index 874185ea..e8d0432c 100644
--- a/tests/input/res/drawable-xhdpi/ch_521_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_521_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_522_logo.png b/tests/input/res/drawable-xhdpi/ch_522_logo.png
index ea273252..d7345b8c 100644
--- a/tests/input/res/drawable-xhdpi/ch_522_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_522_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_523_logo.png b/tests/input/res/drawable-xhdpi/ch_523_logo.png
index eb27f052..61573120 100644
--- a/tests/input/res/drawable-xhdpi/ch_523_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_523_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_524_logo.png b/tests/input/res/drawable-xhdpi/ch_524_logo.png
index e3ea1563..9a8b2fdd 100644
--- a/tests/input/res/drawable-xhdpi/ch_524_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_524_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_525_logo.png b/tests/input/res/drawable-xhdpi/ch_525_logo.png
index 2321e786..9ed318fa 100644
--- a/tests/input/res/drawable-xhdpi/ch_525_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_525_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_526_logo.png b/tests/input/res/drawable-xhdpi/ch_526_logo.png
index 57c0e5f2..5000af2a 100644
--- a/tests/input/res/drawable-xhdpi/ch_526_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_526_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_527_logo.png b/tests/input/res/drawable-xhdpi/ch_527_logo.png
index cad756c2..38fbd9eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_527_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_527_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_528_logo.png b/tests/input/res/drawable-xhdpi/ch_528_logo.png
index be46d47f..565e8b2a 100644
--- a/tests/input/res/drawable-xhdpi/ch_528_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_528_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_529_logo.png b/tests/input/res/drawable-xhdpi/ch_529_logo.png
index 54fece7f..b0924df7 100644
--- a/tests/input/res/drawable-xhdpi/ch_529_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_529_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_52_logo.png b/tests/input/res/drawable-xhdpi/ch_52_logo.png
index ec3eb477..6faa9702 100644
--- a/tests/input/res/drawable-xhdpi/ch_52_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_52_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_530_logo.png b/tests/input/res/drawable-xhdpi/ch_530_logo.png
index 27709060..0eec0234 100644
--- a/tests/input/res/drawable-xhdpi/ch_530_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_530_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_531_logo.png b/tests/input/res/drawable-xhdpi/ch_531_logo.png
index 44c6b84a..2f0243d1 100644
--- a/tests/input/res/drawable-xhdpi/ch_531_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_531_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_532_logo.png b/tests/input/res/drawable-xhdpi/ch_532_logo.png
index e6076ce1..a6ece89e 100644
--- a/tests/input/res/drawable-xhdpi/ch_532_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_532_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_533_logo.png b/tests/input/res/drawable-xhdpi/ch_533_logo.png
index 3d19a963..a1695158 100644
--- a/tests/input/res/drawable-xhdpi/ch_533_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_533_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_534_logo.png b/tests/input/res/drawable-xhdpi/ch_534_logo.png
index 50784977..00ad0b07 100644
--- a/tests/input/res/drawable-xhdpi/ch_534_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_534_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_535_logo.png b/tests/input/res/drawable-xhdpi/ch_535_logo.png
index 8163a96f..a536ff32 100644
--- a/tests/input/res/drawable-xhdpi/ch_535_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_535_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_536_logo.png b/tests/input/res/drawable-xhdpi/ch_536_logo.png
index a03f9e04..60fcdf33 100644
--- a/tests/input/res/drawable-xhdpi/ch_536_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_536_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_537_logo.png b/tests/input/res/drawable-xhdpi/ch_537_logo.png
index 17434611..0446d9bc 100644
--- a/tests/input/res/drawable-xhdpi/ch_537_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_537_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_538_logo.png b/tests/input/res/drawable-xhdpi/ch_538_logo.png
index 3141c0dc..6f98e08d 100644
--- a/tests/input/res/drawable-xhdpi/ch_538_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_538_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_539_logo.png b/tests/input/res/drawable-xhdpi/ch_539_logo.png
index b110e032..b6f17bbb 100644
--- a/tests/input/res/drawable-xhdpi/ch_539_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_539_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_53_logo.png b/tests/input/res/drawable-xhdpi/ch_53_logo.png
index 0e656758..441e1d97 100644
--- a/tests/input/res/drawable-xhdpi/ch_53_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_53_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_540_logo.png b/tests/input/res/drawable-xhdpi/ch_540_logo.png
index 8ebf4165..61950bff 100644
--- a/tests/input/res/drawable-xhdpi/ch_540_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_540_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_541_logo.png b/tests/input/res/drawable-xhdpi/ch_541_logo.png
index 3e1af08b..eea9a988 100644
--- a/tests/input/res/drawable-xhdpi/ch_541_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_541_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_542_logo.png b/tests/input/res/drawable-xhdpi/ch_542_logo.png
index d5f22057..684cf6d1 100644
--- a/tests/input/res/drawable-xhdpi/ch_542_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_542_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_543_logo.png b/tests/input/res/drawable-xhdpi/ch_543_logo.png
index 3e0f7509..44e4e6e0 100644
--- a/tests/input/res/drawable-xhdpi/ch_543_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_543_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_544_logo.png b/tests/input/res/drawable-xhdpi/ch_544_logo.png
index d86af336..adf6c97a 100644
--- a/tests/input/res/drawable-xhdpi/ch_544_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_544_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_545_logo.png b/tests/input/res/drawable-xhdpi/ch_545_logo.png
index 17660161..57f8edc6 100644
--- a/tests/input/res/drawable-xhdpi/ch_545_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_545_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_546_logo.png b/tests/input/res/drawable-xhdpi/ch_546_logo.png
index 50f6511f..4ac92311 100644
--- a/tests/input/res/drawable-xhdpi/ch_546_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_546_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_547_logo.png b/tests/input/res/drawable-xhdpi/ch_547_logo.png
index cea4ddc5..ca857974 100644
--- a/tests/input/res/drawable-xhdpi/ch_547_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_547_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_548_logo.png b/tests/input/res/drawable-xhdpi/ch_548_logo.png
index 22e8cde1..1037011c 100644
--- a/tests/input/res/drawable-xhdpi/ch_548_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_548_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_549_logo.png b/tests/input/res/drawable-xhdpi/ch_549_logo.png
index 517abc60..fd10a2ee 100644
--- a/tests/input/res/drawable-xhdpi/ch_549_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_549_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_54_logo.png b/tests/input/res/drawable-xhdpi/ch_54_logo.png
index b5ab64d8..50f22f48 100644
--- a/tests/input/res/drawable-xhdpi/ch_54_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_54_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_550_logo.png b/tests/input/res/drawable-xhdpi/ch_550_logo.png
index 34000a65..992666b6 100644
--- a/tests/input/res/drawable-xhdpi/ch_550_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_550_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_551_logo.png b/tests/input/res/drawable-xhdpi/ch_551_logo.png
index f64a3f9b..41369f0b 100644
--- a/tests/input/res/drawable-xhdpi/ch_551_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_551_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_552_logo.png b/tests/input/res/drawable-xhdpi/ch_552_logo.png
index 2c814f31..56be3e73 100644
--- a/tests/input/res/drawable-xhdpi/ch_552_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_552_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_553_logo.png b/tests/input/res/drawable-xhdpi/ch_553_logo.png
index 6feb5fd5..04812119 100644
--- a/tests/input/res/drawable-xhdpi/ch_553_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_553_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_554_logo.png b/tests/input/res/drawable-xhdpi/ch_554_logo.png
index 4fc0815a..b7e943a3 100644
--- a/tests/input/res/drawable-xhdpi/ch_554_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_554_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_555_logo.png b/tests/input/res/drawable-xhdpi/ch_555_logo.png
index b156f760..fb74741b 100644
--- a/tests/input/res/drawable-xhdpi/ch_555_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_555_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_556_logo.png b/tests/input/res/drawable-xhdpi/ch_556_logo.png
index 6db0f725..8c6d4046 100644
--- a/tests/input/res/drawable-xhdpi/ch_556_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_556_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_557_logo.png b/tests/input/res/drawable-xhdpi/ch_557_logo.png
index b718c7d4..fe65c25c 100644
--- a/tests/input/res/drawable-xhdpi/ch_557_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_557_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_558_logo.png b/tests/input/res/drawable-xhdpi/ch_558_logo.png
index 3a031f7c..598e6424 100644
--- a/tests/input/res/drawable-xhdpi/ch_558_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_558_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_559_logo.png b/tests/input/res/drawable-xhdpi/ch_559_logo.png
index 21e086d3..68a46085 100644
--- a/tests/input/res/drawable-xhdpi/ch_559_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_559_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_55_logo.png b/tests/input/res/drawable-xhdpi/ch_55_logo.png
index d5aa5fc9..59f21e84 100644
--- a/tests/input/res/drawable-xhdpi/ch_55_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_55_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_560_logo.png b/tests/input/res/drawable-xhdpi/ch_560_logo.png
index 0862c7e2..db6d6693 100644
--- a/tests/input/res/drawable-xhdpi/ch_560_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_560_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_561_logo.png b/tests/input/res/drawable-xhdpi/ch_561_logo.png
index 0ae7b9fb..b53f08f0 100644
--- a/tests/input/res/drawable-xhdpi/ch_561_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_561_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_562_logo.png b/tests/input/res/drawable-xhdpi/ch_562_logo.png
index e3b0e337..970f0174 100644
--- a/tests/input/res/drawable-xhdpi/ch_562_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_562_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_563_logo.png b/tests/input/res/drawable-xhdpi/ch_563_logo.png
index 35d8552f..1c426378 100644
--- a/tests/input/res/drawable-xhdpi/ch_563_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_563_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_564_logo.png b/tests/input/res/drawable-xhdpi/ch_564_logo.png
index 1e5d0750..61a89f16 100644
--- a/tests/input/res/drawable-xhdpi/ch_564_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_564_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_565_logo.png b/tests/input/res/drawable-xhdpi/ch_565_logo.png
index c5e0c341..956342b2 100644
--- a/tests/input/res/drawable-xhdpi/ch_565_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_565_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_566_logo.png b/tests/input/res/drawable-xhdpi/ch_566_logo.png
index a2178ba0..a935ec4a 100644
--- a/tests/input/res/drawable-xhdpi/ch_566_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_566_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_567_logo.png b/tests/input/res/drawable-xhdpi/ch_567_logo.png
index 66b56918..4d6e407e 100644
--- a/tests/input/res/drawable-xhdpi/ch_567_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_567_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_568_logo.png b/tests/input/res/drawable-xhdpi/ch_568_logo.png
index ef977e4c..f4578ed0 100644
--- a/tests/input/res/drawable-xhdpi/ch_568_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_568_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_569_logo.png b/tests/input/res/drawable-xhdpi/ch_569_logo.png
index f234dfd2..807c7323 100644
--- a/tests/input/res/drawable-xhdpi/ch_569_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_569_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_56_logo.png b/tests/input/res/drawable-xhdpi/ch_56_logo.png
index da62a21a..dc296510 100644
--- a/tests/input/res/drawable-xhdpi/ch_56_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_56_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_570_logo.png b/tests/input/res/drawable-xhdpi/ch_570_logo.png
index 61e8e57a..ef03c654 100644
--- a/tests/input/res/drawable-xhdpi/ch_570_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_570_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_571_logo.png b/tests/input/res/drawable-xhdpi/ch_571_logo.png
index 4a62e9f0..422f9aa4 100644
--- a/tests/input/res/drawable-xhdpi/ch_571_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_571_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_572_logo.png b/tests/input/res/drawable-xhdpi/ch_572_logo.png
index c4b7638a..68d08376 100644
--- a/tests/input/res/drawable-xhdpi/ch_572_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_572_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_573_logo.png b/tests/input/res/drawable-xhdpi/ch_573_logo.png
index 458544be..1d8ca402 100644
--- a/tests/input/res/drawable-xhdpi/ch_573_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_573_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_574_logo.png b/tests/input/res/drawable-xhdpi/ch_574_logo.png
index 0c29bf9f..f582224a 100644
--- a/tests/input/res/drawable-xhdpi/ch_574_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_574_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_575_logo.png b/tests/input/res/drawable-xhdpi/ch_575_logo.png
index 51397746..44fc827b 100644
--- a/tests/input/res/drawable-xhdpi/ch_575_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_575_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_576_logo.png b/tests/input/res/drawable-xhdpi/ch_576_logo.png
index ba443bd8..a8c9b36d 100644
--- a/tests/input/res/drawable-xhdpi/ch_576_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_576_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_577_logo.png b/tests/input/res/drawable-xhdpi/ch_577_logo.png
index d7fa7f31..328c67a9 100644
--- a/tests/input/res/drawable-xhdpi/ch_577_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_577_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_578_logo.png b/tests/input/res/drawable-xhdpi/ch_578_logo.png
index 30464d8e..d856dac5 100644
--- a/tests/input/res/drawable-xhdpi/ch_578_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_578_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_579_logo.png b/tests/input/res/drawable-xhdpi/ch_579_logo.png
index a43e8d6f..2a989c37 100644
--- a/tests/input/res/drawable-xhdpi/ch_579_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_579_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_57_logo.png b/tests/input/res/drawable-xhdpi/ch_57_logo.png
index ce0f92f8..72981424 100644
--- a/tests/input/res/drawable-xhdpi/ch_57_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_57_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_580_logo.png b/tests/input/res/drawable-xhdpi/ch_580_logo.png
index 97db5776..4c8034c8 100644
--- a/tests/input/res/drawable-xhdpi/ch_580_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_580_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_581_logo.png b/tests/input/res/drawable-xhdpi/ch_581_logo.png
index f2c1dc72..7423ef65 100644
--- a/tests/input/res/drawable-xhdpi/ch_581_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_581_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_582_logo.png b/tests/input/res/drawable-xhdpi/ch_582_logo.png
index 0941a065..ffbc803d 100644
--- a/tests/input/res/drawable-xhdpi/ch_582_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_582_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_583_logo.png b/tests/input/res/drawable-xhdpi/ch_583_logo.png
index 02de0c0b..d6b92dce 100644
--- a/tests/input/res/drawable-xhdpi/ch_583_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_583_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_584_logo.png b/tests/input/res/drawable-xhdpi/ch_584_logo.png
index 213822f2..cecbe6c7 100644
--- a/tests/input/res/drawable-xhdpi/ch_584_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_584_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_585_logo.png b/tests/input/res/drawable-xhdpi/ch_585_logo.png
index dedf2b25..99b994f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_585_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_585_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_586_logo.png b/tests/input/res/drawable-xhdpi/ch_586_logo.png
index a2b6b734..a54afdd4 100644
--- a/tests/input/res/drawable-xhdpi/ch_586_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_586_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_587_logo.png b/tests/input/res/drawable-xhdpi/ch_587_logo.png
index 7fad4ebb..e09f40ff 100644
--- a/tests/input/res/drawable-xhdpi/ch_587_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_587_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_588_logo.png b/tests/input/res/drawable-xhdpi/ch_588_logo.png
index 95bac09c..e4b3c192 100644
--- a/tests/input/res/drawable-xhdpi/ch_588_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_588_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_589_logo.png b/tests/input/res/drawable-xhdpi/ch_589_logo.png
index a991b260..2c451a54 100644
--- a/tests/input/res/drawable-xhdpi/ch_589_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_589_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_58_logo.png b/tests/input/res/drawable-xhdpi/ch_58_logo.png
index ac701108..07f71a01 100644
--- a/tests/input/res/drawable-xhdpi/ch_58_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_58_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_590_logo.png b/tests/input/res/drawable-xhdpi/ch_590_logo.png
index a34664f7..56e5e60c 100644
--- a/tests/input/res/drawable-xhdpi/ch_590_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_590_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_591_logo.png b/tests/input/res/drawable-xhdpi/ch_591_logo.png
index 67809b8a..09e1a554 100644
--- a/tests/input/res/drawable-xhdpi/ch_591_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_591_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_592_logo.png b/tests/input/res/drawable-xhdpi/ch_592_logo.png
index 7af17289..82635ce4 100644
--- a/tests/input/res/drawable-xhdpi/ch_592_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_592_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_593_logo.png b/tests/input/res/drawable-xhdpi/ch_593_logo.png
index a07c2451..21f8e54c 100644
--- a/tests/input/res/drawable-xhdpi/ch_593_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_593_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_594_logo.png b/tests/input/res/drawable-xhdpi/ch_594_logo.png
index 59b8565b..8de16c08 100644
--- a/tests/input/res/drawable-xhdpi/ch_594_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_594_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_595_logo.png b/tests/input/res/drawable-xhdpi/ch_595_logo.png
index 063905a4..7fd01896 100644
--- a/tests/input/res/drawable-xhdpi/ch_595_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_595_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_596_logo.png b/tests/input/res/drawable-xhdpi/ch_596_logo.png
index 1ab7ff66..35452d61 100644
--- a/tests/input/res/drawable-xhdpi/ch_596_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_596_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_597_logo.png b/tests/input/res/drawable-xhdpi/ch_597_logo.png
index f8be3409..c812338a 100644
--- a/tests/input/res/drawable-xhdpi/ch_597_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_597_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_598_logo.png b/tests/input/res/drawable-xhdpi/ch_598_logo.png
index 55f93ba1..6a7a4da0 100644
--- a/tests/input/res/drawable-xhdpi/ch_598_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_598_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_599_logo.png b/tests/input/res/drawable-xhdpi/ch_599_logo.png
index b1038a22..9bb000ac 100644
--- a/tests/input/res/drawable-xhdpi/ch_599_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_599_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_59_logo.png b/tests/input/res/drawable-xhdpi/ch_59_logo.png
index df3f65ad..a7a0155f 100644
--- a/tests/input/res/drawable-xhdpi/ch_59_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_59_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_5_logo.png b/tests/input/res/drawable-xhdpi/ch_5_logo.png
index b9a72610..2de0c9cc 100644
--- a/tests/input/res/drawable-xhdpi/ch_5_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_5_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_600_logo.png b/tests/input/res/drawable-xhdpi/ch_600_logo.png
index de16f61c..e3b247e9 100644
--- a/tests/input/res/drawable-xhdpi/ch_600_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_600_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_601_logo.png b/tests/input/res/drawable-xhdpi/ch_601_logo.png
index 9bbf9dad..ff572b8c 100644
--- a/tests/input/res/drawable-xhdpi/ch_601_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_601_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_602_logo.png b/tests/input/res/drawable-xhdpi/ch_602_logo.png
index 72b291c5..56d0505a 100644
--- a/tests/input/res/drawable-xhdpi/ch_602_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_602_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_603_logo.png b/tests/input/res/drawable-xhdpi/ch_603_logo.png
index 14c3a5eb..e0d30043 100644
--- a/tests/input/res/drawable-xhdpi/ch_603_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_603_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_604_logo.png b/tests/input/res/drawable-xhdpi/ch_604_logo.png
index c4b9edc7..4a592ff9 100644
--- a/tests/input/res/drawable-xhdpi/ch_604_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_604_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_605_logo.png b/tests/input/res/drawable-xhdpi/ch_605_logo.png
index 2f1150af..e415b276 100644
--- a/tests/input/res/drawable-xhdpi/ch_605_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_605_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_606_logo.png b/tests/input/res/drawable-xhdpi/ch_606_logo.png
index e87a1d30..2c7b490b 100644
--- a/tests/input/res/drawable-xhdpi/ch_606_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_606_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_607_logo.png b/tests/input/res/drawable-xhdpi/ch_607_logo.png
index 73fb5fec..649d0327 100644
--- a/tests/input/res/drawable-xhdpi/ch_607_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_607_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_608_logo.png b/tests/input/res/drawable-xhdpi/ch_608_logo.png
index 0a084556..5581b4d9 100644
--- a/tests/input/res/drawable-xhdpi/ch_608_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_608_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_609_logo.png b/tests/input/res/drawable-xhdpi/ch_609_logo.png
index fb9b4d49..da8f4bb3 100644
--- a/tests/input/res/drawable-xhdpi/ch_609_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_609_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_60_logo.png b/tests/input/res/drawable-xhdpi/ch_60_logo.png
index 2d98ef39..0ee771f8 100644
--- a/tests/input/res/drawable-xhdpi/ch_60_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_60_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_610_logo.png b/tests/input/res/drawable-xhdpi/ch_610_logo.png
index 468b1d90..7cdbcbd6 100644
--- a/tests/input/res/drawable-xhdpi/ch_610_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_610_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_611_logo.png b/tests/input/res/drawable-xhdpi/ch_611_logo.png
index 0ae9d397..b14d3f54 100644
--- a/tests/input/res/drawable-xhdpi/ch_611_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_611_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_612_logo.png b/tests/input/res/drawable-xhdpi/ch_612_logo.png
index c2f003dc..d56de9ff 100644
--- a/tests/input/res/drawable-xhdpi/ch_612_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_612_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_613_logo.png b/tests/input/res/drawable-xhdpi/ch_613_logo.png
index d8ddd450..7cfec8b5 100644
--- a/tests/input/res/drawable-xhdpi/ch_613_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_613_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_614_logo.png b/tests/input/res/drawable-xhdpi/ch_614_logo.png
index 2db895ce..cc7841ce 100644
--- a/tests/input/res/drawable-xhdpi/ch_614_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_614_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_615_logo.png b/tests/input/res/drawable-xhdpi/ch_615_logo.png
index e5bd8e5a..6c38d269 100644
--- a/tests/input/res/drawable-xhdpi/ch_615_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_615_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_616_logo.png b/tests/input/res/drawable-xhdpi/ch_616_logo.png
index ca6d8baf..e11b777d 100644
--- a/tests/input/res/drawable-xhdpi/ch_616_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_616_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_617_logo.png b/tests/input/res/drawable-xhdpi/ch_617_logo.png
index 830998f6..78aeb608 100644
--- a/tests/input/res/drawable-xhdpi/ch_617_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_617_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_618_logo.png b/tests/input/res/drawable-xhdpi/ch_618_logo.png
index b95b2235..e1f883fb 100644
--- a/tests/input/res/drawable-xhdpi/ch_618_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_618_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_619_logo.png b/tests/input/res/drawable-xhdpi/ch_619_logo.png
index fcb8b5b6..75f4eeba 100644
--- a/tests/input/res/drawable-xhdpi/ch_619_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_619_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_61_logo.png b/tests/input/res/drawable-xhdpi/ch_61_logo.png
index 46f8a3c6..801cb923 100644
--- a/tests/input/res/drawable-xhdpi/ch_61_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_61_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_620_logo.png b/tests/input/res/drawable-xhdpi/ch_620_logo.png
index a9120460..b6380b73 100644
--- a/tests/input/res/drawable-xhdpi/ch_620_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_620_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_621_logo.png b/tests/input/res/drawable-xhdpi/ch_621_logo.png
index 552af5ef..e6a53185 100644
--- a/tests/input/res/drawable-xhdpi/ch_621_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_621_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_622_logo.png b/tests/input/res/drawable-xhdpi/ch_622_logo.png
index 87e1bcfd..1cde4b8f 100644
--- a/tests/input/res/drawable-xhdpi/ch_622_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_622_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_623_logo.png b/tests/input/res/drawable-xhdpi/ch_623_logo.png
index eb187bbc..f271e516 100644
--- a/tests/input/res/drawable-xhdpi/ch_623_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_623_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_624_logo.png b/tests/input/res/drawable-xhdpi/ch_624_logo.png
index 8615a41f..21343a8c 100644
--- a/tests/input/res/drawable-xhdpi/ch_624_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_624_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_625_logo.png b/tests/input/res/drawable-xhdpi/ch_625_logo.png
index d75d7c0f..e15b9853 100644
--- a/tests/input/res/drawable-xhdpi/ch_625_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_625_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_626_logo.png b/tests/input/res/drawable-xhdpi/ch_626_logo.png
index 41d8d0df..c1f8e273 100644
--- a/tests/input/res/drawable-xhdpi/ch_626_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_626_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_627_logo.png b/tests/input/res/drawable-xhdpi/ch_627_logo.png
index 5dd145bf..c07973b5 100644
--- a/tests/input/res/drawable-xhdpi/ch_627_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_627_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_628_logo.png b/tests/input/res/drawable-xhdpi/ch_628_logo.png
index 455eb4dd..369240ca 100644
--- a/tests/input/res/drawable-xhdpi/ch_628_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_628_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_629_logo.png b/tests/input/res/drawable-xhdpi/ch_629_logo.png
index 41f69d00..ac9f7bd7 100644
--- a/tests/input/res/drawable-xhdpi/ch_629_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_629_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_62_logo.png b/tests/input/res/drawable-xhdpi/ch_62_logo.png
index f5f4e383..c4b48ea7 100644
--- a/tests/input/res/drawable-xhdpi/ch_62_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_62_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_630_logo.png b/tests/input/res/drawable-xhdpi/ch_630_logo.png
index bdb78df6..4959855a 100644
--- a/tests/input/res/drawable-xhdpi/ch_630_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_630_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_631_logo.png b/tests/input/res/drawable-xhdpi/ch_631_logo.png
index 548526c3..e03e2706 100644
--- a/tests/input/res/drawable-xhdpi/ch_631_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_631_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_632_logo.png b/tests/input/res/drawable-xhdpi/ch_632_logo.png
index 708ee74c..5be9d478 100644
--- a/tests/input/res/drawable-xhdpi/ch_632_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_632_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_633_logo.png b/tests/input/res/drawable-xhdpi/ch_633_logo.png
index 996cf780..9c51c4a7 100644
--- a/tests/input/res/drawable-xhdpi/ch_633_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_633_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_634_logo.png b/tests/input/res/drawable-xhdpi/ch_634_logo.png
index 2fe92b32..72d30bc6 100644
--- a/tests/input/res/drawable-xhdpi/ch_634_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_634_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_635_logo.png b/tests/input/res/drawable-xhdpi/ch_635_logo.png
index 353c3b42..6c03f3c5 100644
--- a/tests/input/res/drawable-xhdpi/ch_635_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_635_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_636_logo.png b/tests/input/res/drawable-xhdpi/ch_636_logo.png
index aef47ced..928a67c2 100644
--- a/tests/input/res/drawable-xhdpi/ch_636_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_636_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_637_logo.png b/tests/input/res/drawable-xhdpi/ch_637_logo.png
index 5f61016c..4a07f186 100644
--- a/tests/input/res/drawable-xhdpi/ch_637_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_637_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_638_logo.png b/tests/input/res/drawable-xhdpi/ch_638_logo.png
index 5b280f70..33813958 100644
--- a/tests/input/res/drawable-xhdpi/ch_638_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_638_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_639_logo.png b/tests/input/res/drawable-xhdpi/ch_639_logo.png
index 81b537e5..be6ba122 100644
--- a/tests/input/res/drawable-xhdpi/ch_639_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_639_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_63_logo.png b/tests/input/res/drawable-xhdpi/ch_63_logo.png
index 128205f7..dd84e2e6 100644
--- a/tests/input/res/drawable-xhdpi/ch_63_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_63_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_640_logo.png b/tests/input/res/drawable-xhdpi/ch_640_logo.png
index 17935dcd..f6e1750c 100644
--- a/tests/input/res/drawable-xhdpi/ch_640_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_640_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_641_logo.png b/tests/input/res/drawable-xhdpi/ch_641_logo.png
index bae9b10e..421019c8 100644
--- a/tests/input/res/drawable-xhdpi/ch_641_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_641_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_642_logo.png b/tests/input/res/drawable-xhdpi/ch_642_logo.png
index b0f9f91c..e441876c 100644
--- a/tests/input/res/drawable-xhdpi/ch_642_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_642_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_643_logo.png b/tests/input/res/drawable-xhdpi/ch_643_logo.png
index a8b84a80..29745014 100644
--- a/tests/input/res/drawable-xhdpi/ch_643_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_643_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_644_logo.png b/tests/input/res/drawable-xhdpi/ch_644_logo.png
index 05940f12..f5e4f2a0 100644
--- a/tests/input/res/drawable-xhdpi/ch_644_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_644_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_645_logo.png b/tests/input/res/drawable-xhdpi/ch_645_logo.png
index 6f99f635..bfa0d2cd 100644
--- a/tests/input/res/drawable-xhdpi/ch_645_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_645_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_646_logo.png b/tests/input/res/drawable-xhdpi/ch_646_logo.png
index dc114cbc..d148f910 100644
--- a/tests/input/res/drawable-xhdpi/ch_646_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_646_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_647_logo.png b/tests/input/res/drawable-xhdpi/ch_647_logo.png
index 8a5fd7e4..cccc2c66 100644
--- a/tests/input/res/drawable-xhdpi/ch_647_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_647_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_648_logo.png b/tests/input/res/drawable-xhdpi/ch_648_logo.png
index 0aa2f162..1fa3cad7 100644
--- a/tests/input/res/drawable-xhdpi/ch_648_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_648_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_649_logo.png b/tests/input/res/drawable-xhdpi/ch_649_logo.png
index 507a0856..0958fd36 100644
--- a/tests/input/res/drawable-xhdpi/ch_649_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_649_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_64_logo.png b/tests/input/res/drawable-xhdpi/ch_64_logo.png
index c65289ce..9a6a84ec 100644
--- a/tests/input/res/drawable-xhdpi/ch_64_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_64_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_650_logo.png b/tests/input/res/drawable-xhdpi/ch_650_logo.png
index 9f523276..bd3ab1f0 100644
--- a/tests/input/res/drawable-xhdpi/ch_650_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_650_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_651_logo.png b/tests/input/res/drawable-xhdpi/ch_651_logo.png
index 73bc87ca..03e859a0 100644
--- a/tests/input/res/drawable-xhdpi/ch_651_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_651_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_652_logo.png b/tests/input/res/drawable-xhdpi/ch_652_logo.png
index f99d75c8..81b61689 100644
--- a/tests/input/res/drawable-xhdpi/ch_652_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_652_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_653_logo.png b/tests/input/res/drawable-xhdpi/ch_653_logo.png
index 9edeef1e..f6665e5f 100644
--- a/tests/input/res/drawable-xhdpi/ch_653_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_653_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_654_logo.png b/tests/input/res/drawable-xhdpi/ch_654_logo.png
index c94b8708..6ca0e57c 100644
--- a/tests/input/res/drawable-xhdpi/ch_654_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_654_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_655_logo.png b/tests/input/res/drawable-xhdpi/ch_655_logo.png
index ea3251c0..51e7b392 100644
--- a/tests/input/res/drawable-xhdpi/ch_655_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_655_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_656_logo.png b/tests/input/res/drawable-xhdpi/ch_656_logo.png
index 5ea07b59..bae25480 100644
--- a/tests/input/res/drawable-xhdpi/ch_656_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_656_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_657_logo.png b/tests/input/res/drawable-xhdpi/ch_657_logo.png
index 2cce7067..029e91c9 100644
--- a/tests/input/res/drawable-xhdpi/ch_657_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_657_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_658_logo.png b/tests/input/res/drawable-xhdpi/ch_658_logo.png
index 28b87454..61a77eac 100644
--- a/tests/input/res/drawable-xhdpi/ch_658_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_658_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_659_logo.png b/tests/input/res/drawable-xhdpi/ch_659_logo.png
index 73285caf..f12e97ee 100644
--- a/tests/input/res/drawable-xhdpi/ch_659_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_659_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_65_logo.png b/tests/input/res/drawable-xhdpi/ch_65_logo.png
index 81d7ac20..b770749e 100644
--- a/tests/input/res/drawable-xhdpi/ch_65_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_65_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_660_logo.png b/tests/input/res/drawable-xhdpi/ch_660_logo.png
index b49cfac0..1408fb45 100644
--- a/tests/input/res/drawable-xhdpi/ch_660_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_660_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_661_logo.png b/tests/input/res/drawable-xhdpi/ch_661_logo.png
index 3ce1072b..f8224b76 100644
--- a/tests/input/res/drawable-xhdpi/ch_661_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_661_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_662_logo.png b/tests/input/res/drawable-xhdpi/ch_662_logo.png
index e29aa8f8..08d36a1b 100644
--- a/tests/input/res/drawable-xhdpi/ch_662_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_662_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_663_logo.png b/tests/input/res/drawable-xhdpi/ch_663_logo.png
index 0f8da210..b95c596c 100644
--- a/tests/input/res/drawable-xhdpi/ch_663_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_663_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_664_logo.png b/tests/input/res/drawable-xhdpi/ch_664_logo.png
index 9b1d9111..4c42427a 100644
--- a/tests/input/res/drawable-xhdpi/ch_664_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_664_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_665_logo.png b/tests/input/res/drawable-xhdpi/ch_665_logo.png
index d8fae363..c8918dce 100644
--- a/tests/input/res/drawable-xhdpi/ch_665_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_665_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_666_logo.png b/tests/input/res/drawable-xhdpi/ch_666_logo.png
index e3efa18c..6839f828 100644
--- a/tests/input/res/drawable-xhdpi/ch_666_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_666_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_667_logo.png b/tests/input/res/drawable-xhdpi/ch_667_logo.png
index 70572014..28702195 100644
--- a/tests/input/res/drawable-xhdpi/ch_667_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_667_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_668_logo.png b/tests/input/res/drawable-xhdpi/ch_668_logo.png
index 04b3f3ac..944a8d46 100644
--- a/tests/input/res/drawable-xhdpi/ch_668_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_668_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_669_logo.png b/tests/input/res/drawable-xhdpi/ch_669_logo.png
index 6067444b..2677744f 100644
--- a/tests/input/res/drawable-xhdpi/ch_669_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_669_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_66_logo.png b/tests/input/res/drawable-xhdpi/ch_66_logo.png
index d07139c0..e298eb86 100644
--- a/tests/input/res/drawable-xhdpi/ch_66_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_66_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_670_logo.png b/tests/input/res/drawable-xhdpi/ch_670_logo.png
index e2e7206b..bcb1d377 100644
--- a/tests/input/res/drawable-xhdpi/ch_670_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_670_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_671_logo.png b/tests/input/res/drawable-xhdpi/ch_671_logo.png
index 51e54b94..3e01dba8 100644
--- a/tests/input/res/drawable-xhdpi/ch_671_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_671_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_672_logo.png b/tests/input/res/drawable-xhdpi/ch_672_logo.png
index 88dfea80..478d3f22 100644
--- a/tests/input/res/drawable-xhdpi/ch_672_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_672_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_673_logo.png b/tests/input/res/drawable-xhdpi/ch_673_logo.png
index 00090169..123522db 100644
--- a/tests/input/res/drawable-xhdpi/ch_673_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_673_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_674_logo.png b/tests/input/res/drawable-xhdpi/ch_674_logo.png
index 4931fadb..25c44806 100644
--- a/tests/input/res/drawable-xhdpi/ch_674_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_674_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_675_logo.png b/tests/input/res/drawable-xhdpi/ch_675_logo.png
index d82d3bdb..223ba448 100644
--- a/tests/input/res/drawable-xhdpi/ch_675_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_675_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_676_logo.png b/tests/input/res/drawable-xhdpi/ch_676_logo.png
index c4735ac7..12cca720 100644
--- a/tests/input/res/drawable-xhdpi/ch_676_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_676_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_677_logo.png b/tests/input/res/drawable-xhdpi/ch_677_logo.png
index 4d099f48..ec735de1 100644
--- a/tests/input/res/drawable-xhdpi/ch_677_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_677_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_678_logo.png b/tests/input/res/drawable-xhdpi/ch_678_logo.png
index 3680766d..1eee9496 100644
--- a/tests/input/res/drawable-xhdpi/ch_678_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_678_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_679_logo.png b/tests/input/res/drawable-xhdpi/ch_679_logo.png
index c36ef2e5..231b68eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_679_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_679_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_67_logo.png b/tests/input/res/drawable-xhdpi/ch_67_logo.png
index d01eade6..5fcf7946 100644
--- a/tests/input/res/drawable-xhdpi/ch_67_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_67_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_680_logo.png b/tests/input/res/drawable-xhdpi/ch_680_logo.png
index 2fef4629..24c09b87 100644
--- a/tests/input/res/drawable-xhdpi/ch_680_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_680_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_681_logo.png b/tests/input/res/drawable-xhdpi/ch_681_logo.png
index ae68f8c6..2bae5da6 100644
--- a/tests/input/res/drawable-xhdpi/ch_681_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_681_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_682_logo.png b/tests/input/res/drawable-xhdpi/ch_682_logo.png
index 7eac1354..6bb1047f 100644
--- a/tests/input/res/drawable-xhdpi/ch_682_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_682_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_683_logo.png b/tests/input/res/drawable-xhdpi/ch_683_logo.png
index 27a8fdf4..04be69f4 100644
--- a/tests/input/res/drawable-xhdpi/ch_683_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_683_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_684_logo.png b/tests/input/res/drawable-xhdpi/ch_684_logo.png
index 1eba95fe..02e0666d 100644
--- a/tests/input/res/drawable-xhdpi/ch_684_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_684_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_685_logo.png b/tests/input/res/drawable-xhdpi/ch_685_logo.png
index 21f49b0e..ff410e54 100644
--- a/tests/input/res/drawable-xhdpi/ch_685_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_685_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_686_logo.png b/tests/input/res/drawable-xhdpi/ch_686_logo.png
index 0b3f511f..f93e7d7f 100644
--- a/tests/input/res/drawable-xhdpi/ch_686_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_686_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_687_logo.png b/tests/input/res/drawable-xhdpi/ch_687_logo.png
index 37d380c5..a97a96f4 100644
--- a/tests/input/res/drawable-xhdpi/ch_687_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_687_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_688_logo.png b/tests/input/res/drawable-xhdpi/ch_688_logo.png
index 5d0d78fd..f094f64c 100644
--- a/tests/input/res/drawable-xhdpi/ch_688_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_688_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_689_logo.png b/tests/input/res/drawable-xhdpi/ch_689_logo.png
index 4f3ae717..c557b3f1 100644
--- a/tests/input/res/drawable-xhdpi/ch_689_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_689_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_68_logo.png b/tests/input/res/drawable-xhdpi/ch_68_logo.png
index 28284848..957bcb55 100644
--- a/tests/input/res/drawable-xhdpi/ch_68_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_68_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_690_logo.png b/tests/input/res/drawable-xhdpi/ch_690_logo.png
index 50d8ccfb..ee692d35 100644
--- a/tests/input/res/drawable-xhdpi/ch_690_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_690_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_691_logo.png b/tests/input/res/drawable-xhdpi/ch_691_logo.png
index 2a6957b0..7087605e 100644
--- a/tests/input/res/drawable-xhdpi/ch_691_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_691_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_692_logo.png b/tests/input/res/drawable-xhdpi/ch_692_logo.png
index 245e0b28..902b536f 100644
--- a/tests/input/res/drawable-xhdpi/ch_692_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_692_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_693_logo.png b/tests/input/res/drawable-xhdpi/ch_693_logo.png
index ccc1d79c..3fb1634e 100644
--- a/tests/input/res/drawable-xhdpi/ch_693_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_693_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_694_logo.png b/tests/input/res/drawable-xhdpi/ch_694_logo.png
index 3141e0fc..baaa7b69 100644
--- a/tests/input/res/drawable-xhdpi/ch_694_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_694_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_695_logo.png b/tests/input/res/drawable-xhdpi/ch_695_logo.png
index 96eabf5d..1d957bfd 100644
--- a/tests/input/res/drawable-xhdpi/ch_695_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_695_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_696_logo.png b/tests/input/res/drawable-xhdpi/ch_696_logo.png
index 1e127f7c..ca8ed9e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_696_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_696_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_697_logo.png b/tests/input/res/drawable-xhdpi/ch_697_logo.png
index 45f91a89..e01c4825 100644
--- a/tests/input/res/drawable-xhdpi/ch_697_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_697_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_698_logo.png b/tests/input/res/drawable-xhdpi/ch_698_logo.png
index 920ec7af..c6540359 100644
--- a/tests/input/res/drawable-xhdpi/ch_698_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_698_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_699_logo.png b/tests/input/res/drawable-xhdpi/ch_699_logo.png
index 0f2c79f4..70a22946 100644
--- a/tests/input/res/drawable-xhdpi/ch_699_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_699_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_69_logo.png b/tests/input/res/drawable-xhdpi/ch_69_logo.png
index f4ba87ce..6ccbe33b 100644
--- a/tests/input/res/drawable-xhdpi/ch_69_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_69_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_6_logo.png b/tests/input/res/drawable-xhdpi/ch_6_logo.png
index 017af150..22887a6c 100644
--- a/tests/input/res/drawable-xhdpi/ch_6_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_6_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_700_logo.png b/tests/input/res/drawable-xhdpi/ch_700_logo.png
index 764bf18d..1cbf5379 100644
--- a/tests/input/res/drawable-xhdpi/ch_700_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_700_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_701_logo.png b/tests/input/res/drawable-xhdpi/ch_701_logo.png
index 02385412..9b438c00 100644
--- a/tests/input/res/drawable-xhdpi/ch_701_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_701_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_702_logo.png b/tests/input/res/drawable-xhdpi/ch_702_logo.png
index 812cfe7d..92bef76d 100644
--- a/tests/input/res/drawable-xhdpi/ch_702_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_702_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_703_logo.png b/tests/input/res/drawable-xhdpi/ch_703_logo.png
index 2a8173b6..78d680b0 100644
--- a/tests/input/res/drawable-xhdpi/ch_703_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_703_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_704_logo.png b/tests/input/res/drawable-xhdpi/ch_704_logo.png
index 320f5833..fcb61adb 100644
--- a/tests/input/res/drawable-xhdpi/ch_704_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_704_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_705_logo.png b/tests/input/res/drawable-xhdpi/ch_705_logo.png
index a92a1e1f..87566617 100644
--- a/tests/input/res/drawable-xhdpi/ch_705_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_705_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_706_logo.png b/tests/input/res/drawable-xhdpi/ch_706_logo.png
index 6e159bea..fe9d775b 100644
--- a/tests/input/res/drawable-xhdpi/ch_706_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_706_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_707_logo.png b/tests/input/res/drawable-xhdpi/ch_707_logo.png
index 3e61c6c8..b3b0451c 100644
--- a/tests/input/res/drawable-xhdpi/ch_707_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_707_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_708_logo.png b/tests/input/res/drawable-xhdpi/ch_708_logo.png
index b8a8ce34..2a95b3a4 100644
--- a/tests/input/res/drawable-xhdpi/ch_708_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_708_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_709_logo.png b/tests/input/res/drawable-xhdpi/ch_709_logo.png
index 2ca3238b..55111fbe 100644
--- a/tests/input/res/drawable-xhdpi/ch_709_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_709_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_70_logo.png b/tests/input/res/drawable-xhdpi/ch_70_logo.png
index 7d72badf..1860ec9c 100644
--- a/tests/input/res/drawable-xhdpi/ch_70_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_70_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_710_logo.png b/tests/input/res/drawable-xhdpi/ch_710_logo.png
index 563b7493..6284e6ee 100644
--- a/tests/input/res/drawable-xhdpi/ch_710_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_710_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_711_logo.png b/tests/input/res/drawable-xhdpi/ch_711_logo.png
index 6c8de85b..d55d32ca 100644
--- a/tests/input/res/drawable-xhdpi/ch_711_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_711_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_712_logo.png b/tests/input/res/drawable-xhdpi/ch_712_logo.png
index 1b0fa6fb..7268941c 100644
--- a/tests/input/res/drawable-xhdpi/ch_712_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_712_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_713_logo.png b/tests/input/res/drawable-xhdpi/ch_713_logo.png
index c2f89dc8..781301e4 100644
--- a/tests/input/res/drawable-xhdpi/ch_713_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_713_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_714_logo.png b/tests/input/res/drawable-xhdpi/ch_714_logo.png
index 83a159d6..8145eaac 100644
--- a/tests/input/res/drawable-xhdpi/ch_714_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_714_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_715_logo.png b/tests/input/res/drawable-xhdpi/ch_715_logo.png
index 07b54ade..b7715dc5 100644
--- a/tests/input/res/drawable-xhdpi/ch_715_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_715_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_716_logo.png b/tests/input/res/drawable-xhdpi/ch_716_logo.png
index 2d0e1320..0c1f26e4 100644
--- a/tests/input/res/drawable-xhdpi/ch_716_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_716_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_717_logo.png b/tests/input/res/drawable-xhdpi/ch_717_logo.png
index dbe319b3..de20828f 100644
--- a/tests/input/res/drawable-xhdpi/ch_717_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_717_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_718_logo.png b/tests/input/res/drawable-xhdpi/ch_718_logo.png
index 91525ffc..8d915ecc 100644
--- a/tests/input/res/drawable-xhdpi/ch_718_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_718_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_719_logo.png b/tests/input/res/drawable-xhdpi/ch_719_logo.png
index f0219111..bd1c668d 100644
--- a/tests/input/res/drawable-xhdpi/ch_719_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_719_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_71_logo.png b/tests/input/res/drawable-xhdpi/ch_71_logo.png
index 286b88a0..e3f8b550 100644
--- a/tests/input/res/drawable-xhdpi/ch_71_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_71_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_720_logo.png b/tests/input/res/drawable-xhdpi/ch_720_logo.png
index a26db569..66a60923 100644
--- a/tests/input/res/drawable-xhdpi/ch_720_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_720_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_721_logo.png b/tests/input/res/drawable-xhdpi/ch_721_logo.png
index bda52ec3..c877d396 100644
--- a/tests/input/res/drawable-xhdpi/ch_721_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_721_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_722_logo.png b/tests/input/res/drawable-xhdpi/ch_722_logo.png
index 9d1dfc5e..9fe37161 100644
--- a/tests/input/res/drawable-xhdpi/ch_722_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_722_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_723_logo.png b/tests/input/res/drawable-xhdpi/ch_723_logo.png
index 0148215f..94563ccd 100644
--- a/tests/input/res/drawable-xhdpi/ch_723_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_723_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_724_logo.png b/tests/input/res/drawable-xhdpi/ch_724_logo.png
index 4a07ad49..52e5fcd9 100644
--- a/tests/input/res/drawable-xhdpi/ch_724_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_724_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_725_logo.png b/tests/input/res/drawable-xhdpi/ch_725_logo.png
index 833fc93d..518fefaa 100644
--- a/tests/input/res/drawable-xhdpi/ch_725_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_725_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_726_logo.png b/tests/input/res/drawable-xhdpi/ch_726_logo.png
index 074a4321..1f28222e 100644
--- a/tests/input/res/drawable-xhdpi/ch_726_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_726_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_727_logo.png b/tests/input/res/drawable-xhdpi/ch_727_logo.png
index df12c2a6..bffbc57f 100644
--- a/tests/input/res/drawable-xhdpi/ch_727_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_727_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_728_logo.png b/tests/input/res/drawable-xhdpi/ch_728_logo.png
index 9f2be10b..f036778b 100644
--- a/tests/input/res/drawable-xhdpi/ch_728_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_728_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_729_logo.png b/tests/input/res/drawable-xhdpi/ch_729_logo.png
index c73e460e..a2838d56 100644
--- a/tests/input/res/drawable-xhdpi/ch_729_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_729_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_72_logo.png b/tests/input/res/drawable-xhdpi/ch_72_logo.png
index e50d00f1..5b2f971c 100644
--- a/tests/input/res/drawable-xhdpi/ch_72_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_72_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_730_logo.png b/tests/input/res/drawable-xhdpi/ch_730_logo.png
index d822f3b5..443d08b8 100644
--- a/tests/input/res/drawable-xhdpi/ch_730_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_730_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_731_logo.png b/tests/input/res/drawable-xhdpi/ch_731_logo.png
index c0a057b4..d07e52a1 100644
--- a/tests/input/res/drawable-xhdpi/ch_731_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_731_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_732_logo.png b/tests/input/res/drawable-xhdpi/ch_732_logo.png
index 323da948..56f51b3f 100644
--- a/tests/input/res/drawable-xhdpi/ch_732_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_732_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_733_logo.png b/tests/input/res/drawable-xhdpi/ch_733_logo.png
index 62a6d9b5..18248b0a 100644
--- a/tests/input/res/drawable-xhdpi/ch_733_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_733_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_734_logo.png b/tests/input/res/drawable-xhdpi/ch_734_logo.png
index 19995ea4..fb740e33 100644
--- a/tests/input/res/drawable-xhdpi/ch_734_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_734_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_735_logo.png b/tests/input/res/drawable-xhdpi/ch_735_logo.png
index 3c5f9686..9f83309f 100644
--- a/tests/input/res/drawable-xhdpi/ch_735_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_735_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_736_logo.png b/tests/input/res/drawable-xhdpi/ch_736_logo.png
index 741abecb..768fc5ef 100644
--- a/tests/input/res/drawable-xhdpi/ch_736_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_736_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_737_logo.png b/tests/input/res/drawable-xhdpi/ch_737_logo.png
index f0ee672b..6af65c67 100644
--- a/tests/input/res/drawable-xhdpi/ch_737_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_737_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_738_logo.png b/tests/input/res/drawable-xhdpi/ch_738_logo.png
index 666ffb32..3b908312 100644
--- a/tests/input/res/drawable-xhdpi/ch_738_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_738_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_739_logo.png b/tests/input/res/drawable-xhdpi/ch_739_logo.png
index 8680c2db..fea61e37 100644
--- a/tests/input/res/drawable-xhdpi/ch_739_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_739_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_73_logo.png b/tests/input/res/drawable-xhdpi/ch_73_logo.png
index 604af9a4..13556e6d 100644
--- a/tests/input/res/drawable-xhdpi/ch_73_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_73_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_740_logo.png b/tests/input/res/drawable-xhdpi/ch_740_logo.png
index f666e327..7fe9aa19 100644
--- a/tests/input/res/drawable-xhdpi/ch_740_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_740_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_741_logo.png b/tests/input/res/drawable-xhdpi/ch_741_logo.png
index 2527ce5d..a437fd22 100644
--- a/tests/input/res/drawable-xhdpi/ch_741_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_741_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_742_logo.png b/tests/input/res/drawable-xhdpi/ch_742_logo.png
index c9b1c397..5674dccb 100644
--- a/tests/input/res/drawable-xhdpi/ch_742_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_742_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_743_logo.png b/tests/input/res/drawable-xhdpi/ch_743_logo.png
index 4284b6c4..dbfcaa51 100644
--- a/tests/input/res/drawable-xhdpi/ch_743_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_743_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_744_logo.png b/tests/input/res/drawable-xhdpi/ch_744_logo.png
index 5daf188f..fe6dd633 100644
--- a/tests/input/res/drawable-xhdpi/ch_744_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_744_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_745_logo.png b/tests/input/res/drawable-xhdpi/ch_745_logo.png
index 45a7ff51..703bc014 100644
--- a/tests/input/res/drawable-xhdpi/ch_745_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_745_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_746_logo.png b/tests/input/res/drawable-xhdpi/ch_746_logo.png
index 54a79c1a..15775a4c 100644
--- a/tests/input/res/drawable-xhdpi/ch_746_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_746_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_747_logo.png b/tests/input/res/drawable-xhdpi/ch_747_logo.png
index f854c2e1..d5666758 100644
--- a/tests/input/res/drawable-xhdpi/ch_747_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_747_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_748_logo.png b/tests/input/res/drawable-xhdpi/ch_748_logo.png
index fb7cf30f..3bb80444 100644
--- a/tests/input/res/drawable-xhdpi/ch_748_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_748_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_749_logo.png b/tests/input/res/drawable-xhdpi/ch_749_logo.png
index 332b8bd2..92a6954a 100644
--- a/tests/input/res/drawable-xhdpi/ch_749_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_749_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_74_logo.png b/tests/input/res/drawable-xhdpi/ch_74_logo.png
index cf0250e7..484f4c0d 100644
--- a/tests/input/res/drawable-xhdpi/ch_74_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_74_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_750_logo.png b/tests/input/res/drawable-xhdpi/ch_750_logo.png
index 47300227..96af0fa6 100644
--- a/tests/input/res/drawable-xhdpi/ch_750_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_750_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_751_logo.png b/tests/input/res/drawable-xhdpi/ch_751_logo.png
index 06ad62d8..bddc6d97 100644
--- a/tests/input/res/drawable-xhdpi/ch_751_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_751_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_752_logo.png b/tests/input/res/drawable-xhdpi/ch_752_logo.png
index b263daa3..38d693f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_752_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_752_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_753_logo.png b/tests/input/res/drawable-xhdpi/ch_753_logo.png
index a7aa046c..3c383de7 100644
--- a/tests/input/res/drawable-xhdpi/ch_753_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_753_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_754_logo.png b/tests/input/res/drawable-xhdpi/ch_754_logo.png
index cc3f9f39..04d7b62b 100644
--- a/tests/input/res/drawable-xhdpi/ch_754_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_754_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_755_logo.png b/tests/input/res/drawable-xhdpi/ch_755_logo.png
index e3f5a1ea..d7846b43 100644
--- a/tests/input/res/drawable-xhdpi/ch_755_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_755_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_756_logo.png b/tests/input/res/drawable-xhdpi/ch_756_logo.png
index bd0374bd..6b51e7d1 100644
--- a/tests/input/res/drawable-xhdpi/ch_756_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_756_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_757_logo.png b/tests/input/res/drawable-xhdpi/ch_757_logo.png
index 3d355b6d..b396d7c3 100644
--- a/tests/input/res/drawable-xhdpi/ch_757_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_757_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_758_logo.png b/tests/input/res/drawable-xhdpi/ch_758_logo.png
index 95d35d59..d77783b7 100644
--- a/tests/input/res/drawable-xhdpi/ch_758_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_758_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_759_logo.png b/tests/input/res/drawable-xhdpi/ch_759_logo.png
index dbac83cc..ca26792b 100644
--- a/tests/input/res/drawable-xhdpi/ch_759_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_759_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_75_logo.png b/tests/input/res/drawable-xhdpi/ch_75_logo.png
index 93690282..aa78479e 100644
--- a/tests/input/res/drawable-xhdpi/ch_75_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_75_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_760_logo.png b/tests/input/res/drawable-xhdpi/ch_760_logo.png
index 6a4b3515..5d56db66 100644
--- a/tests/input/res/drawable-xhdpi/ch_760_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_760_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_761_logo.png b/tests/input/res/drawable-xhdpi/ch_761_logo.png
index 90dfd653..e505365d 100644
--- a/tests/input/res/drawable-xhdpi/ch_761_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_761_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_762_logo.png b/tests/input/res/drawable-xhdpi/ch_762_logo.png
index 43aa7a9e..202b7572 100644
--- a/tests/input/res/drawable-xhdpi/ch_762_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_762_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_763_logo.png b/tests/input/res/drawable-xhdpi/ch_763_logo.png
index 3a7a22cc..14af6ab4 100644
--- a/tests/input/res/drawable-xhdpi/ch_763_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_763_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_764_logo.png b/tests/input/res/drawable-xhdpi/ch_764_logo.png
index 1decc311..c4e1ea66 100644
--- a/tests/input/res/drawable-xhdpi/ch_764_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_764_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_765_logo.png b/tests/input/res/drawable-xhdpi/ch_765_logo.png
index 377aecce..3b5ded8e 100644
--- a/tests/input/res/drawable-xhdpi/ch_765_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_765_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_766_logo.png b/tests/input/res/drawable-xhdpi/ch_766_logo.png
index 212a1e2b..61391524 100644
--- a/tests/input/res/drawable-xhdpi/ch_766_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_766_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_767_logo.png b/tests/input/res/drawable-xhdpi/ch_767_logo.png
index d237213e..4fa0441e 100644
--- a/tests/input/res/drawable-xhdpi/ch_767_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_767_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_768_logo.png b/tests/input/res/drawable-xhdpi/ch_768_logo.png
index 863c4be5..80e8293b 100644
--- a/tests/input/res/drawable-xhdpi/ch_768_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_768_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_769_logo.png b/tests/input/res/drawable-xhdpi/ch_769_logo.png
index 9543ddb0..63c2e6cc 100644
--- a/tests/input/res/drawable-xhdpi/ch_769_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_769_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_76_logo.png b/tests/input/res/drawable-xhdpi/ch_76_logo.png
index 3107f033..3ebf6807 100644
--- a/tests/input/res/drawable-xhdpi/ch_76_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_76_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_770_logo.png b/tests/input/res/drawable-xhdpi/ch_770_logo.png
index 2ae7bff5..b2ee3584 100644
--- a/tests/input/res/drawable-xhdpi/ch_770_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_770_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_771_logo.png b/tests/input/res/drawable-xhdpi/ch_771_logo.png
index 3b8e6299..9a53a498 100644
--- a/tests/input/res/drawable-xhdpi/ch_771_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_771_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_772_logo.png b/tests/input/res/drawable-xhdpi/ch_772_logo.png
index b439232b..1da9e70d 100644
--- a/tests/input/res/drawable-xhdpi/ch_772_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_772_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_773_logo.png b/tests/input/res/drawable-xhdpi/ch_773_logo.png
index b3bb644f..0f35e46a 100644
--- a/tests/input/res/drawable-xhdpi/ch_773_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_773_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_774_logo.png b/tests/input/res/drawable-xhdpi/ch_774_logo.png
index 147df7bf..acaa8857 100644
--- a/tests/input/res/drawable-xhdpi/ch_774_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_774_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_775_logo.png b/tests/input/res/drawable-xhdpi/ch_775_logo.png
index 06fb2934..70ca99e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_775_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_775_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_776_logo.png b/tests/input/res/drawable-xhdpi/ch_776_logo.png
index c73f2bd7..ab54947d 100644
--- a/tests/input/res/drawable-xhdpi/ch_776_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_776_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_777_logo.png b/tests/input/res/drawable-xhdpi/ch_777_logo.png
index 2fc8f34b..ed378329 100644
--- a/tests/input/res/drawable-xhdpi/ch_777_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_777_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_778_logo.png b/tests/input/res/drawable-xhdpi/ch_778_logo.png
index 66546159..01cdc4e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_778_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_778_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_779_logo.png b/tests/input/res/drawable-xhdpi/ch_779_logo.png
index 6d8841c4..ca5175f7 100644
--- a/tests/input/res/drawable-xhdpi/ch_779_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_779_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_77_logo.png b/tests/input/res/drawable-xhdpi/ch_77_logo.png
index 01927e94..c22abf24 100644
--- a/tests/input/res/drawable-xhdpi/ch_77_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_77_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_780_logo.png b/tests/input/res/drawable-xhdpi/ch_780_logo.png
index 59683d8f..2e5f24e2 100644
--- a/tests/input/res/drawable-xhdpi/ch_780_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_780_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_781_logo.png b/tests/input/res/drawable-xhdpi/ch_781_logo.png
index a553b0e6..81e5ed66 100644
--- a/tests/input/res/drawable-xhdpi/ch_781_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_781_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_782_logo.png b/tests/input/res/drawable-xhdpi/ch_782_logo.png
index 04dccb8e..3236afa9 100644
--- a/tests/input/res/drawable-xhdpi/ch_782_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_782_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_783_logo.png b/tests/input/res/drawable-xhdpi/ch_783_logo.png
index f1d7afca..a600800e 100644
--- a/tests/input/res/drawable-xhdpi/ch_783_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_783_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_784_logo.png b/tests/input/res/drawable-xhdpi/ch_784_logo.png
index 5feead87..cd97c5eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_784_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_784_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_785_logo.png b/tests/input/res/drawable-xhdpi/ch_785_logo.png
index 393340a3..d50fd82a 100644
--- a/tests/input/res/drawable-xhdpi/ch_785_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_785_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_786_logo.png b/tests/input/res/drawable-xhdpi/ch_786_logo.png
index b3fa139f..7a93ef71 100644
--- a/tests/input/res/drawable-xhdpi/ch_786_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_786_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_787_logo.png b/tests/input/res/drawable-xhdpi/ch_787_logo.png
index d84af6e4..62b5cf6b 100644
--- a/tests/input/res/drawable-xhdpi/ch_787_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_787_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_788_logo.png b/tests/input/res/drawable-xhdpi/ch_788_logo.png
index 1578e21b..c82602d3 100644
--- a/tests/input/res/drawable-xhdpi/ch_788_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_788_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_789_logo.png b/tests/input/res/drawable-xhdpi/ch_789_logo.png
index ac2db334..7dfbeeb3 100644
--- a/tests/input/res/drawable-xhdpi/ch_789_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_789_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_78_logo.png b/tests/input/res/drawable-xhdpi/ch_78_logo.png
index a1b4243b..03fb415f 100644
--- a/tests/input/res/drawable-xhdpi/ch_78_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_78_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_790_logo.png b/tests/input/res/drawable-xhdpi/ch_790_logo.png
index c5d9823e..d44c2181 100644
--- a/tests/input/res/drawable-xhdpi/ch_790_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_790_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_791_logo.png b/tests/input/res/drawable-xhdpi/ch_791_logo.png
index f7e1dacb..ee81b961 100644
--- a/tests/input/res/drawable-xhdpi/ch_791_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_791_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_792_logo.png b/tests/input/res/drawable-xhdpi/ch_792_logo.png
index c15a0044..37715025 100644
--- a/tests/input/res/drawable-xhdpi/ch_792_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_792_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_793_logo.png b/tests/input/res/drawable-xhdpi/ch_793_logo.png
index 280f46f1..eca3a477 100644
--- a/tests/input/res/drawable-xhdpi/ch_793_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_793_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_794_logo.png b/tests/input/res/drawable-xhdpi/ch_794_logo.png
index 9ae6b17f..fbbfc372 100644
--- a/tests/input/res/drawable-xhdpi/ch_794_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_794_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_795_logo.png b/tests/input/res/drawable-xhdpi/ch_795_logo.png
index 7efd3347..0366a2bd 100644
--- a/tests/input/res/drawable-xhdpi/ch_795_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_795_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_796_logo.png b/tests/input/res/drawable-xhdpi/ch_796_logo.png
index 7dda53ce..e13e6bc1 100644
--- a/tests/input/res/drawable-xhdpi/ch_796_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_796_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_797_logo.png b/tests/input/res/drawable-xhdpi/ch_797_logo.png
index 2c93401f..e45decc0 100644
--- a/tests/input/res/drawable-xhdpi/ch_797_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_797_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_798_logo.png b/tests/input/res/drawable-xhdpi/ch_798_logo.png
index 7ee1dd73..6b9659e2 100644
--- a/tests/input/res/drawable-xhdpi/ch_798_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_798_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_799_logo.png b/tests/input/res/drawable-xhdpi/ch_799_logo.png
index ad318c0c..e8cb2ef8 100644
--- a/tests/input/res/drawable-xhdpi/ch_799_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_799_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_79_logo.png b/tests/input/res/drawable-xhdpi/ch_79_logo.png
index e5319376..237fa7b2 100644
--- a/tests/input/res/drawable-xhdpi/ch_79_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_79_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_7_logo.png b/tests/input/res/drawable-xhdpi/ch_7_logo.png
index cf7e0607..df78066a 100644
--- a/tests/input/res/drawable-xhdpi/ch_7_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_7_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_800_logo.png b/tests/input/res/drawable-xhdpi/ch_800_logo.png
index 8a337024..6c775941 100644
--- a/tests/input/res/drawable-xhdpi/ch_800_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_800_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_801_logo.png b/tests/input/res/drawable-xhdpi/ch_801_logo.png
index 46fc4670..f0006515 100644
--- a/tests/input/res/drawable-xhdpi/ch_801_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_801_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_802_logo.png b/tests/input/res/drawable-xhdpi/ch_802_logo.png
index 353122bc..4c504b58 100644
--- a/tests/input/res/drawable-xhdpi/ch_802_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_802_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_803_logo.png b/tests/input/res/drawable-xhdpi/ch_803_logo.png
index 4ec39903..edfa6869 100644
--- a/tests/input/res/drawable-xhdpi/ch_803_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_803_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_804_logo.png b/tests/input/res/drawable-xhdpi/ch_804_logo.png
index 90346cb4..c7b0dba0 100644
--- a/tests/input/res/drawable-xhdpi/ch_804_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_804_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_805_logo.png b/tests/input/res/drawable-xhdpi/ch_805_logo.png
index 6db24339..bcd6ee28 100644
--- a/tests/input/res/drawable-xhdpi/ch_805_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_805_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_806_logo.png b/tests/input/res/drawable-xhdpi/ch_806_logo.png
index f17943d7..e926e9f4 100644
--- a/tests/input/res/drawable-xhdpi/ch_806_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_806_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_807_logo.png b/tests/input/res/drawable-xhdpi/ch_807_logo.png
index c348272c..25334551 100644
--- a/tests/input/res/drawable-xhdpi/ch_807_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_807_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_808_logo.png b/tests/input/res/drawable-xhdpi/ch_808_logo.png
index 3a5a14d6..5d7b51a9 100644
--- a/tests/input/res/drawable-xhdpi/ch_808_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_808_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_809_logo.png b/tests/input/res/drawable-xhdpi/ch_809_logo.png
index ae20572e..2f6a8e31 100644
--- a/tests/input/res/drawable-xhdpi/ch_809_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_809_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_80_logo.png b/tests/input/res/drawable-xhdpi/ch_80_logo.png
index f5572bc1..ff7a55c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_80_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_80_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_810_logo.png b/tests/input/res/drawable-xhdpi/ch_810_logo.png
index 361fb2de..1a083992 100644
--- a/tests/input/res/drawable-xhdpi/ch_810_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_810_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_811_logo.png b/tests/input/res/drawable-xhdpi/ch_811_logo.png
index b006af1e..070df630 100644
--- a/tests/input/res/drawable-xhdpi/ch_811_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_811_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_812_logo.png b/tests/input/res/drawable-xhdpi/ch_812_logo.png
index 9d30f844..376e68cb 100644
--- a/tests/input/res/drawable-xhdpi/ch_812_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_812_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_813_logo.png b/tests/input/res/drawable-xhdpi/ch_813_logo.png
index c1ba8f91..d72f0a8e 100644
--- a/tests/input/res/drawable-xhdpi/ch_813_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_813_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_814_logo.png b/tests/input/res/drawable-xhdpi/ch_814_logo.png
index 68fc2305..b50d9ad1 100644
--- a/tests/input/res/drawable-xhdpi/ch_814_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_814_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_815_logo.png b/tests/input/res/drawable-xhdpi/ch_815_logo.png
index bed3a701..fdbc4cdd 100644
--- a/tests/input/res/drawable-xhdpi/ch_815_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_815_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_816_logo.png b/tests/input/res/drawable-xhdpi/ch_816_logo.png
index 4e67a117..f1212200 100644
--- a/tests/input/res/drawable-xhdpi/ch_816_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_816_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_817_logo.png b/tests/input/res/drawable-xhdpi/ch_817_logo.png
index 59b778f0..be4fa008 100644
--- a/tests/input/res/drawable-xhdpi/ch_817_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_817_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_818_logo.png b/tests/input/res/drawable-xhdpi/ch_818_logo.png
index 9ba78efb..c9d087d7 100644
--- a/tests/input/res/drawable-xhdpi/ch_818_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_818_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_819_logo.png b/tests/input/res/drawable-xhdpi/ch_819_logo.png
index df51ee72..b8cab83d 100644
--- a/tests/input/res/drawable-xhdpi/ch_819_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_819_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_81_logo.png b/tests/input/res/drawable-xhdpi/ch_81_logo.png
index ee3b863a..58f6fc00 100644
--- a/tests/input/res/drawable-xhdpi/ch_81_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_81_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_820_logo.png b/tests/input/res/drawable-xhdpi/ch_820_logo.png
index 729d7e22..3bf591fb 100644
--- a/tests/input/res/drawable-xhdpi/ch_820_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_820_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_821_logo.png b/tests/input/res/drawable-xhdpi/ch_821_logo.png
index 4d23dedf..16046f46 100644
--- a/tests/input/res/drawable-xhdpi/ch_821_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_821_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_822_logo.png b/tests/input/res/drawable-xhdpi/ch_822_logo.png
index c46c673a..58d688c9 100644
--- a/tests/input/res/drawable-xhdpi/ch_822_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_822_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_823_logo.png b/tests/input/res/drawable-xhdpi/ch_823_logo.png
index 587c1cfa..6b70ecc1 100644
--- a/tests/input/res/drawable-xhdpi/ch_823_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_823_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_824_logo.png b/tests/input/res/drawable-xhdpi/ch_824_logo.png
index af3a67e4..4c90c96e 100644
--- a/tests/input/res/drawable-xhdpi/ch_824_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_824_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_825_logo.png b/tests/input/res/drawable-xhdpi/ch_825_logo.png
index 7d03bd53..5111136c 100644
--- a/tests/input/res/drawable-xhdpi/ch_825_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_825_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_826_logo.png b/tests/input/res/drawable-xhdpi/ch_826_logo.png
index 081bf5fe..f35941e8 100644
--- a/tests/input/res/drawable-xhdpi/ch_826_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_826_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_827_logo.png b/tests/input/res/drawable-xhdpi/ch_827_logo.png
index 5a6a0b03..49add1ab 100644
--- a/tests/input/res/drawable-xhdpi/ch_827_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_827_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_828_logo.png b/tests/input/res/drawable-xhdpi/ch_828_logo.png
index 7d480133..67936aa4 100644
--- a/tests/input/res/drawable-xhdpi/ch_828_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_828_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_829_logo.png b/tests/input/res/drawable-xhdpi/ch_829_logo.png
index 8cca81b3..7bc97945 100644
--- a/tests/input/res/drawable-xhdpi/ch_829_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_829_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_82_logo.png b/tests/input/res/drawable-xhdpi/ch_82_logo.png
index f92064a9..ddd21127 100644
--- a/tests/input/res/drawable-xhdpi/ch_82_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_82_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_830_logo.png b/tests/input/res/drawable-xhdpi/ch_830_logo.png
index f15a64b4..3aa669d8 100644
--- a/tests/input/res/drawable-xhdpi/ch_830_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_830_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_831_logo.png b/tests/input/res/drawable-xhdpi/ch_831_logo.png
index e37ae3c4..f7c2cf1c 100644
--- a/tests/input/res/drawable-xhdpi/ch_831_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_831_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_832_logo.png b/tests/input/res/drawable-xhdpi/ch_832_logo.png
index 6083ee11..19096734 100644
--- a/tests/input/res/drawable-xhdpi/ch_832_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_832_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_833_logo.png b/tests/input/res/drawable-xhdpi/ch_833_logo.png
index 70cfab74..d0a1af2f 100644
--- a/tests/input/res/drawable-xhdpi/ch_833_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_833_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_834_logo.png b/tests/input/res/drawable-xhdpi/ch_834_logo.png
index b73153e2..52e2ef58 100644
--- a/tests/input/res/drawable-xhdpi/ch_834_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_834_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_835_logo.png b/tests/input/res/drawable-xhdpi/ch_835_logo.png
index dc4c8faf..7ac421e1 100644
--- a/tests/input/res/drawable-xhdpi/ch_835_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_835_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_836_logo.png b/tests/input/res/drawable-xhdpi/ch_836_logo.png
index 8be46e7c..7f4577b4 100644
--- a/tests/input/res/drawable-xhdpi/ch_836_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_836_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_837_logo.png b/tests/input/res/drawable-xhdpi/ch_837_logo.png
index 3916215f..df5e1c86 100644
--- a/tests/input/res/drawable-xhdpi/ch_837_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_837_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_838_logo.png b/tests/input/res/drawable-xhdpi/ch_838_logo.png
index 72f06bc2..579557ed 100644
--- a/tests/input/res/drawable-xhdpi/ch_838_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_838_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_839_logo.png b/tests/input/res/drawable-xhdpi/ch_839_logo.png
index eeaa5b9a..3988cc5b 100644
--- a/tests/input/res/drawable-xhdpi/ch_839_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_839_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_83_logo.png b/tests/input/res/drawable-xhdpi/ch_83_logo.png
index 240d1191..dd97e15c 100644
--- a/tests/input/res/drawable-xhdpi/ch_83_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_83_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_840_logo.png b/tests/input/res/drawable-xhdpi/ch_840_logo.png
index d5ac3d08..29e88d2a 100644
--- a/tests/input/res/drawable-xhdpi/ch_840_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_840_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_841_logo.png b/tests/input/res/drawable-xhdpi/ch_841_logo.png
index 07aaf457..9ee069a4 100644
--- a/tests/input/res/drawable-xhdpi/ch_841_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_841_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_842_logo.png b/tests/input/res/drawable-xhdpi/ch_842_logo.png
index e475f029..edbd8c57 100644
--- a/tests/input/res/drawable-xhdpi/ch_842_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_842_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_843_logo.png b/tests/input/res/drawable-xhdpi/ch_843_logo.png
index b96dc6f3..7ee70de2 100644
--- a/tests/input/res/drawable-xhdpi/ch_843_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_843_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_844_logo.png b/tests/input/res/drawable-xhdpi/ch_844_logo.png
index cac18521..6a0a95a8 100644
--- a/tests/input/res/drawable-xhdpi/ch_844_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_844_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_845_logo.png b/tests/input/res/drawable-xhdpi/ch_845_logo.png
index 70f28fe8..ae4aa7eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_845_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_845_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_846_logo.png b/tests/input/res/drawable-xhdpi/ch_846_logo.png
index 6d039538..79eb61d9 100644
--- a/tests/input/res/drawable-xhdpi/ch_846_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_846_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_847_logo.png b/tests/input/res/drawable-xhdpi/ch_847_logo.png
index 55052554..2a8fd743 100644
--- a/tests/input/res/drawable-xhdpi/ch_847_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_847_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_848_logo.png b/tests/input/res/drawable-xhdpi/ch_848_logo.png
index cd7d3b1d..c2e82237 100644
--- a/tests/input/res/drawable-xhdpi/ch_848_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_848_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_849_logo.png b/tests/input/res/drawable-xhdpi/ch_849_logo.png
index 87df8860..44d58b8d 100644
--- a/tests/input/res/drawable-xhdpi/ch_849_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_849_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_84_logo.png b/tests/input/res/drawable-xhdpi/ch_84_logo.png
index 21ea6fc6..5ad6a473 100644
--- a/tests/input/res/drawable-xhdpi/ch_84_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_84_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_850_logo.png b/tests/input/res/drawable-xhdpi/ch_850_logo.png
index 68813ef1..358dc326 100644
--- a/tests/input/res/drawable-xhdpi/ch_850_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_850_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_851_logo.png b/tests/input/res/drawable-xhdpi/ch_851_logo.png
index b07cf2d3..7c5ef9cd 100644
--- a/tests/input/res/drawable-xhdpi/ch_851_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_851_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_852_logo.png b/tests/input/res/drawable-xhdpi/ch_852_logo.png
index 61b162ea..0ab1e98b 100644
--- a/tests/input/res/drawable-xhdpi/ch_852_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_852_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_853_logo.png b/tests/input/res/drawable-xhdpi/ch_853_logo.png
index 69942aba..c5b6a11b 100644
--- a/tests/input/res/drawable-xhdpi/ch_853_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_853_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_854_logo.png b/tests/input/res/drawable-xhdpi/ch_854_logo.png
index b0799590..5c34d4e2 100644
--- a/tests/input/res/drawable-xhdpi/ch_854_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_854_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_855_logo.png b/tests/input/res/drawable-xhdpi/ch_855_logo.png
index 3b7696f6..b8f10da8 100644
--- a/tests/input/res/drawable-xhdpi/ch_855_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_855_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_856_logo.png b/tests/input/res/drawable-xhdpi/ch_856_logo.png
index a7e34292..1b790da7 100644
--- a/tests/input/res/drawable-xhdpi/ch_856_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_856_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_857_logo.png b/tests/input/res/drawable-xhdpi/ch_857_logo.png
index 25d4fa7d..a7f3b55d 100644
--- a/tests/input/res/drawable-xhdpi/ch_857_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_857_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_858_logo.png b/tests/input/res/drawable-xhdpi/ch_858_logo.png
index ed1eef3c..e3555be6 100644
--- a/tests/input/res/drawable-xhdpi/ch_858_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_858_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_859_logo.png b/tests/input/res/drawable-xhdpi/ch_859_logo.png
index 1cb63e24..970ee63e 100644
--- a/tests/input/res/drawable-xhdpi/ch_859_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_859_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_85_logo.png b/tests/input/res/drawable-xhdpi/ch_85_logo.png
index a30f2d04..35c5c992 100644
--- a/tests/input/res/drawable-xhdpi/ch_85_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_85_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_860_logo.png b/tests/input/res/drawable-xhdpi/ch_860_logo.png
index d029798d..72720501 100644
--- a/tests/input/res/drawable-xhdpi/ch_860_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_860_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_861_logo.png b/tests/input/res/drawable-xhdpi/ch_861_logo.png
index 3cb709ec..bf6d0be9 100644
--- a/tests/input/res/drawable-xhdpi/ch_861_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_861_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_862_logo.png b/tests/input/res/drawable-xhdpi/ch_862_logo.png
index bd6c8b80..ee6c88f2 100644
--- a/tests/input/res/drawable-xhdpi/ch_862_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_862_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_863_logo.png b/tests/input/res/drawable-xhdpi/ch_863_logo.png
index 4e09cd24..9b92ef30 100644
--- a/tests/input/res/drawable-xhdpi/ch_863_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_863_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_864_logo.png b/tests/input/res/drawable-xhdpi/ch_864_logo.png
index 2682aa31..2024e828 100644
--- a/tests/input/res/drawable-xhdpi/ch_864_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_864_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_865_logo.png b/tests/input/res/drawable-xhdpi/ch_865_logo.png
index 44e6f672..80b87668 100644
--- a/tests/input/res/drawable-xhdpi/ch_865_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_865_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_866_logo.png b/tests/input/res/drawable-xhdpi/ch_866_logo.png
index 00d100d7..6dfe8538 100644
--- a/tests/input/res/drawable-xhdpi/ch_866_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_866_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_867_logo.png b/tests/input/res/drawable-xhdpi/ch_867_logo.png
index 4ff7f1cb..6cb51f22 100644
--- a/tests/input/res/drawable-xhdpi/ch_867_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_867_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_868_logo.png b/tests/input/res/drawable-xhdpi/ch_868_logo.png
index 21b71275..e179e5cf 100644
--- a/tests/input/res/drawable-xhdpi/ch_868_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_868_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_869_logo.png b/tests/input/res/drawable-xhdpi/ch_869_logo.png
index 3b4e1ed1..940780eb 100644
--- a/tests/input/res/drawable-xhdpi/ch_869_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_869_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_86_logo.png b/tests/input/res/drawable-xhdpi/ch_86_logo.png
index 7946763d..93bbad73 100644
--- a/tests/input/res/drawable-xhdpi/ch_86_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_86_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_870_logo.png b/tests/input/res/drawable-xhdpi/ch_870_logo.png
index 402aaaec..caa05fe8 100644
--- a/tests/input/res/drawable-xhdpi/ch_870_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_870_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_871_logo.png b/tests/input/res/drawable-xhdpi/ch_871_logo.png
index 7f10c50b..9085b8a8 100644
--- a/tests/input/res/drawable-xhdpi/ch_871_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_871_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_872_logo.png b/tests/input/res/drawable-xhdpi/ch_872_logo.png
index 78f48b88..695dabaf 100644
--- a/tests/input/res/drawable-xhdpi/ch_872_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_872_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_873_logo.png b/tests/input/res/drawable-xhdpi/ch_873_logo.png
index 57991ed2..21871509 100644
--- a/tests/input/res/drawable-xhdpi/ch_873_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_873_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_874_logo.png b/tests/input/res/drawable-xhdpi/ch_874_logo.png
index 51f28d29..2bbcf9cc 100644
--- a/tests/input/res/drawable-xhdpi/ch_874_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_874_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_875_logo.png b/tests/input/res/drawable-xhdpi/ch_875_logo.png
index 267e6ef9..494b8ebc 100644
--- a/tests/input/res/drawable-xhdpi/ch_875_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_875_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_876_logo.png b/tests/input/res/drawable-xhdpi/ch_876_logo.png
index 948d90d8..eded05e4 100644
--- a/tests/input/res/drawable-xhdpi/ch_876_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_876_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_877_logo.png b/tests/input/res/drawable-xhdpi/ch_877_logo.png
index cdf9884b..cf22732d 100644
--- a/tests/input/res/drawable-xhdpi/ch_877_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_877_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_878_logo.png b/tests/input/res/drawable-xhdpi/ch_878_logo.png
index bdf6a7ee..3ca881cf 100644
--- a/tests/input/res/drawable-xhdpi/ch_878_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_878_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_879_logo.png b/tests/input/res/drawable-xhdpi/ch_879_logo.png
index 24b14eca..8f629b25 100644
--- a/tests/input/res/drawable-xhdpi/ch_879_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_879_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_87_logo.png b/tests/input/res/drawable-xhdpi/ch_87_logo.png
index 01e471c3..1a661da8 100644
--- a/tests/input/res/drawable-xhdpi/ch_87_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_87_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_880_logo.png b/tests/input/res/drawable-xhdpi/ch_880_logo.png
index df7f5bb2..f23459d8 100644
--- a/tests/input/res/drawable-xhdpi/ch_880_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_880_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_881_logo.png b/tests/input/res/drawable-xhdpi/ch_881_logo.png
index 00b73120..810320be 100644
--- a/tests/input/res/drawable-xhdpi/ch_881_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_881_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_882_logo.png b/tests/input/res/drawable-xhdpi/ch_882_logo.png
index 3e0b72f3..cee19fc9 100644
--- a/tests/input/res/drawable-xhdpi/ch_882_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_882_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_883_logo.png b/tests/input/res/drawable-xhdpi/ch_883_logo.png
index d1682429..b7cd2a11 100644
--- a/tests/input/res/drawable-xhdpi/ch_883_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_883_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_884_logo.png b/tests/input/res/drawable-xhdpi/ch_884_logo.png
index 0370ba77..ee24315c 100644
--- a/tests/input/res/drawable-xhdpi/ch_884_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_884_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_885_logo.png b/tests/input/res/drawable-xhdpi/ch_885_logo.png
index 2a602c75..aac4f31f 100644
--- a/tests/input/res/drawable-xhdpi/ch_885_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_885_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_886_logo.png b/tests/input/res/drawable-xhdpi/ch_886_logo.png
index 9366a7e3..d929436e 100644
--- a/tests/input/res/drawable-xhdpi/ch_886_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_886_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_887_logo.png b/tests/input/res/drawable-xhdpi/ch_887_logo.png
index b820c72a..4d38b4c9 100644
--- a/tests/input/res/drawable-xhdpi/ch_887_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_887_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_888_logo.png b/tests/input/res/drawable-xhdpi/ch_888_logo.png
index 8db876d5..b8bf4191 100644
--- a/tests/input/res/drawable-xhdpi/ch_888_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_888_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_889_logo.png b/tests/input/res/drawable-xhdpi/ch_889_logo.png
index 93a4af97..e38f60dd 100644
--- a/tests/input/res/drawable-xhdpi/ch_889_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_889_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_88_logo.png b/tests/input/res/drawable-xhdpi/ch_88_logo.png
index 55277a75..9cf19a3b 100644
--- a/tests/input/res/drawable-xhdpi/ch_88_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_88_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_890_logo.png b/tests/input/res/drawable-xhdpi/ch_890_logo.png
index c7a83324..46e8755c 100644
--- a/tests/input/res/drawable-xhdpi/ch_890_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_890_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_891_logo.png b/tests/input/res/drawable-xhdpi/ch_891_logo.png
index aadf15ab..8fcae156 100644
--- a/tests/input/res/drawable-xhdpi/ch_891_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_891_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_892_logo.png b/tests/input/res/drawable-xhdpi/ch_892_logo.png
index 79a0fed1..4672b7e1 100644
--- a/tests/input/res/drawable-xhdpi/ch_892_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_892_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_893_logo.png b/tests/input/res/drawable-xhdpi/ch_893_logo.png
index a3a9b50f..170586f5 100644
--- a/tests/input/res/drawable-xhdpi/ch_893_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_893_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_894_logo.png b/tests/input/res/drawable-xhdpi/ch_894_logo.png
index a87d9621..4b366898 100644
--- a/tests/input/res/drawable-xhdpi/ch_894_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_894_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_895_logo.png b/tests/input/res/drawable-xhdpi/ch_895_logo.png
index d3a49991..1855d24c 100644
--- a/tests/input/res/drawable-xhdpi/ch_895_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_895_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_896_logo.png b/tests/input/res/drawable-xhdpi/ch_896_logo.png
index 40a75e8a..dc47d447 100644
--- a/tests/input/res/drawable-xhdpi/ch_896_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_896_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_897_logo.png b/tests/input/res/drawable-xhdpi/ch_897_logo.png
index be4eeb27..909a60e0 100644
--- a/tests/input/res/drawable-xhdpi/ch_897_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_897_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_898_logo.png b/tests/input/res/drawable-xhdpi/ch_898_logo.png
index 9a37a1fc..a57a6344 100644
--- a/tests/input/res/drawable-xhdpi/ch_898_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_898_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_899_logo.png b/tests/input/res/drawable-xhdpi/ch_899_logo.png
index 962af4e7..fa99418a 100644
--- a/tests/input/res/drawable-xhdpi/ch_899_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_899_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_89_logo.png b/tests/input/res/drawable-xhdpi/ch_89_logo.png
index 6aadc018..0c7edc8c 100644
--- a/tests/input/res/drawable-xhdpi/ch_89_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_89_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_8_logo.png b/tests/input/res/drawable-xhdpi/ch_8_logo.png
index f34a325b..0886b851 100644
--- a/tests/input/res/drawable-xhdpi/ch_8_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_8_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_900_logo.png b/tests/input/res/drawable-xhdpi/ch_900_logo.png
index fcb8864e..cf6327bb 100644
--- a/tests/input/res/drawable-xhdpi/ch_900_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_900_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_901_logo.png b/tests/input/res/drawable-xhdpi/ch_901_logo.png
index e789fbfd..17e1c9ef 100644
--- a/tests/input/res/drawable-xhdpi/ch_901_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_901_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_902_logo.png b/tests/input/res/drawable-xhdpi/ch_902_logo.png
index 64483003..f98b40cb 100644
--- a/tests/input/res/drawable-xhdpi/ch_902_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_902_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_903_logo.png b/tests/input/res/drawable-xhdpi/ch_903_logo.png
index c8659821..d3d331d8 100644
--- a/tests/input/res/drawable-xhdpi/ch_903_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_903_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_904_logo.png b/tests/input/res/drawable-xhdpi/ch_904_logo.png
index e10b556c..d3e29be6 100644
--- a/tests/input/res/drawable-xhdpi/ch_904_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_904_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_905_logo.png b/tests/input/res/drawable-xhdpi/ch_905_logo.png
index cd328c0a..65ab0adc 100644
--- a/tests/input/res/drawable-xhdpi/ch_905_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_905_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_906_logo.png b/tests/input/res/drawable-xhdpi/ch_906_logo.png
index 546301f1..1cc924d7 100644
--- a/tests/input/res/drawable-xhdpi/ch_906_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_906_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_907_logo.png b/tests/input/res/drawable-xhdpi/ch_907_logo.png
index c281e3ab..9fd37e6e 100644
--- a/tests/input/res/drawable-xhdpi/ch_907_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_907_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_908_logo.png b/tests/input/res/drawable-xhdpi/ch_908_logo.png
index c4d8ef58..15597dba 100644
--- a/tests/input/res/drawable-xhdpi/ch_908_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_908_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_909_logo.png b/tests/input/res/drawable-xhdpi/ch_909_logo.png
index a365e213..db80fbef 100644
--- a/tests/input/res/drawable-xhdpi/ch_909_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_909_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_90_logo.png b/tests/input/res/drawable-xhdpi/ch_90_logo.png
index 5f7d97b6..2f2960da 100644
--- a/tests/input/res/drawable-xhdpi/ch_90_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_90_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_910_logo.png b/tests/input/res/drawable-xhdpi/ch_910_logo.png
index caab3966..dd6f8a31 100644
--- a/tests/input/res/drawable-xhdpi/ch_910_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_910_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_911_logo.png b/tests/input/res/drawable-xhdpi/ch_911_logo.png
index 758aca0a..23266b64 100644
--- a/tests/input/res/drawable-xhdpi/ch_911_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_911_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_912_logo.png b/tests/input/res/drawable-xhdpi/ch_912_logo.png
index 0354e02f..677197d5 100644
--- a/tests/input/res/drawable-xhdpi/ch_912_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_912_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_913_logo.png b/tests/input/res/drawable-xhdpi/ch_913_logo.png
index 03e8d6df..41c4ae03 100644
--- a/tests/input/res/drawable-xhdpi/ch_913_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_913_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_914_logo.png b/tests/input/res/drawable-xhdpi/ch_914_logo.png
index 2604331d..2a2b4a2d 100644
--- a/tests/input/res/drawable-xhdpi/ch_914_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_914_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_915_logo.png b/tests/input/res/drawable-xhdpi/ch_915_logo.png
index 13e5fa97..85941edf 100644
--- a/tests/input/res/drawable-xhdpi/ch_915_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_915_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_916_logo.png b/tests/input/res/drawable-xhdpi/ch_916_logo.png
index e79b57fa..fbf4a41e 100644
--- a/tests/input/res/drawable-xhdpi/ch_916_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_916_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_917_logo.png b/tests/input/res/drawable-xhdpi/ch_917_logo.png
index a964fae1..018dff5e 100644
--- a/tests/input/res/drawable-xhdpi/ch_917_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_917_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_918_logo.png b/tests/input/res/drawable-xhdpi/ch_918_logo.png
index 6ac64434..2c8b0b80 100644
--- a/tests/input/res/drawable-xhdpi/ch_918_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_918_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_919_logo.png b/tests/input/res/drawable-xhdpi/ch_919_logo.png
index e2e6903e..de2e6073 100644
--- a/tests/input/res/drawable-xhdpi/ch_919_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_919_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_91_logo.png b/tests/input/res/drawable-xhdpi/ch_91_logo.png
index 389baf71..3992165b 100644
--- a/tests/input/res/drawable-xhdpi/ch_91_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_91_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_920_logo.png b/tests/input/res/drawable-xhdpi/ch_920_logo.png
index 2e52e5da..33839469 100644
--- a/tests/input/res/drawable-xhdpi/ch_920_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_920_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_921_logo.png b/tests/input/res/drawable-xhdpi/ch_921_logo.png
index 894a745f..019c36f5 100644
--- a/tests/input/res/drawable-xhdpi/ch_921_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_921_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_922_logo.png b/tests/input/res/drawable-xhdpi/ch_922_logo.png
index fc298ce8..79e4e07d 100644
--- a/tests/input/res/drawable-xhdpi/ch_922_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_922_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_923_logo.png b/tests/input/res/drawable-xhdpi/ch_923_logo.png
index a6da18a3..6738d938 100644
--- a/tests/input/res/drawable-xhdpi/ch_923_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_923_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_924_logo.png b/tests/input/res/drawable-xhdpi/ch_924_logo.png
index 47f4eb44..3cbc4e30 100644
--- a/tests/input/res/drawable-xhdpi/ch_924_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_924_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_925_logo.png b/tests/input/res/drawable-xhdpi/ch_925_logo.png
index c0eef60f..500111c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_925_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_925_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_926_logo.png b/tests/input/res/drawable-xhdpi/ch_926_logo.png
index 22e8e23c..bd3f94ad 100644
--- a/tests/input/res/drawable-xhdpi/ch_926_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_926_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_927_logo.png b/tests/input/res/drawable-xhdpi/ch_927_logo.png
index c12e0323..51ad2eaa 100644
--- a/tests/input/res/drawable-xhdpi/ch_927_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_927_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_928_logo.png b/tests/input/res/drawable-xhdpi/ch_928_logo.png
index dde2ba6d..6f579bb3 100644
--- a/tests/input/res/drawable-xhdpi/ch_928_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_928_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_929_logo.png b/tests/input/res/drawable-xhdpi/ch_929_logo.png
index 45ee2aac..79f11bb1 100644
--- a/tests/input/res/drawable-xhdpi/ch_929_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_929_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_92_logo.png b/tests/input/res/drawable-xhdpi/ch_92_logo.png
index 330e7356..25508036 100644
--- a/tests/input/res/drawable-xhdpi/ch_92_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_92_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_930_logo.png b/tests/input/res/drawable-xhdpi/ch_930_logo.png
index ff069e4f..4c06ad09 100644
--- a/tests/input/res/drawable-xhdpi/ch_930_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_930_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_931_logo.png b/tests/input/res/drawable-xhdpi/ch_931_logo.png
index 6be9e00d..b7ac61ff 100644
--- a/tests/input/res/drawable-xhdpi/ch_931_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_931_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_932_logo.png b/tests/input/res/drawable-xhdpi/ch_932_logo.png
index 3e88eb1a..cac5a477 100644
--- a/tests/input/res/drawable-xhdpi/ch_932_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_932_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_933_logo.png b/tests/input/res/drawable-xhdpi/ch_933_logo.png
index 2ea636c3..959f957f 100644
--- a/tests/input/res/drawable-xhdpi/ch_933_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_933_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_934_logo.png b/tests/input/res/drawable-xhdpi/ch_934_logo.png
index 851c63cc..e9e5b263 100644
--- a/tests/input/res/drawable-xhdpi/ch_934_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_934_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_935_logo.png b/tests/input/res/drawable-xhdpi/ch_935_logo.png
index 62633a1e..9741307e 100644
--- a/tests/input/res/drawable-xhdpi/ch_935_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_935_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_936_logo.png b/tests/input/res/drawable-xhdpi/ch_936_logo.png
index 02999f66..2c5964de 100644
--- a/tests/input/res/drawable-xhdpi/ch_936_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_936_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_937_logo.png b/tests/input/res/drawable-xhdpi/ch_937_logo.png
index ba9379d5..5392a73c 100644
--- a/tests/input/res/drawable-xhdpi/ch_937_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_937_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_938_logo.png b/tests/input/res/drawable-xhdpi/ch_938_logo.png
index e2b26506..8350910c 100644
--- a/tests/input/res/drawable-xhdpi/ch_938_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_938_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_939_logo.png b/tests/input/res/drawable-xhdpi/ch_939_logo.png
index 79d16fb7..f0635df0 100644
--- a/tests/input/res/drawable-xhdpi/ch_939_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_939_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_93_logo.png b/tests/input/res/drawable-xhdpi/ch_93_logo.png
index 761b7ab1..976c07cb 100644
--- a/tests/input/res/drawable-xhdpi/ch_93_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_93_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_940_logo.png b/tests/input/res/drawable-xhdpi/ch_940_logo.png
index a324cb67..b9c76dbc 100644
--- a/tests/input/res/drawable-xhdpi/ch_940_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_940_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_941_logo.png b/tests/input/res/drawable-xhdpi/ch_941_logo.png
index e071c1cd..d9e3361f 100644
--- a/tests/input/res/drawable-xhdpi/ch_941_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_941_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_942_logo.png b/tests/input/res/drawable-xhdpi/ch_942_logo.png
index 2e59e50a..997643c1 100644
--- a/tests/input/res/drawable-xhdpi/ch_942_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_942_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_943_logo.png b/tests/input/res/drawable-xhdpi/ch_943_logo.png
index f5d2323a..4c6f1752 100644
--- a/tests/input/res/drawable-xhdpi/ch_943_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_943_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_944_logo.png b/tests/input/res/drawable-xhdpi/ch_944_logo.png
index 823dbba1..40a11f40 100644
--- a/tests/input/res/drawable-xhdpi/ch_944_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_944_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_945_logo.png b/tests/input/res/drawable-xhdpi/ch_945_logo.png
index 0c3cba72..9cc401a7 100644
--- a/tests/input/res/drawable-xhdpi/ch_945_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_945_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_946_logo.png b/tests/input/res/drawable-xhdpi/ch_946_logo.png
index 598f23af..bdb5bab4 100644
--- a/tests/input/res/drawable-xhdpi/ch_946_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_946_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_947_logo.png b/tests/input/res/drawable-xhdpi/ch_947_logo.png
index 735649f3..541b632d 100644
--- a/tests/input/res/drawable-xhdpi/ch_947_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_947_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_948_logo.png b/tests/input/res/drawable-xhdpi/ch_948_logo.png
index 8d032694..4db04738 100644
--- a/tests/input/res/drawable-xhdpi/ch_948_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_948_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_949_logo.png b/tests/input/res/drawable-xhdpi/ch_949_logo.png
index 999a2ea3..399a4e51 100644
--- a/tests/input/res/drawable-xhdpi/ch_949_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_949_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_94_logo.png b/tests/input/res/drawable-xhdpi/ch_94_logo.png
index c9603dbb..e22800b8 100644
--- a/tests/input/res/drawable-xhdpi/ch_94_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_94_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_950_logo.png b/tests/input/res/drawable-xhdpi/ch_950_logo.png
index da6acbff..5db6be41 100644
--- a/tests/input/res/drawable-xhdpi/ch_950_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_950_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_951_logo.png b/tests/input/res/drawable-xhdpi/ch_951_logo.png
index 8104bf96..6fbf5951 100644
--- a/tests/input/res/drawable-xhdpi/ch_951_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_951_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_952_logo.png b/tests/input/res/drawable-xhdpi/ch_952_logo.png
index 57637c99..0e5e39aa 100644
--- a/tests/input/res/drawable-xhdpi/ch_952_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_952_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_953_logo.png b/tests/input/res/drawable-xhdpi/ch_953_logo.png
index ae1843c0..430a5e4d 100644
--- a/tests/input/res/drawable-xhdpi/ch_953_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_953_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_954_logo.png b/tests/input/res/drawable-xhdpi/ch_954_logo.png
index c14b6c6b..8ddc6cee 100644
--- a/tests/input/res/drawable-xhdpi/ch_954_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_954_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_955_logo.png b/tests/input/res/drawable-xhdpi/ch_955_logo.png
index f43422f8..69ec92b5 100644
--- a/tests/input/res/drawable-xhdpi/ch_955_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_955_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_956_logo.png b/tests/input/res/drawable-xhdpi/ch_956_logo.png
index 260962ca..bc1edbd7 100644
--- a/tests/input/res/drawable-xhdpi/ch_956_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_956_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_957_logo.png b/tests/input/res/drawable-xhdpi/ch_957_logo.png
index 45a19f55..20db4202 100644
--- a/tests/input/res/drawable-xhdpi/ch_957_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_957_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_958_logo.png b/tests/input/res/drawable-xhdpi/ch_958_logo.png
index 6532fd2a..8e9a7a68 100644
--- a/tests/input/res/drawable-xhdpi/ch_958_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_958_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_959_logo.png b/tests/input/res/drawable-xhdpi/ch_959_logo.png
index 4dddf7d4..4d61c092 100644
--- a/tests/input/res/drawable-xhdpi/ch_959_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_959_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_95_logo.png b/tests/input/res/drawable-xhdpi/ch_95_logo.png
index 0b1d8483..50cc5990 100644
--- a/tests/input/res/drawable-xhdpi/ch_95_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_95_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_960_logo.png b/tests/input/res/drawable-xhdpi/ch_960_logo.png
index 27ed3984..b2a54413 100644
--- a/tests/input/res/drawable-xhdpi/ch_960_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_960_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_961_logo.png b/tests/input/res/drawable-xhdpi/ch_961_logo.png
index f10900f1..5dc31323 100644
--- a/tests/input/res/drawable-xhdpi/ch_961_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_961_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_962_logo.png b/tests/input/res/drawable-xhdpi/ch_962_logo.png
index 7d66bc64..4ef2a219 100644
--- a/tests/input/res/drawable-xhdpi/ch_962_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_962_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_963_logo.png b/tests/input/res/drawable-xhdpi/ch_963_logo.png
index ed5923bd..22633d33 100644
--- a/tests/input/res/drawable-xhdpi/ch_963_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_963_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_964_logo.png b/tests/input/res/drawable-xhdpi/ch_964_logo.png
index 7907b72f..ba8ad46c 100644
--- a/tests/input/res/drawable-xhdpi/ch_964_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_964_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_965_logo.png b/tests/input/res/drawable-xhdpi/ch_965_logo.png
index 9b2fa082..2c935852 100644
--- a/tests/input/res/drawable-xhdpi/ch_965_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_965_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_966_logo.png b/tests/input/res/drawable-xhdpi/ch_966_logo.png
index 48bc04d1..8b751988 100644
--- a/tests/input/res/drawable-xhdpi/ch_966_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_966_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_967_logo.png b/tests/input/res/drawable-xhdpi/ch_967_logo.png
index d15299cd..974712fd 100644
--- a/tests/input/res/drawable-xhdpi/ch_967_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_967_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_968_logo.png b/tests/input/res/drawable-xhdpi/ch_968_logo.png
index cfe29e4c..d1edc191 100644
--- a/tests/input/res/drawable-xhdpi/ch_968_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_968_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_969_logo.png b/tests/input/res/drawable-xhdpi/ch_969_logo.png
index 1d97435c..7774ed92 100644
--- a/tests/input/res/drawable-xhdpi/ch_969_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_969_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_96_logo.png b/tests/input/res/drawable-xhdpi/ch_96_logo.png
index 24cf0845..e37da468 100644
--- a/tests/input/res/drawable-xhdpi/ch_96_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_96_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_970_logo.png b/tests/input/res/drawable-xhdpi/ch_970_logo.png
index c077ec06..5dd52457 100644
--- a/tests/input/res/drawable-xhdpi/ch_970_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_970_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_971_logo.png b/tests/input/res/drawable-xhdpi/ch_971_logo.png
index c9148c51..0aca871c 100644
--- a/tests/input/res/drawable-xhdpi/ch_971_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_971_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_972_logo.png b/tests/input/res/drawable-xhdpi/ch_972_logo.png
index 3c9004a5..2f8803b5 100644
--- a/tests/input/res/drawable-xhdpi/ch_972_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_972_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_973_logo.png b/tests/input/res/drawable-xhdpi/ch_973_logo.png
index c8c114b8..35ec5c90 100644
--- a/tests/input/res/drawable-xhdpi/ch_973_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_973_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_974_logo.png b/tests/input/res/drawable-xhdpi/ch_974_logo.png
index a336e295..98f9a7aa 100644
--- a/tests/input/res/drawable-xhdpi/ch_974_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_974_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_975_logo.png b/tests/input/res/drawable-xhdpi/ch_975_logo.png
index b9d917c2..bdc31316 100644
--- a/tests/input/res/drawable-xhdpi/ch_975_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_975_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_976_logo.png b/tests/input/res/drawable-xhdpi/ch_976_logo.png
index 02fc087f..078d35b7 100644
--- a/tests/input/res/drawable-xhdpi/ch_976_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_976_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_977_logo.png b/tests/input/res/drawable-xhdpi/ch_977_logo.png
index 377ee44f..c6fbb7be 100644
--- a/tests/input/res/drawable-xhdpi/ch_977_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_977_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_978_logo.png b/tests/input/res/drawable-xhdpi/ch_978_logo.png
index 09e6fba9..00a6e5e1 100644
--- a/tests/input/res/drawable-xhdpi/ch_978_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_978_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_979_logo.png b/tests/input/res/drawable-xhdpi/ch_979_logo.png
index e0f91625..fd1f56d1 100644
--- a/tests/input/res/drawable-xhdpi/ch_979_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_979_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_97_logo.png b/tests/input/res/drawable-xhdpi/ch_97_logo.png
index 04243156..f852548a 100644
--- a/tests/input/res/drawable-xhdpi/ch_97_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_97_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_980_logo.png b/tests/input/res/drawable-xhdpi/ch_980_logo.png
index e74e48d9..362a1988 100644
--- a/tests/input/res/drawable-xhdpi/ch_980_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_980_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_981_logo.png b/tests/input/res/drawable-xhdpi/ch_981_logo.png
index fd8eea25..9f879c4b 100644
--- a/tests/input/res/drawable-xhdpi/ch_981_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_981_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_982_logo.png b/tests/input/res/drawable-xhdpi/ch_982_logo.png
index 53902f70..0d945a11 100644
--- a/tests/input/res/drawable-xhdpi/ch_982_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_982_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_983_logo.png b/tests/input/res/drawable-xhdpi/ch_983_logo.png
index 0700c680..ffeaddfc 100644
--- a/tests/input/res/drawable-xhdpi/ch_983_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_983_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_984_logo.png b/tests/input/res/drawable-xhdpi/ch_984_logo.png
index b812b238..d8f92211 100644
--- a/tests/input/res/drawable-xhdpi/ch_984_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_984_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_985_logo.png b/tests/input/res/drawable-xhdpi/ch_985_logo.png
index 0b2b5ead..b6c6f0dc 100644
--- a/tests/input/res/drawable-xhdpi/ch_985_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_985_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_986_logo.png b/tests/input/res/drawable-xhdpi/ch_986_logo.png
index 22edb80a..8e2c0b50 100644
--- a/tests/input/res/drawable-xhdpi/ch_986_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_986_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_987_logo.png b/tests/input/res/drawable-xhdpi/ch_987_logo.png
index 53a13ea0..ce8c107a 100644
--- a/tests/input/res/drawable-xhdpi/ch_987_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_987_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_988_logo.png b/tests/input/res/drawable-xhdpi/ch_988_logo.png
index 8f33cfd0..ffa8ded7 100644
--- a/tests/input/res/drawable-xhdpi/ch_988_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_988_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_989_logo.png b/tests/input/res/drawable-xhdpi/ch_989_logo.png
index ca89cd04..8522a03a 100644
--- a/tests/input/res/drawable-xhdpi/ch_989_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_989_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_98_logo.png b/tests/input/res/drawable-xhdpi/ch_98_logo.png
index c95bb658..13fe760f 100644
--- a/tests/input/res/drawable-xhdpi/ch_98_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_98_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_990_logo.png b/tests/input/res/drawable-xhdpi/ch_990_logo.png
index 809e64b6..bd6df061 100644
--- a/tests/input/res/drawable-xhdpi/ch_990_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_990_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_991_logo.png b/tests/input/res/drawable-xhdpi/ch_991_logo.png
index 9774f198..8611d57d 100644
--- a/tests/input/res/drawable-xhdpi/ch_991_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_991_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_992_logo.png b/tests/input/res/drawable-xhdpi/ch_992_logo.png
index 01381a84..36d26bc0 100644
--- a/tests/input/res/drawable-xhdpi/ch_992_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_992_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_993_logo.png b/tests/input/res/drawable-xhdpi/ch_993_logo.png
index 2f470e98..f67e0eec 100644
--- a/tests/input/res/drawable-xhdpi/ch_993_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_993_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_994_logo.png b/tests/input/res/drawable-xhdpi/ch_994_logo.png
index 6c6cf86f..a63d5ee1 100644
--- a/tests/input/res/drawable-xhdpi/ch_994_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_994_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_995_logo.png b/tests/input/res/drawable-xhdpi/ch_995_logo.png
index 0d8e14b2..b7b45167 100644
--- a/tests/input/res/drawable-xhdpi/ch_995_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_995_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_996_logo.png b/tests/input/res/drawable-xhdpi/ch_996_logo.png
index e904fe21..82c042c3 100644
--- a/tests/input/res/drawable-xhdpi/ch_996_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_996_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_997_logo.png b/tests/input/res/drawable-xhdpi/ch_997_logo.png
index 9d608a58..d70e4793 100644
--- a/tests/input/res/drawable-xhdpi/ch_997_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_997_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_998_logo.png b/tests/input/res/drawable-xhdpi/ch_998_logo.png
index 14386f70..f6c69d2e 100644
--- a/tests/input/res/drawable-xhdpi/ch_998_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_998_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_999_logo.png b/tests/input/res/drawable-xhdpi/ch_999_logo.png
index 6cc6cd2a..844c06fd 100644
--- a/tests/input/res/drawable-xhdpi/ch_999_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_999_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_99_logo.png b/tests/input/res/drawable-xhdpi/ch_99_logo.png
index b9d94a8e..d8be447d 100644
--- a/tests/input/res/drawable-xhdpi/ch_99_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_99_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/ch_9_logo.png b/tests/input/res/drawable-xhdpi/ch_9_logo.png
index 8e7c246d..8ba6bc55 100644
--- a/tests/input/res/drawable-xhdpi/ch_9_logo.png
+++ b/tests/input/res/drawable-xhdpi/ch_9_logo.png
Binary files differ
diff --git a/tests/input/res/drawable-xhdpi/icon.png b/tests/input/res/drawable-xhdpi/icon.png
index 8497c28c..87af81e3 100644
--- a/tests/input/res/drawable-xhdpi/icon.png
+++ b/tests/input/res/drawable-xhdpi/icon.png
Binary files differ
diff --git a/tests/input/res/values/integers.xml b/tests/input/res/values/integers.xml
new file mode 100644
index 00000000..b11d1005
--- /dev/null
+++ b/tests/input/res/values/integers.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+
+<resources>
+ <integer name="tuner_count">2</integer>
+</resources>
diff --git a/tests/input/res/xml/testtvinputservice.xml b/tests/input/res/xml/testtvinputservice.xml
index 74be3892..709e9b37 100644
--- a/tests/input/res/xml/testtvinputservice.xml
+++ b/tests/input/res/xml/testtvinputservice.xml
@@ -15,4 +15,6 @@
~ limitations under the License.
-->
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
- android:setupActivity="com.android.tv.testinput.TestTvInputSetupActivity" />
+ android:setupActivity="com.android.tv.testinput.TestTvInputSetupActivity"
+ android:canRecord="true"
+ android:tunerCount="@integer/tuner_count" />
diff --git a/tests/input/src/com/android/tv/testinput/TestTvInputService.java b/tests/input/src/com/android/tv/testinput/TestTvInputService.java
index b20e0331..659b341f 100644
--- a/tests/input/src/com/android/tv/testinput/TestTvInputService.java
+++ b/tests/input/src/com/android/tv/testinput/TestTvInputService.java
@@ -16,17 +16,24 @@
package com.android.tv.testinput;
+import android.annotation.TargetApi;
import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.ContentValues;
import android.content.Context;
+import android.database.Cursor;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.media.PlaybackParams;
import android.media.tv.TvContract;
+import android.media.tv.TvContract.Programs;
+import android.media.tv.TvContract.RecordedPrograms;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
import android.media.tv.TvTrackInfo;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -35,22 +42,28 @@ import android.util.Log;
import android.view.KeyEvent;
import android.view.Surface;
+import com.android.tv.input.TunerHelper;
import com.android.tv.testing.ChannelInfo;
import com.android.tv.testing.testinput.ChannelState;
import java.util.Date;
+import java.util.concurrent.TimeUnit;
/**
* Simple TV input service which provides test channels.
*/
public class TestTvInputService extends TvInputService {
- private static final String TAG = "TestTvInputServices";
+ private static final String TAG = "TestTvInputService";
private static final int REFRESH_DELAY_MS = 1000 / 5;
private static final boolean DEBUG = false;
- private static final boolean HAS_TIME_SHIFT_API = Build.VERSION.SDK_INT
- >= Build.VERSION_CODES.M;
+
+ // Consider the command delivering time from Live TV.
+ private static final long MAX_COMMAND_DELAY = TimeUnit.SECONDS.toMillis(3);
+
private final TestInputControl mBackend = TestInputControl.getInstance();
+ private TunerHelper mTunerHelper;
+
public static String buildInputId(Context context) {
return TvContract.buildInputId(new ComponentName(context, TestTvInputService.class));
}
@@ -59,14 +72,27 @@ public class TestTvInputService extends TvInputService {
public void onCreate() {
super.onCreate();
mBackend.init(this, buildInputId(this));
+ mTunerHelper = new TunerHelper(getResources().getInteger(R.integer.tuner_count));
}
@Override
public Session onCreateSession(String inputId) {
Log.v(TAG, "Creating session for " + inputId);
+ // onCreateSession always succeeds because this session can be used to play the recorded
+ // program.
return new SimpleSessionImpl(this);
}
+ @TargetApi(Build.VERSION_CODES.N)
+ @Override
+ public RecordingSession onCreateRecordingSession(String inputId) {
+ Log.v(TAG, "Creating recording session for " + inputId);
+ if (!mTunerHelper.tunerAvailableForRecording()) {
+ return null;
+ }
+ return new SimpleRecordingSessionImpl(this, inputId);
+ }
+
/**
* Simple session implementation that just display some text.
*/
@@ -77,6 +103,7 @@ public class TestTvInputService extends TvInputService {
private final Paint mTextPaint = new Paint();
private final DrawRunnable mDrawRunnable = new DrawRunnable();
private Surface mSurface = null;
+ private Uri mChannelUri = null;
private ChannelInfo mChannel = null;
private ChannelState mCurrentState = null;
private String mCurrentVideoTrackId = null;
@@ -141,9 +168,11 @@ public class TestTvInputService extends TvInputService {
if (DEBUG) {
Log.v(TAG, "Releasing session " + this);
}
+ mTunerHelper.stopTune(mChannelUri);
mDrawRunnable.cancel();
mHandler.removeCallbacks(mDrawRunnable);
mSurface = null;
+ mChannelUri = null;
mChannel = null;
mCurrentState = null;
}
@@ -180,6 +209,8 @@ public class TestTvInputService extends TvInputService {
@Override
public boolean onTune(Uri channelUri) {
Log.i(TAG, "Tune to " + channelUri);
+ mTunerHelper.stopTune(mChannelUri);
+ mChannelUri = channelUri;
ChannelInfo info = mBackend.getChannelInfo(channelUri);
synchronized (mDrawRunnable) {
if (info == null || mChannel == null
@@ -193,17 +224,18 @@ public class TestTvInputService extends TvInputService {
if (mChannel == null) {
Log.i(TAG, "Channel not found for " + channelUri);
notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
+ } else if (!mTunerHelper.tune(channelUri, false)) {
+ Log.i(TAG, "No available tuner for " + channelUri);
+ notifyVideoUnavailable(TvInputManager.VIDEO_UNAVAILABLE_REASON_UNKNOWN);
} else {
Log.i(TAG, "Tuning to " + mChannel);
}
- if (HAS_TIME_SHIFT_API) {
- notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE);
- mRecordStartTimeMs = mCurrentPositionMs = mLastCurrentPositionUpdateTimeMs
- = System.currentTimeMillis();
- mPausedTimeMs = 0;
- mHandler.sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS);
- mSpeed = 1;
- }
+ notifyTimeShiftStatusChanged(TvInputManager.TIME_SHIFT_STATUS_AVAILABLE);
+ mRecordStartTimeMs = mCurrentPositionMs = mLastCurrentPositionUpdateTimeMs
+ = System.currentTimeMillis();
+ mPausedTimeMs = 0;
+ mHandler.sendEmptyMessageDelayed(MSG_SEEK, SEEK_DELAY_MS);
+ mSpeed = 1;
return true;
}
@@ -290,9 +322,24 @@ public class TestTvInputService extends TvInputService {
} else {
mCurrentState = null;
}
- }
- draw(currentSurface, currentChannel);
+ if (currentSurface != null) {
+ String now = new Date(mCurrentPositionMs).toString();
+ String name = currentChannel == null ? "Null" : currentChannel.name;
+ Canvas c = currentSurface.lockCanvas(null);
+ c.drawColor(0xFF888888);
+ c.drawText(name, 100f, 200f, mTextPaint);
+ c.drawText(now, 100f, 400f, mTextPaint);
+ currentSurface.unlockCanvasAndPost(c);
+ if (DEBUG) {
+ Log.v(TAG, "Post to canvas");
+ }
+ } else {
+ if (DEBUG) {
+ Log.v(TAG, "No surface");
+ }
+ }
+ }
if (updatedState) {
update(oldState, newState, currentChannel);
}
@@ -319,29 +366,146 @@ public class TestTvInputService extends TvInputService {
}
}
- private void draw(Surface surface, ChannelInfo currentChannel) {
- if (surface != null) {
- String now = HAS_TIME_SHIFT_API
- ? new Date(mCurrentPositionMs).toString() : new Date().toString();
- String name = currentChannel == null ? "Null" : currentChannel.name;
- Canvas c = surface.lockCanvas(null);
- c.drawColor(0xFF888888);
- c.drawText(name, 100f, 200f, mTextPaint);
- c.drawText(now, 100f, 400f, mTextPaint);
- surface.unlockCanvasAndPost(c);
- if (DEBUG) {
- Log.v(TAG, "Post to canvas");
+ public void cancel() {
+ mIsCanceled = true;
+ }
+ }
+ }
+
+ private class SimpleRecordingSessionImpl extends RecordingSession {
+ private final String[] PROGRAM_PROJECTION = {
+ Programs.COLUMN_TITLE,
+ Programs.COLUMN_EPISODE_TITLE,
+ Programs.COLUMN_SHORT_DESCRIPTION,
+ Programs.COLUMN_POSTER_ART_URI,
+ Programs.COLUMN_THUMBNAIL_URI,
+ Programs.COLUMN_CANONICAL_GENRE,
+ Programs.COLUMN_CONTENT_RATING,
+ Programs.COLUMN_START_TIME_UTC_MILLIS,
+ Programs.COLUMN_END_TIME_UTC_MILLIS,
+ Programs.COLUMN_VIDEO_WIDTH,
+ Programs.COLUMN_VIDEO_HEIGHT,
+ Programs.COLUMN_SEASON_DISPLAY_NUMBER,
+ Programs.COLUMN_SEASON_TITLE,
+ Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
+ };
+
+ private final String mInputId;
+ private long mStartTime;
+ private long mEndTime;
+ private Uri mChannelUri;
+ private Uri mProgramHintUri;
+
+ public SimpleRecordingSessionImpl(Context context, String inputId) {
+ super(context);
+ mInputId = inputId;
+ }
+
+ @Override
+ public void onTune(Uri uri) {
+ Log.i(TAG, "SimpleReccordingSesesionImpl: onTune()");
+ mTunerHelper.stopRecording(mChannelUri);
+ mChannelUri = uri;
+ ChannelInfo channel = mBackend.getChannelInfo(uri);
+ if (channel == null) {
+ notifyError(TvInputManager.RECORDING_ERROR_UNKNOWN);
+ } else if (!mTunerHelper.tune(uri, true)) {
+ notifyError(TvInputManager.RECORDING_ERROR_RESOURCE_BUSY);
+ } else {
+ notifyTuned(uri);
+ }
+ }
+
+ @Override
+ public void onStartRecording(Uri programHintUri) {
+ Log.i(TAG, "SimpleReccordingSesesionImpl: onStartRecording()");
+ mStartTime = System.currentTimeMillis();
+ mProgramHintUri = programHintUri;
+ }
+
+ @Override
+ public void onStopRecording() {
+ Log.i(TAG, "SimpleReccordingSesesionImpl: onStopRecording()");
+ mEndTime = System.currentTimeMillis();
+ final long startTime = mStartTime;
+ final long endTime = mEndTime;
+ final Uri programHintUri = mProgramHintUri;
+ final Uri channelUri = mChannelUri;
+ new AsyncTask<Void, Void, Void>() {
+ @Override
+ protected Void doInBackground(Void... arg0) {
+ long time = System.currentTimeMillis();
+ if (programHintUri != null) {
+ // Retrieves program info from mProgramHintUri
+ try (Cursor c = getContentResolver().query(programHintUri,
+ PROGRAM_PROJECTION, null, null, null)) {
+ if (c != null && c.getCount() > 0) {
+ storeRecordedProgram(c, startTime, endTime);
+ return null;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error querying " + this, e);
+ }
}
- } else {
- if (DEBUG) {
- Log.v(TAG, "No surface");
+ // Retrieves the current program
+ try (Cursor c = getContentResolver().query(
+ TvContract.buildProgramsUriForChannel(channelUri, startTime,
+ endTime - startTime < MAX_COMMAND_DELAY ? startTime :
+ endTime - MAX_COMMAND_DELAY),
+ PROGRAM_PROJECTION, null, null, null)) {
+ if (c != null && c.getCount() == 1) {
+ storeRecordedProgram(c, startTime, endTime);
+ return null;
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Error querying " + this, e);
}
+ storeRecordedProgram(null, startTime, endTime);
+ return null;
}
- }
- public void cancel() {
- mIsCanceled = true;
- }
+ private void storeRecordedProgram(Cursor c, long startTime, long endTime) {
+ ContentValues values = new ContentValues();
+ values.put(RecordedPrograms.COLUMN_INPUT_ID, mInputId);
+ values.put(RecordedPrograms.COLUMN_CHANNEL_ID,
+ ContentUris.parseId(channelUri));
+ values.put(RecordedPrograms.COLUMN_RECORDING_DURATION_MILLIS,
+ endTime - startTime);
+ if (c != null) {
+ int index = 0;
+ c.moveToNext();
+ values.put(Programs.COLUMN_TITLE, c.getString(index++));
+ values.put(Programs.COLUMN_EPISODE_TITLE, c.getString(index++));
+ values.put(Programs.COLUMN_SHORT_DESCRIPTION, c.getString(index++));
+ values.put(Programs.COLUMN_POSTER_ART_URI, c.getString(index++));
+ values.put(Programs.COLUMN_THUMBNAIL_URI, c.getString(index++));
+ values.put(Programs.COLUMN_CANONICAL_GENRE, c.getString(index++));
+ values.put(Programs.COLUMN_CONTENT_RATING, c.getString(index++));
+ values.put(Programs.COLUMN_START_TIME_UTC_MILLIS, c.getLong(index++));
+ values.put(Programs.COLUMN_END_TIME_UTC_MILLIS, c.getLong(index++));
+ values.put(Programs.COLUMN_VIDEO_WIDTH, c.getLong(index++));
+ values.put(Programs.COLUMN_VIDEO_HEIGHT, c.getLong(index++));
+ values.put(Programs.COLUMN_SEASON_DISPLAY_NUMBER, c.getString(index++));
+ values.put(Programs.COLUMN_SEASON_TITLE, c.getString(index++));
+ values.put(Programs.COLUMN_EPISODE_DISPLAY_NUMBER,
+ c.getString(index++));
+ } else {
+ values.put(RecordedPrograms.COLUMN_TITLE, "No program info");
+ values.put(RecordedPrograms.COLUMN_START_TIME_UTC_MILLIS, startTime);
+ values.put(RecordedPrograms.COLUMN_END_TIME_UTC_MILLIS, endTime);
+ }
+ Uri uri = getContentResolver()
+ .insert(TvContract.RecordedPrograms.CONTENT_URI, values);
+ notifyRecordingStopped(uri);
+ }
+ }.execute();
+ }
+
+ @Override
+ public void onRelease() {
+ Log.i(TAG, "SimpleReccordingSesesionImpl: onRelease()");
+ mTunerHelper.stopRecording(mChannelUri);
+ mChannelUri = null;
}
}
-} \ No newline at end of file
+}
diff --git a/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java b/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java
new file mode 100644
index 00000000..b0463e71
--- /dev/null
+++ b/tests/jank/src/com/android/tv/tests/jank/ChannelZappingJankTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.tests.jank;
+
+import android.content.res.Resources;
+import android.support.test.filters.MediumTest;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.tv.testing.uihelper.LiveChannelsUiDeviceHelper;
+
+/**
+ * Jank tests for channel zapping.
+ */
+@MediumTest
+public class ChannelZappingJankTest extends JankTestBase {
+ private static final String TAG = "ChannelZappingJankTest";
+
+ private static final String STARTING_CHANNEL = "13";
+
+ /**
+ * The minimum number of frames expected during each jank test.
+ * If there is less the test will fail. To be safe we loop the action in each test to create
+ * twice this many frames under normal conditions.
+ * <p>At least 100 frams should be chosen so there will be enough frame
+ * for the 90th, 95th, and 98th percentile measurements are significant.
+ *
+ * @see <a href="http://go/janktesthelper-best-practices">Jank Test Helper Best Practices</a>
+ */
+ private static final int EXPECTED_FRAMES = 100;
+ private static final int WARM_UP_CHANNEL_ZAPPING_COUNT = 2;
+
+ private UiDevice mDevice;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ Resources targetResources = getInstrumentation().getTargetContext().getResources();
+ LiveChannelsUiDeviceHelper liveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice,
+ targetResources, getInstrumentation().getContext());
+ liveChannelsHelper.assertAppStarted();
+ Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice);
+ }
+
+ @JankTest(expectedFrames = EXPECTED_FRAMES,
+ beforeTest = "warmChannelZapping")
+ @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME)
+ public void testChannelZapping() {
+ int frameCountForOneChannelZapping = 40; // measured by hand
+ int repeat = EXPECTED_FRAMES * 2 / frameCountForOneChannelZapping;
+ for (int i = 0; i < repeat; i++) {
+ mDevice.pressDPadUp();
+ mDevice.waitForIdle();
+ // Press BACK to close banner.
+ mDevice.pressBack();
+ mDevice.waitForIdle();
+ }
+ }
+
+ // It's public to be used with @JankTest annotation.
+ public void warmChannelZapping() {
+ for (int i = 0; i < WARM_UP_CHANNEL_ZAPPING_COUNT; ++i) {
+ mDevice.pressDPadUp();
+ mDevice.waitForIdle();
+ }
+ // Press BACK to close banner.
+ mDevice.pressBack();
+ mDevice.waitForIdle();
+ }
+}
diff --git a/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java b/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java
new file mode 100644
index 00000000..47ebea3b
--- /dev/null
+++ b/tests/jank/src/com/android/tv/tests/jank/MenuJankTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.tests.jank;
+
+import android.content.res.Resources;
+import android.support.test.filters.MediumTest;
+import android.support.test.jank.GfxMonitor;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+
+import com.android.tv.testing.uihelper.LiveChannelsUiDeviceHelper;
+import com.android.tv.testing.uihelper.MenuHelper;
+
+/**
+ * Jank tests for the program guide.
+ */
+@MediumTest
+public class MenuJankTest extends JankTestBase {
+ private static final String STARTING_CHANNEL = "1";
+
+ /**
+ * The minimum number of frames expected during each jank test.
+ * If there is less the test will fail. To be safe we loop the action in each test to create
+ * twice this many frames under normal conditions.
+ * <p>200 is chosen so there will be enough frame for the 90th, 95th, and 98th percentile
+ * measurements are significant.
+ *
+ * @see <a href="http://go/janktesthelper-best-practices">Jank Test Helper Best Practices</a>
+ */
+ private static final int EXPECTED_FRAMES = 200;
+
+ protected UiDevice mDevice;
+
+ protected Resources mTargetResources;
+ protected MenuHelper mMenuHelper;
+ protected LiveChannelsUiDeviceHelper mLiveChannelsHelper;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ mTargetResources = getInstrumentation().getTargetContext().getResources();
+ mMenuHelper = new MenuHelper(mDevice, mTargetResources);
+ mLiveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice, mTargetResources,
+ getInstrumentation().getContext());
+ mLiveChannelsHelper.assertAppStarted();
+ Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice);
+ }
+
+ @JankTest(expectedFrames = EXPECTED_FRAMES,
+ beforeTest = "fillTheMenuRowWithPreviousChannels")
+ @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME)
+ public void testShowMenu() {
+ int frames = 40; // measured by hand.
+ int repeat = EXPECTED_FRAMES * 2 / frames;
+ for (int i = 0; i < repeat; i++) {
+ mMenuHelper.showMenu();
+ mDevice.pressBack();
+ mDevice.waitForIdle();
+ }
+ }
+
+ public void fillTheMenuRowWithPreviousChannels() {
+ int cardViewCount = 6;
+ for (int i = 0; i < cardViewCount; i++) {
+ mDevice.pressDPadUp();
+ mDevice.waitForIdle();
+ }
+ }
+}
diff --git a/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java b/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java
index bec933ca..7d751c4c 100644
--- a/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java
+++ b/tests/jank/src/com/android/tv/tests/jank/ProgramGuideJankTest.java
@@ -18,14 +18,12 @@ package com.android.tv.tests.jank;
import static com.android.tv.testing.uihelper.UiDeviceAsserts.assertWaitForCondition;
import android.content.res.Resources;
-import android.os.Build;
-import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.MediumTest;
import android.support.test.jank.GfxMonitor;
import android.support.test.jank.JankTest;
import android.support.test.jank.JankTestBase;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.MediumTest;
import com.android.tv.R;
import com.android.tv.testing.uihelper.ByResource;
@@ -38,13 +36,11 @@ import com.android.tv.testing.uihelper.UiDeviceUtils;
* Jank tests for the program guide.
*/
@MediumTest
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.M)
public class ProgramGuideJankTest extends JankTestBase {
private static final boolean DEBUG = false;
private static final String TAG = "ProgramGuideJank";
private static final String STARTING_CHANNEL = "13";
- public static final String LIVE_CHANNELS_PROCESS_NAME = "com.android.tv";
/**
* The minimum number of frames expected during each jank test.
@@ -56,13 +52,11 @@ public class ProgramGuideJankTest extends JankTestBase {
* @see <a href="http://go/janktesthelper-best-practices">Jank Test Helper Best Practices</a>
*/
private static final int EXPECTED_FRAMES = 200;
- public static final String LIVE_CHANNELS_PACKAGE = "com.android.tv";
- protected UiDevice mDevice;
+ private UiDevice mDevice;
- protected Resources mTargetResources;
- protected MenuHelper mMenuHelper;
- protected LiveChannelsUiDeviceHelper mLiveChannelsHelper;
+ private Resources mTargetResources;
+ private MenuHelper mMenuHelper;
@Override
protected void setUp() throws Exception {
@@ -70,16 +64,15 @@ public class ProgramGuideJankTest extends JankTestBase {
mDevice = UiDevice.getInstance(getInstrumentation());
mTargetResources = getInstrumentation().getTargetContext().getResources();
mMenuHelper = new MenuHelper(mDevice, mTargetResources);
- mLiveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice, mTargetResources,
- getInstrumentation().getContext());
- mLiveChannelsHelper.assertAppStarted();
- pressKeysForChannelNumber(STARTING_CHANNEL);
+ LiveChannelsUiDeviceHelper liveChannelsHelper = new LiveChannelsUiDeviceHelper(mDevice,
+ mTargetResources, getInstrumentation().getContext());
+ liveChannelsHelper.assertAppStarted();
+ Utils.pressKeysForChannelNumber(STARTING_CHANNEL, mDevice);
}
-
@JankTest(expectedFrames = EXPECTED_FRAMES,
beforeTest = "warmProgramGuide")
- @GfxMonitor(processName = LIVE_CHANNELS_PACKAGE)
+ @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME)
public void testShowClearProgramGuide() {
int frames = 53; // measured by hand
int repeat = EXPECTED_FRAMES * 2 / frames;
@@ -92,7 +85,7 @@ public class ProgramGuideJankTest extends JankTestBase {
@JankTest(expectedFrames = EXPECTED_FRAMES,
beforeLoop = "showProgramGuide",
afterLoop = "clearProgramGuide")
- @GfxMonitor(processName = LIVE_CHANNELS_PROCESS_NAME)
+ @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME)
public void testScrollDown() {
int frames = 20; // measured by hand
int repeat = EXPECTED_FRAMES * 2 / frames;
@@ -104,7 +97,7 @@ public class ProgramGuideJankTest extends JankTestBase {
@JankTest(expectedFrames = EXPECTED_FRAMES,
beforeLoop = "showProgramGuide",
afterLoop = "clearProgramGuide")
- @GfxMonitor(processName = LIVE_CHANNELS_PROCESS_NAME)
+ @GfxMonitor(processName = Utils.LIVE_CHANNELS_PROCESS_NAME)
public void testScrollRight() {
int frames = 30; // measured by hand
int repeat = EXPECTED_FRAMES * 2 / frames;
@@ -113,33 +106,29 @@ public class ProgramGuideJankTest extends JankTestBase {
}
}
- //TODO: move to a mixin/helper
- protected void pressKeysForChannelNumber(String channel) {
- UiDeviceUtils.pressKeys(mDevice, channel);
- mDevice.pressDPadCenter();
- }
-
- public void selectProgramGuideMenuItem() {
+ private void selectProgramGuideMenuItem() {
mMenuHelper.showMenu();
mMenuHelper.assertNavigateToMenuItem(R.string.menu_title_channels,
R.string.channels_item_program_guide);
mDevice.waitForIdle();
}
+ // It's public to be used with @JankTest annotation.
public void warmProgramGuide() {
// TODO: b/21078199 First time Program Guide is opened there is a noticeable delay
selectProgramGuideMenuItem();
mDevice.pressDPadCenter();
assertWaitForCondition(mDevice, Until.hasObject(Constants.PROGRAM_GUIDE));
mDevice.pressBack();
-
}
+ // It's public to be used with @JankTest annotation.
public void clearProgramGuide() {
mDevice.pressBack();
assertWaitForCondition(mDevice, Until.gone(Constants.PROGRAM_GUIDE));
}
+ // It's public to be used with @JankTest annotation.
public void showProgramGuide() {
selectProgramGuideMenuItem();
mDevice.pressDPadCenter();
diff --git a/tests/jank/src/com/android/tv/tests/jank/Utils.java b/tests/jank/src/com/android/tv/tests/jank/Utils.java
new file mode 100644
index 00000000..cd1f7eff
--- /dev/null
+++ b/tests/jank/src/com/android/tv/tests/jank/Utils.java
@@ -0,0 +1,35 @@
+/*
+ * 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.tests.jank;
+
+import com.android.tv.testing.uihelper.UiDeviceUtils;
+
+import android.support.test.uiautomator.UiDevice;
+
+public final class Utils {
+ /** Live TV process name */
+ public static final String LIVE_CHANNELS_PROCESS_NAME = "com.android.tv";
+
+ private Utils() { }
+
+ /**
+ * Presses channel number to tune to {@code channel}.
+ */
+ public static void pressKeysForChannelNumber(String channel, UiDevice uiDevice) {
+ UiDeviceUtils.pressKeys(uiDevice, channel);
+ uiDevice.pressDPadCenter();
+ }
+}
diff --git a/tests/unit/Android.mk b/tests/unit/Android.mk
index 3808cdc2..7ed100d0 100644
--- a/tests/unit/Android.mk
+++ b/tests/unit/Android.mk
@@ -16,7 +16,7 @@ LOCAL_PACKAGE_NAME := TVUnitTests
LOCAL_INSTRUMENTATION_FOR := LiveTv
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 23 # M
include $(BUILD_PACKAGE)
diff --git a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
index 6e01f423..899083f3 100644
--- a/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
+++ b/tests/unit/src/com/android/tv/CurrentPositionMediatorTest.java
@@ -19,8 +19,8 @@ package com.android.tv;
import static com.android.tv.TimeShiftManager.INVALID_TIME;
import static com.android.tv.TimeShiftManager.REQUEST_TIMEOUT_MS;
+import android.support.test.filters.MediumTest;
import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.MediumTest;
@MediumTest
public class CurrentPositionMediatorTest extends BaseMainActivityTestCase {
diff --git a/tests/unit/src/com/android/tv/FeaturesTest.java b/tests/unit/src/com/android/tv/FeaturesTest.java
index a0a6a5be..644c4248 100644
--- a/tests/unit/src/com/android/tv/FeaturesTest.java
+++ b/tests/unit/src/com/android/tv/FeaturesTest.java
@@ -16,7 +16,7 @@
package com.android.tv;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import junit.framework.TestCase;
diff --git a/tests/unit/src/com/android/tv/MainActivityTest.java b/tests/unit/src/com/android/tv/MainActivityTest.java
index a09111e8..b2fe6745 100644
--- a/tests/unit/src/com/android/tv/MainActivityTest.java
+++ b/tests/unit/src/com/android/tv/MainActivityTest.java
@@ -15,7 +15,7 @@
*/
package com.android.tv;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
import android.view.View;
import android.widget.TextView;
diff --git a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
index 878d4293..f7c6f622 100644
--- a/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
+++ b/tests/unit/src/com/android/tv/TimeShiftManagerTest.java
@@ -23,7 +23,7 @@ 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 android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
@MediumTest
public class TimeShiftManagerTest extends BaseMainActivityTestCase {
diff --git a/tests/unit/src/com/android/tv/common/TvContentRatingCacheTest.java b/tests/unit/src/com/android/tv/common/TvContentRatingCacheTest.java
index cad1e7ca..eadc50d5 100644
--- a/tests/unit/src/com/android/tv/common/TvContentRatingCacheTest.java
+++ b/tests/unit/src/com/android/tv/common/TvContentRatingCacheTest.java
@@ -18,9 +18,9 @@ package com.android.tv.common;
import android.content.ComponentCallbacks2;
import android.media.tv.TvContentRating;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.testing.TvContentRatingConstants;
import com.android.tv.util.Utils;
@@ -42,7 +42,7 @@ public class TvContentRatingCacheTest extends AndroidTestCase {
*/
public static final String Y7_AND_MA = TvContentRatingConstants.STRING_US_TV_Y7_US_TV_FV + ","
+ TvContentRatingConstants.STRING_US_TV_MA;
- TvContentRatingCache mCache = TvContentRatingCache.getInstance();
+ final TvContentRatingCache mCache = TvContentRatingCache.getInstance();
@Override
protected void setUp() throws Exception {
diff --git a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
index 574dac8d..9f9ada1f 100644
--- a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
@@ -25,13 +25,13 @@ import android.database.Cursor;
import android.media.tv.TvContract;
import android.media.tv.TvContract.Channels;
import android.net.Uri;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
import android.test.UiThreadTest;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockCursor;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -107,11 +107,7 @@ public class ChannelDataManagerTest extends AndroidTestCase {
private void startAndWaitForComplete() throws Exception {
mChannelDataManager.start();
- try {
- assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {
- throw e;
- }
+ assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
}
private void restart() throws Exception {
diff --git a/tests/unit/src/com/android/tv/data/ChannelNumberTest.java b/tests/unit/src/com/android/tv/data/ChannelNumberTest.java
index 1dd18da0..4e6e9f3c 100644
--- a/tests/unit/src/com/android/tv/data/ChannelNumberTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelNumberTest.java
@@ -17,7 +17,7 @@ package com.android.tv.data;
import static com.android.tv.data.ChannelNumber.parseChannelNumber;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import com.android.tv.testing.ComparableTester;
diff --git a/tests/unit/src/com/android/tv/data/ChannelTest.java b/tests/unit/src/com/android/tv/data/ChannelTest.java
index c39942d9..95e3ee90 100644
--- a/tests/unit/src/com/android/tv/data/ChannelTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelTest.java
@@ -21,8 +21,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.testing.ComparatorTester;
import com.android.tv.util.TvInputManagerHelper;
@@ -188,8 +188,7 @@ public class ChannelTest extends AndroidTestCase {
@Override
public Boolean answer(InvocationOnMock invocation) throws Throwable {
String inputId = (String) invocation.getArguments()[0];
- boolean isPartner = PARTNER_INPUT_ID.equals(inputId);
- return isPartner;
+ return PARTNER_INPUT_ID.equals(inputId);
}
});
Comparator<Channel> comparator = new TestChannelComparator(manager);
diff --git a/tests/unit/src/com/android/tv/data/GenreItemTest.java b/tests/unit/src/com/android/tv/data/GenreItemTest.java
index 643768f8..fb48fd41 100644
--- a/tests/unit/src/com/android/tv/data/GenreItemTest.java
+++ b/tests/unit/src/com/android/tv/data/GenreItemTest.java
@@ -18,9 +18,8 @@ package com.android.tv.data;
import android.media.tv.TvContract.Programs.Genres;
import android.os.Build;
-import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
/**
* Tests for {@link Channel}.
diff --git a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
index 96ecefdf..430eef91 100644
--- a/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/ProgramDataManagerTest.java
@@ -22,17 +22,17 @@ import android.database.Cursor;
import android.media.tv.TvContract;
import android.net.Uri;
import android.os.HandlerThread;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
import android.test.mock.MockCursor;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import android.util.SparseArray;
import com.android.tv.testing.Constants;
-import com.android.tv.testing.ProgramInfo;
import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.ProgramInfo;
import com.android.tv.util.Utils;
import java.util.ArrayList;
@@ -78,7 +78,7 @@ public class ProgramDataManagerTest extends AndroidTestCase {
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mProgramDataManager = new ProgramDataManager(
- mContentResolver, mClock, mHandlerThread.getLooper());
+ mContentResolver, mClock, mHandlerThread.getLooper(), null);
mProgramDataManager.setPrefetchEnabled(true);
mProgramDataManager.addListener(mListener);
}
diff --git a/tests/unit/src/com/android/tv/data/ProgramTest.java b/tests/unit/src/com/android/tv/data/ProgramTest.java
index 25856e18..7e474cd6 100644
--- a/tests/unit/src/com/android/tv/data/ProgramTest.java
+++ b/tests/unit/src/com/android/tv/data/ProgramTest.java
@@ -18,11 +18,20 @@ 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 android.test.suitebuilder.annotation.SmallTest;
+import com.android.tv.data.Program.CriticScore;
+import com.android.tv.dvr.SeriesRecording;
+
+import android.media.tv.TvContentRating;
+import android.media.tv.TvContract.Programs.Genres;
+import android.os.Parcel;
+import android.support.test.filters.SmallTest;
+import android.util.Log;
import junit.framework.TestCase;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
/**
* Tests for {@link Program}.
@@ -85,6 +94,71 @@ public class ProgramTest extends TestCase {
assertHasGenre(program, GenreItems.ID_ALL_CHANNELS, true);
}
+ public void testParcelable() throws Exception {
+ List<CriticScore> criticScores = new ArrayList<>();
+ criticScores.add(new CriticScore("1", "2", "3"));
+ criticScores.add(new CriticScore("4", "5", "6"));
+ TvContentRating[] ratings = new TvContentRating[2];
+ ratings[0] = TvContentRating.unflattenFromString("1/2/3");
+ ratings[1] = TvContentRating.unflattenFromString("4/5/6");
+ Program p = new Program.Builder()
+ .setId(1)
+ .setPackageName("2")
+ .setChannelId(3)
+ .setTitle("4")
+ .setSeriesId("5")
+ .setEpisodeTitle("6")
+ .setSeasonNumber("7")
+ .setSeasonTitle("8")
+ .setEpisodeNumber("9")
+ .setStartTimeUtcMillis(10)
+ .setEndTimeUtcMillis(11)
+ .setDescription("12")
+ .setLongDescription("12-long")
+ .setVideoWidth(13)
+ .setVideoHeight(14)
+ .setCriticScores(criticScores)
+ .setPosterArtUri("15")
+ .setThumbnailUri("16")
+ .setCanonicalGenres(Genres.encode(Genres.SPORTS, Genres.SHOPPING))
+ .setContentRatings(ratings)
+ .setRecordingProhibited(true)
+ .build();
+ Parcel p1 = Parcel.obtain();
+ Parcel p2 = Parcel.obtain();
+ try {
+ p.writeToParcel(p1, 0);
+ byte[] bytes = p1.marshall();
+ p2.unmarshall(bytes, 0, bytes.length);
+ p2.setDataPosition(0);
+ Program r2 = Program.fromParcel(p2);
+ assertEquals(p, r2);
+ } finally {
+ p1.recycle();
+ p2.recycle();
+ }
+ }
+
+ public void testParcelableWithCriticScore() {
+ Program program = new Program.Builder()
+ .setTitle("MyTitle")
+ .addCriticScore(new CriticScore(
+ "default source",
+ "5/10",
+ "https://testurl/testimage.jpg"))
+ .build();
+ Parcel parcel = Parcel.obtain();
+ program.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Program programFromParcel = Program.CREATOR.createFromParcel(parcel);
+
+ assertNotNull(programFromParcel.getCriticScores());
+ assertEquals(programFromParcel.getCriticScores().get(0).source, "default source");
+ assertEquals(programFromParcel.getCriticScores().get(0).score, "5/10");
+ assertEquals(programFromParcel.getCriticScores().get(0).logoUrl,
+ "https://testurl/testimage.jpg");
+ }
+
private static void assertNullCanonicalGenres(Program program) {
String[] actual = program.getCanonicalGenres();
assertNull("Expected null canonical genres but was " + Arrays.toString(actual), actual);
diff --git a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
index 6b2bc8e5..f5504d48 100644
--- a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
+++ b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
@@ -16,12 +16,11 @@
package com.android.tv.data;
-import android.annotation.SuppressLint;
import android.content.pm.ResolveInfo;
import android.media.tv.TvInputInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import android.util.Pair;
import com.android.tv.testing.ComparatorTester;
@@ -42,7 +41,6 @@ import java.util.LinkedHashMap;
*/
@SmallTest
public class TvInputNewComparatorTest extends AndroidTestCase {
- @Suppress // http://b/26903987
public void testComparator() throws Exception {
final LinkedHashMap<String, Pair<Boolean, Boolean>> INPUT_ID_TO_NEW_INPUT =
new LinkedHashMap<>();
diff --git a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
index eb99cb88..c86bb724 100644
--- a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
@@ -16,10 +16,10 @@
package com.android.tv.data;
+import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
import android.test.AndroidTestCase;
import android.test.UiThreadTest;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import com.android.tv.data.WatchedHistoryManager.WatchedRecord;
import com.android.tv.testing.Utils;
@@ -58,11 +58,7 @@ public class WatchedHistoryManagerTest extends AndroidTestCase {
private void startAndWaitForComplete() throws Exception {
mWatchedHistoryManager.start();
- try {
- assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
- } catch (InterruptedException e) {
- throw e;
- }
+ assertTrue(mListener.loadFinishedLatch.await(WAIT_TIME_OUT_MS, TimeUnit.MILLISECONDS));
}
@UiThreadTest
@@ -135,7 +131,7 @@ public class WatchedHistoryManagerTest extends AndroidTestCase {
}
private class TestWatchedHistoryManagerListener implements WatchedHistoryManager.Listener {
- public CountDownLatch loadFinishedLatch = new CountDownLatch(1);
+ public final CountDownLatch loadFinishedLatch = new CountDownLatch(1);
@Override
public void onLoadFinished() {
diff --git a/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java b/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java
index 3df9ab97..1292759e 100644
--- a/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/dvr/BaseDvrDataManagerTest.java
@@ -32,6 +32,7 @@ import java.util.concurrent.TimeUnit;
*/
@SmallTest
public class BaseDvrDataManagerTest extends AndroidTestCase {
+ private static final String INPUT_ID = "input_id";
private static final int CHANNEL_ID = 273;
private DvrDataManagerInMemoryImpl mDvrDataManager;
@@ -62,8 +63,8 @@ public class BaseDvrDataManagerTest extends AndroidTestCase {
private ScheduledRecording createNewScheduledRecordingStartingNow() {
return ScheduledRecording.buildFrom(RecordingTestUtils
.createTestRecordingWithIdAndPeriod(
- -1,
- CHANNEL_ID,
+ ScheduledRecording.ID_NOT_SET,
+ INPUT_ID, CHANNEL_ID,
mFakeClock.currentTimeMillis(),
mFakeClock.currentTimeMillis() + TimeUnit.MINUTES.toMillis(5)))
.setState(ScheduledRecording.STATE_RECORDING_NOT_STARTED)
diff --git a/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java b/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java
index a9c5d390..b822f164 100644
--- a/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java
+++ b/tests/unit/src/com/android/tv/dvr/DvrDataManagerImplTest.java
@@ -16,7 +16,7 @@
package com.android.tv.dvr;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import com.android.tv.testing.dvr.RecordingTestUtils;
@@ -30,6 +30,7 @@ import java.util.List;
*/
@SmallTest
public class DvrDataManagerImplTest extends TestCase {
+ private static final String INPUT_ID = "input_id";
private static final int CHANNEL_ID = 273;
public void testGetNextScheduledStartTimeAfter() throws Exception {
@@ -37,32 +38,33 @@ public class DvrDataManagerImplTest extends TestCase {
List<ScheduledRecording> scheduledRecordings = new ArrayList<>();
assertNextStartTime(scheduledRecordings, 0L, DvrDataManager.NEXT_START_TIME_NOT_FOUND);
scheduledRecordings.add(RecordingTestUtils
- .createTestRecordingWithIdAndPeriod(id++, CHANNEL_ID, 10L, 20L));
+ .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++, CHANNEL_ID, 20L, 30L));
+ .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++, CHANNEL_ID, 30L, 40L));
+ .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++, CHANNEL_ID, 10L, 20L));
+ .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
scheduledRecordings.add(RecordingTestUtils
- .createTestRecordingWithIdAndPeriod(id++, CHANNEL_ID, 10L, 20L));
+ .createTestRecordingWithIdAndPeriod(id++, INPUT_ID, CHANNEL_ID, 10L, 20L));
scheduledRecordings.add(RecordingTestUtils
- .createTestRecordingWithIdAndPeriod(id++, CHANNEL_ID, 10L, 20L));
+ .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) {
+ private void assertNextStartTime(List<ScheduledRecording> scheduledRecordings, long startTime,
+ long expected) {
assertEquals("getNextScheduledStartTimeAfter()", expected,
DvrDataManagerImpl.getNextStartTimeAfter(scheduledRecordings, startTime));
}
diff --git a/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java b/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java
index 95b342bb..85e35c4d 100644
--- a/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java
+++ b/tests/unit/src/com/android/tv/dvr/DvrDataManagerInMemoryImpl.java
@@ -17,14 +17,14 @@
package com.android.tv.dvr;
import android.content.Context;
-import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
-import android.support.annotation.VisibleForTesting;
+import android.text.TextUtils;
+import android.util.Log;
import android.util.Range;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.common.recording.RecordedProgram;
+import com.android.tv.dvr.ScheduledRecording.RecordingState;
import com.android.tv.util.Clock;
import java.util.ArrayList;
@@ -37,14 +37,12 @@ import java.util.concurrent.atomic.AtomicLong;
/**
* A DVR Data manager that stores values in memory suitable for testing.
*/
-@VisibleForTesting // TODO(DVR): move to testing dir.
-@MainThread
-public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
+final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
private final static 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 List<SeasonRecording> mSeasonSchedule = new ArrayList<>();
+ private final Map<Long, SeriesRecording> mSeriesRecordings = new HashMap<>();
public DvrDataManagerInMemoryImpl(Context context, Clock clock) {
super(context, clock);
@@ -55,8 +53,18 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
return true;
}
+ @Override
+ public boolean isDvrScheduleLoadFinished() {
+ return true;
+ }
+
+ @Override
+ public boolean isRecordedProgramLoadFinished() {
+ return true;
+ }
+
private List<ScheduledRecording> getScheduledRecordingsPrograms() {
- return new ArrayList(mScheduledRecordings.values());
+ return new ArrayList<>(mScheduledRecordings.values());
}
@Override
@@ -69,8 +77,19 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
return new ArrayList<>(mScheduledRecordings.values());
}
- public List<SeasonRecording> getSeasonRecordings() {
- return mSeasonSchedule;
+ 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
@@ -87,11 +106,34 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
}
@Override
- public List<ScheduledRecording> getRecordingsThatOverlapWith(Range<Long> period) {
+ 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)) {
+ 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);
}
}
@@ -102,8 +144,10 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
* Add a new scheduled recording.
*/
@Override
- public void addScheduledRecording(ScheduledRecording scheduledRecording) {
- addScheduledRecordingInternal(scheduledRecording);
+ public void addScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording r : scheduledRecordings) {
+ addScheduledRecordingInternal(r);
+ }
}
@@ -115,7 +159,7 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
long id = r.getId();
if (mRecordedPrograms.containsKey(id)) {
mRecordedPrograms.put(id, r);
- notifyRecordedProgramChanged(r);
+ notifyRecordedProgramsChanged(r);
} else {
throw new IllegalArgumentException("Recording not found:" + r);
}
@@ -123,7 +167,7 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
public void removeRecordedProgram(RecordedProgram scheduledRecording) {
mRecordedPrograms.remove(scheduledRecording.getId());
- notifyRecordedProgramRemoved(scheduledRecording);
+ notifyRecordedProgramsRemoved(scheduledRecording);
}
@@ -147,35 +191,63 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
.setId(mNextId.incrementAndGet())
.build();
mRecordedPrograms.put(recordedProgram.getId(), recordedProgram);
- notifyRecordedProgramAdded(recordedProgram);
+ notifyRecordedProgramsAdded(recordedProgram);
return recordedProgram;
}
@Override
- public void addSeasonRecording(SeasonRecording seasonRecording) {
- mSeasonSchedule.add(seasonRecording);
+ public void addSeriesRecording(SeriesRecording... seriesRecordings) {
+ for (SeriesRecording r : seriesRecordings) {
+ mSeriesRecordings.put(r.getId(), r);
+ }
+ notifySeriesRecordingAdded(seriesRecordings);
}
@Override
- public void removeScheduledRecording(ScheduledRecording scheduledRecording) {
- mScheduledRecordings.remove(scheduledRecording.getId());
- notifyScheduledRecordingRemoved(scheduledRecording);
+ public void removeScheduledRecording(ScheduledRecording... scheduledRecordings) {
+ for (ScheduledRecording r : scheduledRecordings) {
+ mScheduledRecordings.remove(r.getId());
+ }
+ notifyScheduledRecordingRemoved(scheduledRecordings);
}
@Override
- public void removeSeasonSchedule(SeasonRecording seasonSchedule) {
- mSeasonSchedule.remove(seasonSchedule);
+ public void removeScheduledRecording(boolean forceRemove, ScheduledRecording... schedule) {
+ removeScheduledRecording(schedule);
}
@Override
- public void updateScheduledRecording(ScheduledRecording r) {
- long id = r.getId();
- if (mScheduledRecordings.containsKey(id)) {
- mScheduledRecordings.put(id, r);
- notifyScheduledRecordingStatusChanged(r);
- } else {
- throw new IllegalArgumentException("Recording not found:" + r);
+ 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
@@ -197,17 +269,37 @@ public final class DvrDataManagerInMemoryImpl extends BaseDvrDataManager {
@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 state) {
+ protected List<ScheduledRecording> getRecordingsWithState(int... states) {
ArrayList<ScheduledRecording> result = new ArrayList<>();
for (ScheduledRecording r : mScheduledRecordings.values()) {
- if(r.getState() == state){
- result.add(r);
+ for (int state : states) {
+ if (r.getState() == state) {
+ result.add(r);
+ break;
+ }
}
}
return result;
diff --git a/tests/unit/src/com/android/tv/dvr/DvrDbSyncTest.java b/tests/unit/src/com/android/tv/dvr/DvrDbSyncTest.java
new file mode 100644
index 00000000..7cb3721c
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/DvrDbSyncTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.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 android.test.AndroidTestCase;
+
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link DvrScheduleManager}
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class DvrDbSyncTest extends AndroidTestCase {
+ 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)
+ .setSeasonNumber(BASE_SEASON_NUMBER).setEpisodeNumber(BASE_EPISODE_NUMBER).build();
+ private static final ScheduledRecording BASE_SCHEDULE =
+ ScheduledRecording.builder(INPUT_ID, BASE_PROGRAM).build();
+
+ private DvrDbSync mDbSync;
+ @Mock private DvrDataManagerImpl mDataManager;
+ @Mock private ChannelDataManager mChannelDataManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ MockitoAnnotations.initMocks(this);
+ when(mChannelDataManager.isDbLoadFinished()).thenReturn(true);
+ mDbSync = new DvrDbSync(getContext(), mDataManager, mChannelDataManager);
+ }
+
+ public void testHandleUpdateProgram_null() {
+ addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE);
+ mDbSync.handleUpdateProgram(null, BASE_PROGRAM_ID);
+ verify(mDataManager).removeScheduledRecording(BASE_SCHEDULE);
+ }
+
+ 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);
+ }
+
+ 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());
+ }
+
+ public void testHandleUpdateProgram_changeSeason() {
+ addSchedule(BASE_PROGRAM_ID, BASE_SCHEDULE);
+ String seasonNumber = BASE_SEASON_NUMBER + "1";
+ String episodeNumber = BASE_EPISODE_NUMBER + "1";
+ Program program = new Program.Builder(BASE_PROGRAM).setSeasonNumber(seasonNumber)
+ .setEpisodeNumber(episodeNumber).build();
+ mDbSync.handleUpdateProgram(program, BASE_PROGRAM_ID);
+ assertUpdateScheduleCalled(program);
+ }
+
+ public void testHandleUpdateProgram_finished() {
+ addSchedule(BASE_PROGRAM_ID, ScheduledRecording.buildFrom(BASE_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_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/DvrRecordingServiceTest.java b/tests/unit/src/com/android/tv/dvr/DvrRecordingServiceTest.java
index 292233a2..0a203ede 100644
--- a/tests/unit/src/com/android/tv/dvr/DvrRecordingServiceTest.java
+++ b/tests/unit/src/com/android/tv/dvr/DvrRecordingServiceTest.java
@@ -17,15 +17,12 @@
package com.android.tv.dvr;
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 android.test.ServiceTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import com.android.tv.ApplicationSingletons;
-import com.android.tv.MockTvApplication;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.common.feature.TestableFeature;
import com.android.tv.testing.FakeClock;
@@ -40,25 +37,18 @@ import org.mockito.MockitoAnnotations;
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
public class DvrRecordingServiceTest extends ServiceTestCase<DvrRecordingService> {
-
@Mock Scheduler mMockScheduler;
- @Mock ApplicationSingletons mApplicationSingletons;
private final TestableFeature mDvrFeature = CommonFeatures.DVR;
- private DvrDataManagerInMemoryImpl mDataManager;
- private DvrRecordingService mService;
- private FakeClock mFakeClock = FakeClock.createWithCurrentTime();
+ private final FakeClock mFakeClock = FakeClock.createWithCurrentTime();
@Override
protected void setUp() throws Exception {
super.setUp();
mDvrFeature.enableForTest();
MockitoAnnotations.initMocks(this);
- mDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock);
- setApplication(new MockTvApplication(mApplicationSingletons));
- when(mApplicationSingletons.getDvrDataManager()).thenReturn(mDataManager);
setupService();
- mService = getService();
- mService.setScheduler(mMockScheduler);
+ DvrRecordingService service = getService();
+ service.setScheduler(mMockScheduler);
}
@Override
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..2850a5f7
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/DvrScheduleManagerTest.java
@@ -0,0 +1,634 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.support.test.filters.SmallTest;
+import android.test.MoreAsserts;
+import android.util.Range;
+
+import com.android.tv.testing.dvr.RecordingTestUtils;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests for {@link DvrScheduleManager}
+ */
+@SmallTest
+public class DvrScheduleManagerTest extends TestCase {
+ private static final String INPUT_ID = "input_id";
+
+ public void testGetConflictingSchedules_emptySchedule() {
+ List<ScheduledRecording> schedules = new ArrayList<>();
+ MoreAsserts.assertEmpty(DvrScheduleManager.getConflictingSchedules(schedules, 1));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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));
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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));
+ }
+
+ 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));
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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)
+ ));
+ Map<ScheduledRecording, Boolean> conflictsInfo = DvrScheduleManager
+ .getConflictingSchedulesInfo(schedules, 1);
+
+ assertNull(conflictsInfo.get(schedules.get(0)));
+ assertFalse(conflictsInfo.get(schedules.get(1)));
+ assertTrue(conflictsInfo.get(schedules.get(2)));
+ assertTrue(conflictsInfo.get(schedules.get(3)));
+ assertNull(conflictsInfo.get(schedules.get(4)));
+ assertTrue(conflictsInfo.get(schedules.get(5)));
+ assertNull(conflictsInfo.get(schedules.get(6)));
+ assertFalse(conflictsInfo.get(schedules.get(7)));
+ assertFalse(conflictsInfo.get(schedules.get(8)));
+ assertFalse(conflictsInfo.get(schedules.get(9)));
+ assertFalse(conflictsInfo.get(schedules.get(10)));
+
+ conflictsInfo = DvrScheduleManager
+ .getConflictingSchedulesInfo(schedules, 2);
+
+ assertNull(conflictsInfo.get(schedules.get(0)));
+ assertNull(conflictsInfo.get(schedules.get(1)));
+ assertNull(conflictsInfo.get(schedules.get(2)));
+ assertNull(conflictsInfo.get(schedules.get(3)));
+ assertNull(conflictsInfo.get(schedules.get(4)));
+ assertNull(conflictsInfo.get(schedules.get(5)));
+ assertNull(conflictsInfo.get(schedules.get(6)));
+ assertFalse(conflictsInfo.get(schedules.get(7)));
+ assertFalse(conflictsInfo.get(schedules.get(8)));
+ assertFalse(conflictsInfo.get(schedules.get(9)));
+ assertTrue(conflictsInfo.get(schedules.get(10)));
+
+ conflictsInfo = DvrScheduleManager
+ .getConflictingSchedulesInfo(schedules, 3);
+
+ assertNull(conflictsInfo.get(schedules.get(0)));
+ assertNull(conflictsInfo.get(schedules.get(1)));
+ assertNull(conflictsInfo.get(schedules.get(2)));
+ assertNull(conflictsInfo.get(schedules.get(3)));
+ assertNull(conflictsInfo.get(schedules.get(4)));
+ assertNull(conflictsInfo.get(schedules.get(5)));
+ assertNull(conflictsInfo.get(schedules.get(6)));
+ assertNull(conflictsInfo.get(schedules.get(7)));
+ assertTrue(conflictsInfo.get(schedules.get(8)));
+ assertNull(conflictsInfo.get(schedules.get(9)));
+ assertTrue(conflictsInfo.get(schedules.get(10)));
+ }
+} \ No newline at end of file
diff --git a/tests/unit/src/com/android/tv/dvr/EpisodicProgramLoadTaskTest.java b/tests/unit/src/com/android/tv/dvr/EpisodicProgramLoadTaskTest.java
new file mode 100644
index 00000000..2172d488
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/EpisodicProgramLoadTaskTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+
+import com.android.tv.dvr.EpisodicProgramLoadTask.ScheduledEpisode;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for {@link EpisodicProgramLoadTask}
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class EpisodicProgramLoadTaskTest extends AndroidTestCase {
+ 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";
+
+ public void testEpisodeAlreadyScheduled_true() {
+ List<ScheduledEpisode> episodes = new ArrayList<>();
+ ScheduledEpisode episode = new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1,
+ EPISODE_NUMBER1);
+ episodes.add(episode);
+ assertTrue(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER1)));
+ }
+
+ public void testEpisodeAlreadyScheduled_false() {
+ List<ScheduledEpisode> episodes = new ArrayList<>();
+ ScheduledEpisode episode = new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1,
+ EPISODE_NUMBER1);
+ episodes.add(episode);
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID2, SEASON_NUMBER1, EPISODE_NUMBER1)));
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER2, EPISODE_NUMBER1)));
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1, EPISODE_NUMBER2)));
+ }
+
+ public void testEpisodeAlreadyScheduled_null() {
+ List<ScheduledEpisode> episodes = new ArrayList<>();
+ ScheduledEpisode episode = new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1,
+ EPISODE_NUMBER1);
+ episodes.add(episode);
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, null, EPISODE_NUMBER1)));
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, SEASON_NUMBER1, null)));
+ assertFalse(EpisodicProgramLoadTask.isEpisodeScheduled(episodes,
+ new ScheduledEpisode(SERIES_RECORDING_ID1, null, null)));
+ }
+}
diff --git a/tests/unit/src/com/android/tv/dvr/InputTaskSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/InputTaskSchedulerTest.java
new file mode 100644
index 00000000..cfc9cf28
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/InputTaskSchedulerTest.java
@@ -0,0 +1,220 @@
+/*
+ * 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.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.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.Handler;
+import android.os.Looper;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+
+import com.android.tv.InputSessionManager;
+import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.dvr.InputTaskScheduler.RecordingTaskFactory;
+import com.android.tv.testing.FakeClock;
+import com.android.tv.testing.dvr.RecordingTestUtils;
+import com.android.tv.util.Clock;
+import com.android.tv.util.TestUtils;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for {@link InputTaskScheduler}.
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class InputTaskSchedulerTest extends AndroidTestCase {
+ 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;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ Handler fakeMainHandler = new Handler();
+ Handler workerThreadHandler = new Handler();
+ 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,
+ fakeMainHandler, workerThreadHandler, 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;
+ }
+ });
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testAddSchedule_past() throws Exception {
+ 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));
+ }
+
+ public void testAddSchedule_start() throws Exception {
+ 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();
+ }
+
+ public void testAddSchedule_consecutiveNoStop() throws Exception {
+ 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.
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).never()).stop();
+ }
+
+ public void testAddSchedule_consecutiveNoFail() throws Exception {
+ 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();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).never()).stop();
+ // The second schedule should not fail because it can starts after the first one finishes.
+ verify(mDataManager, timeout((int) LISTENER_TIMEOUT_MS).never())
+ .changeState(any(ScheduledRecording.class),
+ eq(ScheduledRecording.STATE_RECORDING_FAILED));
+ }
+
+ 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();
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).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);
+ }
+
+ public void testUpdateSchedule_noCancel() throws Exception {
+ ScheduledRecording r = RecordingTestUtils.createTestRecordingWithPeriod(INPUT_ID,
+ CHANNEL_ID, mFakeClock.currentTimeMillis(),
+ mFakeClock.currentTimeMillis() + TimeUnit.HOURS.toMillis(1));
+ mScheduler.handleAddSchedule(r);
+ mScheduler.handleBuildSchedule();
+ mScheduler.handleUpdateSchedule(r);
+ verify(mRecordingTasks.get(0), timeout((int) LISTENER_TIMEOUT_MS).never()).cancel();
+ }
+
+ public void testUpdateSchedule_cancel() throws Exception {
+ 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/RecordingTaskTest.java b/tests/unit/src/com/android/tv/dvr/RecordingTaskTest.java
index 2fb0228b..13ad9b0c 100644
--- a/tests/unit/src/com/android/tv/dvr/RecordingTaskTest.java
+++ b/tests/unit/src/com/android/tv/dvr/RecordingTaskTest.java
@@ -16,8 +16,9 @@
package com.android.tv.dvr;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.longThat;
@@ -25,18 +26,17 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
-import android.media.tv.TvRecordingClient;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.os.SystemClock;
import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import com.android.tv.InputSessionManager;
+import com.android.tv.InputSessionManager.RecordingSession;
import com.android.tv.data.Channel;
-import com.android.tv.data.Program;
import com.android.tv.dvr.RecordingTask.State;
import com.android.tv.testing.FakeClock;
import com.android.tv.testing.dvr.RecordingTestUtils;
@@ -56,15 +56,16 @@ import java.util.concurrent.TimeUnit;
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
public class RecordingTaskTest extends AndroidTestCase {
private static final long DURATION = TimeUnit.MINUTES.toMillis(30);
- private static final long START_OFFSET = Scheduler.MS_TO_WAKE_BEFORE_START;
- public static final int CHANNEL_ID = 273;
+ private static final long START_OFFSET_MS = Scheduler.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 DvrSessionManager mMockSessionManager;
- @Mock TvRecordingClient mMockTvRecordingClient;
+ @Mock InputSessionManager mMockSessionManager;
+ @Mock RecordingSession mMockRecordingSession;
@Override
protected void setUp() throws Exception {
@@ -82,46 +83,20 @@ public class RecordingTaskTest extends AndroidTestCase {
ScheduledRecording r = createRecording(channel);
RecordingTask task = createRecordingTask(r, channel);
String inputId = channel.getInputId();
- when(mMockSessionManager.canAcquireDvrSession(inputId, channel)).thenReturn(true);
- when(mMockSessionManager.createTvRecordingClient("tag", task, null))
- .thenReturn(mMockTvRecordingClient);
- when(mMockHandler.sendEmptyMessageDelayed(anyInt(), anyLong())).thenReturn(true);
-
- long delay = START_OFFSET - RecordingTask.MS_BEFORE_START;
- long uptime = SystemClock.uptimeMillis();
- assertTrue(task.handleMessage(createMessage(RecordingTask.MESSAGE_INIT)));
-
+ 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).canAcquireDvrSession(inputId, channel);
- verify(mMockSessionManager).createTvRecordingClient("tag", task, null);
- verify(mMockTvRecordingClient).tune(eq(inputId), eq(channel.getUri()));
-
- verifySendMessageAt(RecordingTask.MESSAGE_START_RECORDING, uptime + delay);
- verifyNoMoreInteractions(mMockHandler, mMockTvRecordingClient, mMockSessionManager);
+ 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().setId(CHANNEL_ID).setDisplayName("Test Ch " + CHANNEL_ID)
- .build();
- }
-
- public void testHandle_init_cannotAcquireSession() {
- Channel channel = createTestChannel();
- ScheduledRecording r = createRecording(channel);
- r = mDataManager.addScheduledRecordingInternal(r);
- RecordingTask task = createRecordingTask(r, channel);
-
- when(mMockSessionManager.canAcquireDvrSession(channel.getInputId(), channel))
- .thenReturn(false);
-
- assertTrue(task.handleMessage(createMessage(RecordingTask.MESSAGE_INIT)));
-
- assertEquals(State.ERROR, task.getState());
- verifySendMessage(Scheduler.HandlerWrapper.MESSAGE_REMOVE);
- ScheduledRecording updatedScheduledRecording = mDataManager
- .getScheduledRecording(r.getId());
- assertEquals("status", ScheduledRecording.STATE_RECORDING_FAILED,
- updatedScheduledRecording.getState());
+ return new Channel.Builder().setInputId(INPUT_ID).setId(CHANNEL_ID)
+ .setDisplayName("Test Ch " + CHANNEL_ID).build();
}
public void testOnConnected() {
@@ -129,31 +104,29 @@ public class RecordingTaskTest extends AndroidTestCase {
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;
+ long startTime = mFakeClock.currentTimeMillis() + START_OFFSET_MS;
long endTime = startTime + DURATION;
- return RecordingTestUtils.createTestRecordingWithPeriod(c.getId(), startTime, endTime);
+ return RecordingTestUtils.createTestRecordingWithPeriod(c.getInputId(), c.getId(),
+ startTime, endTime);
}
private RecordingTask createRecordingTask(ScheduledRecording r, Channel channel) {
- Program p = r.getProgramId() == ScheduledRecording.ID_NOT_SET ? null
- : new Program.Builder().setId(r.getId()).build();
- RecordingTask recordingTask = new RecordingTask(r, channel, mDvrManager,
+ RecordingTask recordingTask = new RecordingTask(getContext(), r, channel, mDvrManager,
mMockSessionManager, mDataManager, mFakeClock);
recordingTask.setHandler(mMockHandler);
return recordingTask;
}
- private void verifySendMessage(int what) {
- verify(mMockHandler).sendMessageAtTime(argThat(messageMatchesWhat(what)), anyLong());
- }
-
private void verifySendMessageAt(int what, long when) {
verify(mMockHandler).sendMessageAtTime(argThat(messageMatchesWhat(what)), delta(when, 100));
}
@@ -181,7 +154,7 @@ public class RecordingTaskTest extends AndroidTestCase {
return msg;
}
- public static ArgumentMatcher<Message> messageMatchesWhat(final int what) {
+ private static ArgumentMatcher<Message> messageMatchesWhat(final int what) {
return new ArgumentMatcher<Message>() {
@Override
public boolean matches(Object argument) {
diff --git a/tests/unit/src/com/android/tv/dvr/ScheduledProgramReaperTest.java b/tests/unit/src/com/android/tv/dvr/ScheduledProgramReaperTest.java
index 6210f464..847540c2 100644
--- a/tests/unit/src/com/android/tv/dvr/ScheduledProgramReaperTest.java
+++ b/tests/unit/src/com/android/tv/dvr/ScheduledProgramReaperTest.java
@@ -23,30 +23,34 @@ import com.android.tv.testing.dvr.RecordingTestUtils;
import junit.framework.TestCase;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
import java.util.concurrent.TimeUnit;
/**
* Tests for {@link ScheduledProgramReaper}.
*/
public class ScheduledProgramReaperTest extends TestCase {
- public static final int CHANNEL_ID = 273;
- public static final long DURATION = TimeUnit.HOURS.toMillis(1);
+ 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;
- private ScheduledRecording mScheduledRecordingDay1;
+ @Mock private DvrManager mDvrManager;
@Override
protected void setUp() throws Exception {
super.setUp();
+ MockitoAnnotations.initMocks(this);
mFakeClock = FakeClock.createWithTimeOne();
mDvrDataManager = new DvrDataManagerInMemoryImpl(null, mFakeClock);
mReaper = new ScheduledProgramReaper(mDvrDataManager, mFakeClock);
}
-
public void testRun_noRecordings() {
MoreAsserts.assertContentsInAnyOrder(mDvrDataManager.getAllScheduledRecordings());
mReaper.run();
@@ -101,7 +105,10 @@ public class ScheduledProgramReaperTest extends TestCase {
private ScheduledRecording addNewScheduledRecordingForTomorrow() {
long startTime = mFakeClock.currentTimeMillis() + TimeUnit.DAYS.toMillis(1);
- return RecordingTestUtils.addScheduledRecording(mDvrDataManager, CHANNEL_ID, startTime,
- startTime + DURATION);
+ 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/ScheduledRecordingTest.java b/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java
index 1aee6d33..96036418 100644
--- a/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java
+++ b/tests/unit/src/com/android/tv/dvr/ScheduledRecordingTest.java
@@ -16,11 +16,12 @@
package com.android.tv.dvr;
-import static com.android.tv.testing.dvr.RecordingTestUtils.createTestRecordingWithIdAndPeriod;
+import static com.android.tv.testing.dvr.RecordingTestUtils
+ .createTestRecordingWithIdAndPeriod;
import static com.android.tv.testing.dvr.RecordingTestUtils.normalizePriority;
+import android.support.test.filters.SmallTest;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import android.util.Range;
import com.android.tv.data.Channel;
@@ -39,19 +40,21 @@ import java.util.List;
*/
@SmallTest
public class ScheduledRecordingTest extends TestCase {
+ private static final String INPUT_ID = "input_id";
private static final int CHANNEL_ID = 273;
public void testIsOverLapping() throws Exception {
- ScheduledRecording r = createTestRecordingWithIdAndPeriod(1, CHANNEL_ID, 10L, 20L);
+ ScheduledRecording r = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID,
+ 10L, 20L);
assertOverLapping(false, 1L, 9L, r);
assertOverLapping(true, 1L, 20L, r);
- assertOverLapping(true, 1L, 10L, 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(true, 20L, 21L, r);
+ assertOverLapping(false, 20L, 21L, r);
assertOverLapping(false, 21L, 29L, r);
}
@@ -59,38 +62,42 @@ public class ScheduledRecordingTest extends TestCase {
public void testBuildProgram() {
Channel c = new Channel.Builder().build();
Program p = new Program.Builder().build();
- ScheduledRecording actual = ScheduledRecording.builder(p).setChannelId(c.getId()).build();
+ ScheduledRecording actual = ScheduledRecording.builder(INPUT_ID, p)
+ .setChannelId(c.getId()).build();
assertEquals("type", ScheduledRecording.TYPE_PROGRAM, actual.getType());
}
public void testBuildTime() {
- ScheduledRecording actual = createTestRecordingWithIdAndPeriod(1, CHANNEL_ID, 10L, 20L);
+ ScheduledRecording actual = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID,
+ 10L, 20L);
assertEquals("type", ScheduledRecording.TYPE_TIMED, actual.getType());
}
public void testBuildFrom() {
- ScheduledRecording expected = createTestRecordingWithIdAndPeriod(1, CHANNEL_ID, 10L, 20L);
+ ScheduledRecording expected = createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID,
+ 10L, 20L);
ScheduledRecording actual = ScheduledRecording.buildFrom(expected).build();
RecordingTestUtils.assertRecordingEquals(expected, actual);
}
public void testBuild_priority() {
ScheduledRecording a = normalizePriority(
- createTestRecordingWithIdAndPeriod(1, CHANNEL_ID, 10L, 20L));
+ createTestRecordingWithIdAndPeriod(1, INPUT_ID, CHANNEL_ID, 10L, 20L));
ScheduledRecording b = normalizePriority(
- createTestRecordingWithIdAndPeriod(2, CHANNEL_ID, 10L, 20L));
+ createTestRecordingWithIdAndPeriod(2, INPUT_ID, CHANNEL_ID, 10L, 20L));
ScheduledRecording c = normalizePriority(
- createTestRecordingWithIdAndPeriod(3, CHANNEL_ID, 10L, 20L));
+ createTestRecordingWithIdAndPeriod(3, INPUT_ID, CHANNEL_ID, 10L, 20L));
// default priority
- MoreAsserts.assertContentsInOrder(sortByPriority(c,b,a), a, b, c);
+ MoreAsserts.assertContentsInOrder(sortByPriority(c, b, a), a, b, c);
- // make C preferred over B
- c = ScheduledRecording.buildFrom(c).setPriority(b.getPriority() - 1).build();
- MoreAsserts.assertContentsInOrder(sortByPriority(c,b,a), a, c, b);
+ // 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) {
+ 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;
@@ -98,6 +105,6 @@ public class ScheduledRecordingTest extends TestCase {
private void assertOverLapping(boolean expected, long lower, long upper, ScheduledRecording r) {
assertEquals("isOverlapping(Range(" + lower + "," + upper + "), recording " + r, expected,
- r.isOverLapping(new Range<Long>(lower, upper)));
+ r.isOverLapping(new Range<>(lower, upper)));
}
}
diff --git a/tests/unit/src/com/android/tv/dvr/SchedulerTest.java b/tests/unit/src/com/android/tv/dvr/SchedulerTest.java
index 140d9091..30ac1ff1 100644
--- a/tests/unit/src/com/android/tv/dvr/SchedulerTest.java
+++ b/tests/unit/src/com/android/tv/dvr/SchedulerTest.java
@@ -16,7 +16,6 @@
package com.android.tv.dvr;
-
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.verify;
@@ -27,14 +26,17 @@ 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 android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+import com.android.tv.InputSessionManager;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.testing.FakeClock;
import com.android.tv.testing.dvr.RecordingTestUtils;
+import com.android.tv.util.TvInputManagerHelper;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.concurrent.TimeUnit;
@@ -45,16 +47,17 @@ import java.util.concurrent.TimeUnit;
@SmallTest
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
public class SchedulerTest extends AndroidTestCase {
+ private static final String INPUT_ID = "input_id";
private static final int CHANNEL_ID = 273;
private FakeClock mFakeClock;
private DvrDataManagerInMemoryImpl mDataManager;
private Scheduler mScheduler;
@Mock DvrManager mDvrManager;
- @Mock DvrSessionManager mSessionManager;
+ @Mock InputSessionManager mSessionManager;
@Mock AlarmManager mMockAlarmManager;
- @Mock
- ChannelDataManager mChannelDataManager;
+ @Mock ChannelDataManager mChannelDataManager;
+ @Mock TvInputManagerHelper mInputManager;
@Override
protected void setUp() throws Exception {
@@ -62,11 +65,13 @@ public class SchedulerTest extends AndroidTestCase {
MockitoAnnotations.initMocks(this);
mFakeClock = FakeClock.createWithCurrentTime();
mDataManager = new DvrDataManagerInMemoryImpl(getContext(), mFakeClock);
+ Mockito.when(mChannelDataManager.isDbLoadFinished()).thenReturn(true);
mScheduler = new Scheduler(Looper.myLooper(), mDvrManager, mSessionManager, mDataManager,
- mChannelDataManager, getContext(), mFakeClock, mMockAlarmManager);
+ mChannelDataManager, mInputManager, getContext(), mFakeClock, mMockAlarmManager);
}
public void testUpdate_none() throws Exception {
+ mScheduler.start();
mScheduler.update();
verifyZeroInteractions(mMockAlarmManager);
}
@@ -75,9 +80,15 @@ public class SchedulerTest extends AndroidTestCase {
long now = mFakeClock.currentTimeMillis();
long startTime = now + TimeUnit.HOURS.toMillis(12);
ScheduledRecording r = RecordingTestUtils
- .createTestRecordingWithPeriod(CHANNEL_ID, startTime,
+ .createTestRecordingWithPeriod(INPUT_ID, CHANNEL_ID, startTime,
startTime + TimeUnit.HOURS.toMillis(1));
mDataManager.addScheduledRecording(r);
+ mScheduler.start();
+ verify(mMockAlarmManager).set(
+ eq(AlarmManager.RTC_WAKEUP),
+ eq(startTime - Scheduler.MS_TO_WAKE_BEFORE_START),
+ any(PendingIntent.class));
+ Mockito.reset(mMockAlarmManager);
mScheduler.update();
verify(mMockAlarmManager).set(
eq(AlarmManager.RTC_WAKEUP),
@@ -89,7 +100,7 @@ public class SchedulerTest extends AndroidTestCase {
long now = mFakeClock.currentTimeMillis();
long startTime = now + 3;
ScheduledRecording r = RecordingTestUtils
- .createTestRecordingWithPeriod(273, startTime, startTime + 100);
+ .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/SeriesRecordingSchedulerTest.java b/tests/unit/src/com/android/tv/dvr/SeriesRecordingSchedulerTest.java
new file mode 100644
index 00000000..efefb93c
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/SeriesRecordingSchedulerTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr;
+
+import android.os.Build;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.util.LongSparseArray;
+
+import com.android.tv.data.Program;
+import com.android.tv.testing.FakeClock;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Tests for {@link SeriesRecordingScheduler}
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class SeriesRecordingSchedulerTest extends AndroidTestCase {
+ 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 DvrDataManagerInMemoryImpl mDataManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ FakeClock fakeClock = FakeClock.createWithCurrentTime();
+ mDataManager = new DvrDataManagerInMemoryImpl(getContext(), fakeClock);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
+ 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/SeriesRecordingTest.java b/tests/unit/src/com/android/tv/dvr/SeriesRecordingTest.java
new file mode 100644
index 00000000..c48fec02
--- /dev/null
+++ b/tests/unit/src/com/android/tv/dvr/SeriesRecordingTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr;
+
+import android.os.Build;
+import android.os.Parcel;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+
+import com.android.tv.data.Program;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests for {@link SeriesRecording}.
+ */
+@SmallTest
+@SdkSuppress(minSdkVersion = Build.VERSION_CODES.N)
+public class SeriesRecordingTest extends TestCase {
+ 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();
+
+ public void testParcelable() throws Exception {
+ 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();
+ }
+ }
+
+ public void testDoesProgramMatch_simpleMatch() {
+ assertDoesProgramMatch(mBaseProgram, mBaseSeriesRecording, true);
+ }
+
+ public void testDoesProgramMatch_differentSeriesId() {
+ Program program = new Program.Builder(mBaseProgram).setSeriesId(OTHER_SERIES_ID).build();
+ assertDoesProgramMatch(program, mBaseSeriesRecording, false);
+ }
+
+ public void testDoesProgramMatch_differentChannel() {
+ Program program = new Program.Builder(mBaseProgram).setChannelId(OTHER_CHANNEL_ID).build();
+ assertDoesProgramMatch(program, mBaseSeriesRecording, false);
+ }
+
+ 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);
+ }
+
+ 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/ui/SortedArrayAdapterTest.java b/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java
index 5195c57d..a571e626 100644
--- a/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java
+++ b/tests/unit/src/com/android/tv/dvr/ui/SortedArrayAdapterTest.java
@@ -35,12 +35,13 @@ public class SortedArrayAdapterTest extends TestCase {
public static final TestData P1 = TestData.create(1, "one");
public static final TestData P2 = TestData.create(2, "before");
public static final TestData P3 = TestData.create(3, "other");
+ public static final TestData EXTRA = TestData.create(4, "extra");
private TestSortedArrayAdapter mAdapter;
@Override
protected void setUp() throws Exception {
super.setUp();
- mAdapter = new TestSortedArrayAdapter();
+ mAdapter = new TestSortedArrayAdapter(Integer.MAX_VALUE, null);
}
public void testContents_empty() {
@@ -60,12 +61,45 @@ public class SortedArrayAdapterTest extends TestCase {
assertContentsInOrder(mAdapter, P2, P1);
}
- public void testAddAll_two() {
- mAdapter.addAll(Arrays.asList(P1, P2));
+ public void testSetInitialItems_two() {
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
assertNotEmpty();
assertContentsInOrder(mAdapter, P2, P1);
}
+ public void testMaxInitialCount() {
+ mAdapter = new TestSortedArrayAdapter(1, null);
+ mAdapter.setInitialItems(Arrays.asList(P1, P2));
+ assertNotEmpty();
+ assertEquals(mAdapter.size(), 1);
+ assertEquals(mAdapter.get(0), P2);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+
public void testRemove() {
mAdapter.add(P1);
mAdapter.add(P2);
@@ -97,7 +131,6 @@ public class SortedArrayAdapterTest extends TestCase {
private void assertEmpty() {
assertEquals("empty", true, mAdapter.isEmpty());
- assertContentsInOrder(mAdapter, EmptyHolder.EMPTY_HOLDER);
}
private void assertNotEmpty() {
@@ -153,14 +186,16 @@ public class SortedArrayAdapterTest extends TestCase {
}
};
- TestSortedArrayAdapter() {
- super(new ClassPresenterSelector(), TEXT_COMPARATOR);
+ TestSortedArrayAdapter(int maxInitialCount, Object extra) {
+ super(new ClassPresenterSelector(), TEXT_COMPARATOR, maxInitialCount);
+ if (extra != null) {
+ addExtraItem((TestData) extra);
+ }
}
@Override
long getId(TestData item) {
return item.mId;
}
-
}
-}
+} \ No newline at end of file
diff --git a/tests/unit/src/com/android/tv/menu/MenuTest.java b/tests/unit/src/com/android/tv/menu/MenuTest.java
index 324706f0..35e2a0fe 100644
--- a/tests/unit/src/com/android/tv/menu/MenuTest.java
+++ b/tests/unit/src/com/android/tv/menu/MenuTest.java
@@ -15,8 +15,8 @@
*/
package com.android.tv.menu;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.menu.Menu.OnMenuVisibilityChangeListener;
diff --git a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
index 34ed30fd..6b0726d9 100644
--- a/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
+++ b/tests/unit/src/com/android/tv/menu/TvOptionsRowAdapterTest.java
@@ -17,12 +17,13 @@ package com.android.tv.menu;
import android.media.tv.TvTrackInfo;
import android.os.SystemClock;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
import com.android.tv.BaseMainActivityTestCase;
import com.android.tv.MainActivity;
import com.android.tv.customization.CustomAction;
import com.android.tv.testing.Constants;
+import com.android.tv.testing.Utils;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.TvTestInputConstants;
@@ -47,11 +48,16 @@ public class TvOptionsRowAdapterTest extends BaseMainActivityTestCase {
@Override
protected void setUp() throws Exception {
super.setUp();
- mTvOptionsRowAdapter = new TvOptionsRowAdapter(mActivity,
- Collections.<CustomAction>emptyList());
+ mTvOptionsRowAdapter = new TvOptionsRowAdapter(mActivity, Collections.emptyList());
tuneToChannel(TvTestInputConstants.CH_1_DEFAULT_DONT_MODIFY);
waitUntilAudioTracksHaveSize(1);
- mTvOptionsRowAdapter.update();
+ // update should be called on the main thread to avoid the multi-thread problem.
+ Utils.runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mTvOptionsRowAdapter.update();
+ }
+ });
}
public void testUpdateAudioAction_2tracks() {
diff --git a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
index bf8fecde..c76de8fb 100644
--- a/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/ChannelRecordTest.java
@@ -16,8 +16,8 @@
package com.android.tv.recommendation;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.testing.Utils;
diff --git a/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java
index 0617845b..aae3a932 100644
--- a/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/FavoriteChannelEvaluatorTest.java
@@ -16,7 +16,7 @@
package com.android.tv.recommendation;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import java.util.List;
import java.util.concurrent.TimeUnit;
diff --git a/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java
index c67f3bc4..55a4e4ac 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecentChannelEvaluatorTest.java
@@ -16,7 +16,7 @@
package com.android.tv.recommendation;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import java.util.HashMap;
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 0ca67052..5270ffce 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
@@ -16,9 +16,9 @@
package com.android.tv.recommendation;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.data.Channel;
import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper;
diff --git a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
index 8427b19f..c9e21e9d 100644
--- a/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RoutineWatchEvaluatorTest.java
@@ -16,8 +16,8 @@
package com.android.tv.recommendation;
+import android.support.test.filters.SmallTest;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.data.Program;
import com.android.tv.recommendation.RoutineWatchEvaluator.ProgramTime;
@@ -199,9 +199,11 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva
List<String> wordList1 = RoutineWatchEvaluator.splitTextToWords(text1);
List<String> wordList2 = RoutineWatchEvaluator.splitTextToWords(text2);
assertEquals("MaximumMatchedWordSequenceLength", expectedLength,
- mEvaluator.calculateMaximumMatchedWordSequenceLength(wordList1, wordList2));
+ RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength(
+ wordList1, wordList2));
assertEquals("MaximumMatchedWordSequenceLength", expectedLength,
- mEvaluator.calculateMaximumMatchedWordSequenceLength(wordList2, wordList1));
+ RoutineWatchEvaluator.calculateMaximumMatchedWordSequenceLength(
+ wordList2, wordList1));
}
private void assertProgramTime(int expectedWeekDay, int expectedStartTimeOfDayInSec,
@@ -221,9 +223,9 @@ public class RoutineWatchEvaluatorTest extends EvaluatorTestCase<RoutineWatchEva
}
// Two tests for testing commutative law.
assertEquals("OverlappedIntervalScore", score,
- mEvaluator.calculateOverlappedIntervalScore(t1, t2));
+ RoutineWatchEvaluator.calculateOverlappedIntervalScore(t1, t2));
assertEquals("OverlappedIntervalScore", score,
- mEvaluator.calculateOverlappedIntervalScore(t2, t1));
+ RoutineWatchEvaluator.calculateOverlappedIntervalScore(t2, t1));
}
private int hourMinuteToSec(int hour, int minute) {
diff --git a/tests/unit/src/com/android/tv/tests/TvActivityTest.java b/tests/unit/src/com/android/tv/tests/TvActivityTest.java
index 92998ab3..3479785f 100644
--- a/tests/unit/src/com/android/tv/tests/TvActivityTest.java
+++ b/tests/unit/src/com/android/tv/tests/TvActivityTest.java
@@ -16,8 +16,8 @@
package com.android.tv.tests;
+import android.support.test.filters.MediumTest;
import android.test.ActivityInstrumentationTestCase2;
-import android.test.suitebuilder.annotation.MediumTest;
import com.android.tv.TvActivity;
diff --git a/tests/unit/src/com/android/tv/util/ImageCacheTest.java b/tests/unit/src/com/android/tv/util/ImageCacheTest.java
index 74d5ef72..e185d5f1 100644
--- a/tests/unit/src/com/android/tv/util/ImageCacheTest.java
+++ b/tests/unit/src/com/android/tv/util/ImageCacheTest.java
@@ -19,7 +19,7 @@ package com.android.tv.util;
import static com.android.tv.util.BitmapUtils.createScaledBitmapInfo;
import android.graphics.Bitmap;
-import android.test.suitebuilder.annotation.MediumTest;
+import android.support.test.filters.MediumTest;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
diff --git a/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java b/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java
index d44ffdef..fe094fb3 100644
--- a/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java
+++ b/tests/unit/src/com/android/tv/util/MultiLongSparseArrayTest.java
@@ -16,8 +16,8 @@
package com.android.tv.util;
+import android.support.test.filters.SmallTest;
import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
import junit.framework.TestCase;
diff --git a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java b/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
index 4e689780..36d25a10 100644
--- a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
+++ b/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
@@ -1,8 +1,8 @@
package com.android.tv.util;
import android.graphics.Bitmap;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
diff --git a/tests/unit/src/com/android/tv/util/TestUtils.java b/tests/unit/src/com/android/tv/util/TestUtils.java
index f4befaa8..e3bda138 100644
--- a/tests/unit/src/com/android/tv/util/TestUtils.java
+++ b/tests/unit/src/com/android/tv/util/TestUtils.java
@@ -18,8 +18,10 @@ package com.android.tv.util;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.graphics.drawable.Icon;
+import android.hardware.hdmi.HdmiDeviceInfo;
import android.media.tv.TvInputInfo;
-import android.os.Build;
+import android.os.Bundle;
import android.support.v4.os.BuildCompat;
import java.lang.reflect.Constructor;
@@ -28,41 +30,56 @@ import java.lang.reflect.Constructor;
* A class that includes convenience methods for testing.
*/
public class TestUtils {
+ /**
+ * Creates a {@link TvInputInfo}.
+ */
public static TvInputInfo createTvInputInfo(ResolveInfo service, String id, String parentId,
int type, boolean isHardwareInput) throws Exception {
+ return createTvInputInfo(service, id, parentId, type, isHardwareInput, false, 0);
+ }
+
+ /**
+ * Creates a {@link TvInputInfo}.
+ * <p>
+ * If this is called on MNC, {@code canRecord} and {@code tunerCount} are ignored.
+ */
+ public static TvInputInfo createTvInputInfo(ResolveInfo service, String id, String parentId,
+ int type, boolean isHardwareInput, boolean canRecord, int tunerCount) throws Exception {
// Create a mock TvInputInfo by using private constructor
- // TODO: Find better way to mock TvInputInfo.
// Note that mockito doesn't support mock/spy on final object.
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- return createTvInputInfoForLmp(service, id, parentId, type);
- } else if (BuildCompat.isAtLeastN()) {
- new RuntimeException("TOOD(dvr): implement"); // http://b/26903987
+ if (BuildCompat.isAtLeastN()) {
+ return createTvInputInfoForNyc(service, id, parentId, type, isHardwareInput, canRecord,
+ tunerCount);
}
return createTvInputInfoForMnc(service, id, parentId, type, isHardwareInput);
}
- private static TvInputInfo createTvInputInfoForLmp(ResolveInfo service, String id,
- String parentId, int type) throws Exception {
- Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor(new Class[]{
- ResolveInfo.class, String.class, String.class, int.class});
+ /**
+ * private TvInputInfo(ResolveInfo service, String id, int type, boolean isHardwareInput,
+ * CharSequence label, int labelResId, Icon icon, Icon iconStandby, Icon iconDisconnected,
+ * String setupActivity, String settingsActivity, boolean canRecord, int tunerCount,
+ * HdmiDeviceInfo hdmiDeviceInfo, boolean isConnectedToHdmiSwitch, String parentId,
+ * Bundle extras) {
+ */
+ private static TvInputInfo createTvInputInfoForNyc(ResolveInfo service, String id,
+ String parentId, int type, boolean isHardwareInput, boolean canRecord, int tunerCount)
+ throws Exception {
+ Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor(
+ ResolveInfo.class, String.class, int.class, boolean.class, CharSequence.class,
+ int.class, Icon.class, Icon.class, Icon.class, String.class, String.class,
+ boolean.class, int.class, HdmiDeviceInfo.class, boolean.class, String.class,
+ Bundle.class);
constructor.setAccessible(true);
- return constructor.newInstance(service, id, parentId, type);
+ return constructor.newInstance(service, id, type, isHardwareInput, null, 0, null, null,
+ null, null, null, canRecord, tunerCount, null, false, parentId, null);
}
private static TvInputInfo createTvInputInfoForMnc(ResolveInfo service, String id,
String parentId, int type, boolean isHardwareInput) throws Exception {
- Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor(new Class[]{
- ResolveInfo.class, String.class, String.class, int.class, boolean.class});
- constructor.setAccessible(true);
- return constructor.newInstance(service, id, parentId, type, isHardwareInput);
- }
-
- private static TvInputInfo createTvInputInfoForNpreview(ResolveInfo service, String id,
- String parentId, int type) throws Exception {
Constructor<TvInputInfo> constructor = TvInputInfo.class.getDeclaredConstructor(
- new Class[]{ResolveInfo.class, String.class, String.class, int.class});
+ ResolveInfo.class, String.class, String.class, int.class, boolean.class);
constructor.setAccessible(true);
- return constructor.newInstance(service, id, parentId, type);
+ return constructor.newInstance(service, id, parentId, type, isHardwareInput);
}
public static ResolveInfo createResolveInfo(String packageName, String name) {
diff --git a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
index 120e23a4..ba1e0b0b 100644
--- a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
+++ b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
@@ -18,9 +18,9 @@ package com.android.tv.util;
import android.content.pm.ResolveInfo;
import android.media.tv.TvInputInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.filters.Suppress;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.test.suitebuilder.annotation.Suppress;
import com.android.tv.testing.ComparatorTester;
@@ -35,7 +35,6 @@ import java.util.LinkedHashMap;
*/
@SmallTest
public class TvInputManagerHelperTest extends AndroidTestCase {
- @Suppress // http://b/26903987
public void testComparator() throws Exception {
final LinkedHashMap<String, Boolean> INPUT_ID_TO_PARTNER_INPUT = new LinkedHashMap<>();
INPUT_ID_TO_PARTNER_INPUT.put("2_partner_input", true);
diff --git a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
index b657f49c..9600fc0b 100644
--- a/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
+++ b/tests/unit/src/com/android/tv/util/TvTrackInfoUtilsTest.java
@@ -18,7 +18,7 @@ package com.android.tv.util;
import static com.android.tv.util.TvTrackInfoUtils.getBestTrackInfo;
import android.media.tv.TvTrackInfo;
-import android.test.suitebuilder.annotation.SmallTest;
+import android.support.test.filters.SmallTest;
import com.android.tv.testing.ComparatorTester;
@@ -41,7 +41,11 @@ public class TvTrackInfoUtilsTest extends TestCase {
private static final TvTrackInfo INFO_2_EN_5 = create("2", "en", 5);
- private static final TvTrackInfo INFO_3_FR_5 = create("3", "fr", 5);
+ private static final TvTrackInfo INFO_3_FR_8 = create("3", "fr", 8);
+
+ private static final TvTrackInfo INFO_4_NULL_2 = create("4", null, 2);
+
+ private static final TvTrackInfo INFO_5_NULL_6 = create("5", null, 6);
private static TvTrackInfo create(String id, String fr, int audioChannelCount) {
return new TvTrackInfo.Builder(TvTrackInfo.TYPE_AUDIO, id)
@@ -50,11 +54,13 @@ public class TvTrackInfoUtilsTest extends TestCase {
.build();
}
- private static final List<TvTrackInfo> ALL = Arrays.asList(INFO_1_EN_1, INFO_2_EN_5, INFO_3_FR_5);
+ private static final List<TvTrackInfo> ALL = Arrays.asList(INFO_1_EN_1, INFO_2_EN_5,
+ INFO_3_FR_8, INFO_4_NULL_2, INFO_5_NULL_6);
+ private static final List<TvTrackInfo> NULL_LANGUAGE_TRACKS = Arrays.asList(INFO_4_NULL_2,
+ INFO_5_NULL_6);
public void testGetBestTrackInfo_empty() {
- TvTrackInfo result = getBestTrackInfo(Collections.<TvTrackInfo>emptyList(),
- UN_MATCHED_ID, "en", 1);
+ TvTrackInfo result = getBestTrackInfo(Collections.emptyList(), UN_MATCHED_ID, "en", 1);
assertEquals("best track ", null, result);
}
@@ -70,7 +76,12 @@ public class TvTrackInfoUtilsTest extends TestCase {
public void testGetBestTrackInfo_languageOnlyMatch() {
TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, "fr", 1);
- assertEquals("best track ", INFO_3_FR_5, result);
+ assertEquals("best track ", INFO_3_FR_8, result);
+ }
+
+ public void testGetBestTrackInfo_channelCountOnlyMatchWithNullLanguage() {
+ TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, null, 8);
+ assertEquals("best track ", INFO_3_FR_8, result);
}
public void testGetBestTrackInfo_noMatches() {
@@ -78,6 +89,15 @@ public class TvTrackInfoUtilsTest extends TestCase {
assertEquals("best track ", INFO_1_EN_1, result);
}
+ public void testGetBestTrackInfo_noMatchesWithNullLanguage() {
+ TvTrackInfo result = getBestTrackInfo(ALL, UN_MATCHED_ID, null, 0);
+ assertEquals("best track ", INFO_1_EN_1, result);
+ }
+
+ public void testGetBestTrackInfo_channelCountAndIdMatch() {
+ TvTrackInfo result = getBestTrackInfo(NULL_LANGUAGE_TRACKS, "5", null, 6);
+ assertEquals("best track ", INFO_5_NULL_6, result);
+ }
public void testComparator() {
Comparator<TvTrackInfo> comparator = TvTrackInfoUtils.createComparator("1", "en", 1);
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java
index 42667bee..9dfb992e 100644
--- a/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_GetDurationString.java
@@ -15,8 +15,8 @@
*/
package com.android.tv.util;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import android.text.format.DateUtils;
import java.util.Calendar;
@@ -231,6 +231,14 @@ public class UtilsTest_GetDurationString extends AndroidTestCase {
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));
}
public void testMidnight() {
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java b/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java
index afcb812a..8a6f3e3b 100644
--- a/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_GetMultiAudioString.java
@@ -18,8 +18,8 @@ package com.android.tv.util;
import android.content.Context;
import android.media.tv.TvTrackInfo;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
/**
* Tests for {@link com.android.tv.util.Utils#getMultiAudioString}.
diff --git a/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java b/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java
index 160a2231..926deb07 100644
--- a/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java
+++ b/tests/unit/src/com/android/tv/util/UtilsTest_IsInGivenDay.java
@@ -16,8 +16,8 @@
package com.android.tv.util;
+import android.support.test.filters.SmallTest;
import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
import java.util.Calendar;
import java.util.GregorianCalendar;
diff --git a/usbtuner/res/animator/setup_before_entry.xml b/usbtuner-res/animator/setup_before_entry.xml
index 82ed7992..82ed7992 100644
--- a/usbtuner/res/animator/setup_before_entry.xml
+++ b/usbtuner-res/animator/setup_before_entry.xml
diff --git a/usbtuner/res/animator/setup_before_exit.xml b/usbtuner-res/animator/setup_before_exit.xml
index 5c00064c..5c00064c 100644
--- a/usbtuner/res/animator/setup_before_exit.xml
+++ b/usbtuner-res/animator/setup_before_exit.xml
diff --git a/usbtuner/res/animator/setup_entry.xml b/usbtuner-res/animator/setup_entry.xml
index 35fcd4a3..35fcd4a3 100644
--- a/usbtuner/res/animator/setup_entry.xml
+++ b/usbtuner-res/animator/setup_entry.xml
diff --git a/usbtuner/res/animator/setup_exit.xml b/usbtuner-res/animator/setup_exit.xml
index 4ce89cd6..4ce89cd6 100644
--- a/usbtuner/res/animator/setup_exit.xml
+++ b/usbtuner-res/animator/setup_exit.xml
diff --git a/usbtuner-res/drawable-xhdpi/ic_setup_antenna.png b/usbtuner-res/drawable-xhdpi/ic_setup_antenna.png
new file mode 100644
index 00000000..bb6d416e
--- /dev/null
+++ b/usbtuner-res/drawable-xhdpi/ic_setup_antenna.png
Binary files differ
diff --git a/usbtuner-res/drawable-xhdpi/recommendation_antenna.png b/usbtuner-res/drawable-xhdpi/recommendation_antenna.png
new file mode 100644
index 00000000..c4710bcc
--- /dev/null
+++ b/usbtuner-res/drawable-xhdpi/recommendation_antenna.png
Binary files differ
diff --git a/usbtuner-res/drawable-xhdpi/usb_antenna.png b/usbtuner-res/drawable-xhdpi/usb_antenna.png
new file mode 100644
index 00000000..ca5b2d72
--- /dev/null
+++ b/usbtuner-res/drawable-xhdpi/usb_antenna.png
Binary files differ
diff --git a/usbtuner/res/drawable/ut_scan_progress.xml b/usbtuner-res/drawable/ut_scan_progress.xml
index f4daf6c8..f4daf6c8 100644
--- a/usbtuner/res/drawable/ut_scan_progress.xml
+++ b/usbtuner-res/drawable/ut_scan_progress.xml
diff --git a/usbtuner/res/drawable/ut_selector_background.xml b/usbtuner-res/drawable/ut_selector_background.xml
index fb3899aa..fb3899aa 100644
--- a/usbtuner/res/drawable/ut_selector_background.xml
+++ b/usbtuner-res/drawable/ut_selector_background.xml
diff --git a/usbtuner/res/layout/ut_activity_playback.xml b/usbtuner-res/layout/ut_activity_playback.xml
index b640e6d5..b640e6d5 100644
--- a/usbtuner/res/layout/ut_activity_playback.xml
+++ b/usbtuner-res/layout/ut_activity_playback.xml
diff --git a/usbtuner/res/layout/ut_channel_list.xml b/usbtuner-res/layout/ut_channel_list.xml
index 430234f8..430234f8 100644
--- a/usbtuner/res/layout/ut_channel_list.xml
+++ b/usbtuner-res/layout/ut_channel_list.xml
diff --git a/usbtuner/res/layout/ut_channel_scan.xml b/usbtuner-res/layout/ut_channel_scan.xml
index 4579b81b..415ac929 100644
--- a/usbtuner/res/layout/ut_channel_scan.xml
+++ b/usbtuner-res/layout/ut_channel_scan.xml
@@ -51,7 +51,7 @@
android:maxLines="@integer/ut_scan_title_max_lines"
android:textColor="@color/ut_scan_title_text"
android:textSize="@dimen/ut_scan_title_text_size"
- android:text="@string/ut_channel_scan" />
+ android:text="@string/bt_channel_scan" />
<ProgressBar
android:id="@+id/tune_progress"
style="@android:style/Widget.ProgressBar.Horizontal"
diff --git a/usbtuner/res/layout/ut_guidance.xml b/usbtuner-res/layout/ut_guidance.xml
index 4f7d3f7a..4f7d3f7a 100644
--- a/usbtuner/res/layout/ut_guidance.xml
+++ b/usbtuner-res/layout/ut_guidance.xml
diff --git a/usbtuner/res/layout/ut_guidedactions.xml b/usbtuner-res/layout/ut_guidedactions.xml
index ae7efc0d..ae7efc0d 100644
--- a/usbtuner/res/layout/ut_guidedactions.xml
+++ b/usbtuner-res/layout/ut_guidedactions.xml
diff --git a/usbtuner/res/layout/ut_overlay_view.xml b/usbtuner-res/layout/ut_overlay_view.xml
index 1d54274d..681d662b 100644
--- a/usbtuner/res/layout/ut_overlay_view.xml
+++ b/usbtuner-res/layout/ut_overlay_view.xml
@@ -50,7 +50,7 @@
android:layout_marginRight="10dp"
android:gravity="right|top"
android:textSize="14sp" />
- <com.android.usbtuner.cc.CaptionLayout
+ <com.google.android.tv.tuner.cc.CaptionLayout
android:id="@+id/caption"
android:layout_width="match_parent"
android:layout_height="match_parent" />
diff --git a/usbtuner/res/raw/ut_kr_all b/usbtuner-res/raw/ut_kr_all
index 85320125..85320125 100644
--- a/usbtuner/res/raw/ut_kr_all
+++ b/usbtuner-res/raw/ut_kr_all
diff --git a/usbtuner/res/raw/ut_kr_atsc_center_frequencies_8vsb b/usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb
index 4ddbf0b6..4ddbf0b6 100644
--- a/usbtuner/res/raw/ut_kr_atsc_center_frequencies_8vsb
+++ b/usbtuner-res/raw/ut_kr_atsc_center_frequencies_8vsb
diff --git a/usbtuner/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/usbtuner/res/raw/ut_kr_cable_standard_center_frequencies_qam256
+++ b/usbtuner-res/raw/ut_kr_cable_standard_center_frequencies_qam256
diff --git a/usbtuner/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/usbtuner/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/usbtuner/res/raw/ut_us_all b/usbtuner-res/raw/ut_us_all
index d4a22560..f3d2d8fa 100644
--- a/usbtuner/res/raw/ut_us_all
+++ b/usbtuner-res/raw/ut_us_all
@@ -1,74 +1,74 @@
# US ATSC center frequencies
# TODO: Verify this.
-A 57028615 8VSB
-A 63028615 8VSB
-A 69028615 8VSB
-A 79028615 8VSB
-A 85028615 8VSB
-A 177028615 8VSB
-A 183028615 8VSB
-A 189028615 8VSB
-A 195028615 8VSB
-A 201028615 8VSB
-A 207028615 8VSB
-A 213028615 8VSB
-A 473028615 8VSB
-A 479028615 8VSB
-A 485028615 8VSB
-A 491028615 8VSB
-A 497028615 8VSB
-A 503028615 8VSB
-A 509028615 8VSB
-A 515028615 8VSB
-A 521028615 8VSB
-A 527028615 8VSB
-A 533028615 8VSB
-A 539028615 8VSB
-A 545028615 8VSB
-A 551028615 8VSB
-A 557028615 8VSB
-A 563028615 8VSB
-A 569028615 8VSB
-A 575028615 8VSB
-A 581028615 8VSB
-A 587028615 8VSB
-A 593028615 8VSB
-A 599028615 8VSB
-A 605028615 8VSB
-A 611028615 8VSB
-A 617028615 8VSB
-A 623028615 8VSB
-A 629028615 8VSB
-A 635028615 8VSB
-A 641028615 8VSB
-A 647028615 8VSB
-A 653028615 8VSB
-A 659028615 8VSB
-A 665028615 8VSB
-A 671028615 8VSB
-A 677028615 8VSB
-A 683028615 8VSB
-A 689028615 8VSB
-A 695028615 8VSB
-A 701028615 8VSB
-A 707028615 8VSB
-A 713028615 8VSB
-A 719028615 8VSB
-A 725028615 8VSB
-A 731028615 8VSB
-A 737028615 8VSB
-A 743028615 8VSB
-A 749028615 8VSB
-A 755028615 8VSB
-A 761028615 8VSB
-A 767028615 8VSB
-A 773028615 8VSB
-A 779028615 8VSB
-A 785028615 8VSB
-A 791028615 8VSB
-A 797028615 8VSB
-A 803028615 8VSB
+A 57028615 8VSB 2
+A 63028615 8VSB 3
+A 69028615 8VSB 4
+A 79028615 8VSB 5
+A 85028615 8VSB 6
+A 177028615 8VSB 7
+A 183028615 8VSB 8
+A 189028615 8VSB 9
+A 195028615 8VSB 10
+A 201028615 8VSB 11
+A 207028615 8VSB 12
+A 213028615 8VSB 13
+A 473028615 8VSB 14
+A 479028615 8VSB 15
+A 485028615 8VSB 16
+A 491028615 8VSB 17
+A 497028615 8VSB 18
+A 503028615 8VSB 19
+A 509028615 8VSB 20
+A 515028615 8VSB 21
+A 521028615 8VSB 22
+A 527028615 8VSB 23
+A 533028615 8VSB 24
+A 539028615 8VSB 25
+A 545028615 8VSB 26
+A 551028615 8VSB 27
+A 557028615 8VSB 28
+A 563028615 8VSB 29
+A 569028615 8VSB 30
+A 575028615 8VSB 31
+A 581028615 8VSB 32
+A 587028615 8VSB 33
+A 593028615 8VSB 34
+A 599028615 8VSB 35
+A 605028615 8VSB 36
+A 611028615 8VSB 37
+A 617028615 8VSB 38
+A 623028615 8VSB 39
+A 629028615 8VSB 40
+A 635028615 8VSB 41
+A 641028615 8VSB 42
+A 647028615 8VSB 43
+A 653028615 8VSB 44
+A 659028615 8VSB 45
+A 665028615 8VSB 46
+A 671028615 8VSB 47
+A 677028615 8VSB 48
+A 683028615 8VSB 49
+A 689028615 8VSB 50
+A 695028615 8VSB 51
+A 701028615 8VSB 52
+A 707028615 8VSB 53
+A 713028615 8VSB 54
+A 719028615 8VSB 55
+A 725028615 8VSB 56
+A 731028615 8VSB 57
+A 737028615 8VSB 58
+A 743028615 8VSB 59
+A 749028615 8VSB 60
+A 755028615 8VSB 61
+A 761028615 8VSB 62
+A 767028615 8VSB 63
+A 773028615 8VSB 64
+A 779028615 8VSB 65
+A 785028615 8VSB 66
+A 791028615 8VSB 67
+A 797028615 8VSB 68
+A 803028615 8VSB 69
# US EIA/NCTA Standard Cable center frequencies
# Channels are in ascending EIA/NCTA channel designation order
# TODO: Verify this.
diff --git a/usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb b/usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb
new file mode 100644
index 00000000..bb59e07e
--- /dev/null
+++ b/usbtuner-res/raw/ut_us_atsc_center_frequencies_8vsb
@@ -0,0 +1,71 @@
+# US ATSC center frequencies
+# TODO: Verify this.
+
+A 57028615 8VSB 2
+A 63028615 8VSB 3
+A 69028615 8VSB 4
+A 79028615 8VSB 5
+A 85028615 8VSB 6
+A 177028615 8VSB 7
+A 183028615 8VSB 8
+A 189028615 8VSB 9
+A 195028615 8VSB 10
+A 201028615 8VSB 11
+A 207028615 8VSB 12
+A 213028615 8VSB 13
+A 473028615 8VSB 14
+A 479028615 8VSB 15
+A 485028615 8VSB 16
+A 491028615 8VSB 17
+A 497028615 8VSB 18
+A 503028615 8VSB 19
+A 509028615 8VSB 20
+A 515028615 8VSB 21
+A 521028615 8VSB 22
+A 527028615 8VSB 23
+A 533028615 8VSB 24
+A 539028615 8VSB 25
+A 545028615 8VSB 26
+A 551028615 8VSB 27
+A 557028615 8VSB 28
+A 563028615 8VSB 29
+A 569028615 8VSB 30
+A 575028615 8VSB 31
+A 581028615 8VSB 32
+A 587028615 8VSB 33
+A 593028615 8VSB 34
+A 599028615 8VSB 35
+A 605028615 8VSB 36
+A 611028615 8VSB 37
+A 617028615 8VSB 38
+A 623028615 8VSB 39
+A 629028615 8VSB 40
+A 635028615 8VSB 41
+A 641028615 8VSB 42
+A 647028615 8VSB 43
+A 653028615 8VSB 44
+A 659028615 8VSB 45
+A 665028615 8VSB 46
+A 671028615 8VSB 47
+A 677028615 8VSB 48
+A 683028615 8VSB 49
+A 689028615 8VSB 50
+A 695028615 8VSB 51
+A 701028615 8VSB 52
+A 707028615 8VSB 53
+A 713028615 8VSB 54
+A 719028615 8VSB 55
+A 725028615 8VSB 56
+A 731028615 8VSB 57
+A 737028615 8VSB 58
+A 743028615 8VSB 59
+A 749028615 8VSB 60
+A 755028615 8VSB 61
+A 761028615 8VSB 62
+A 767028615 8VSB 63
+A 773028615 8VSB 64
+A 779028615 8VSB 65
+A 785028615 8VSB 66
+A 791028615 8VSB 67
+A 797028615 8VSB 68
+A 803028615 8VSB 69
diff --git a/usbtuner/res/raw/ut_us_cable_standard_center_frequencies_qam256 b/usbtuner-res/raw/ut_us_cable_standard_center_frequencies_qam256
index d2d5e302..d2d5e302 100644
--- a/usbtuner/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..4337a696
--- /dev/null
+++ b/usbtuner-res/values-af/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Aan"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Af"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Wag asseblief dat verwerking voltooi word"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Kies jou kanaalbron"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Geen sein nie"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kon nie op <xliff:g id="CHANNEL_NAME">%s</xliff:g> inskakel nie"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Kon nie inskakel nie"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Soek weer"</item>
+ <item msgid="2092797862490235174">"Klaar"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Soek TV-kanale"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Opstelling van TV-ontvanger"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Opstelling van USB-TV-ontvanger"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-TV-ontvanger 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..a903ee76
--- /dev/null
+++ b/usbtuner-res/values-am/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"በርቷል"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ጠፍቷል"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ማስኬድን ለማጠናቀቅ እባክዎ ይጠብቁ"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"የጣቢያ ምንጭዎን ይምረጡ"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"ምንም ሲግናል የለም"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"ወደ <xliff:g id="CHANNEL_NAME">%s</xliff:g> መቃኘት አልተሳካም"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"መቃኘት አልተሳካም"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"የቴሌቪዥን መቃኛ ሶፍትዌር በቅርብ ጊዜ ተዘምኗል። እባክዎ ሰርጦቹን እንደገና ይቃኟቸው።"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ኦዲዮን ለማንቃት በስርዓት ድምጽ ቅንብሮች ውስጥ የዙሪያ ድምጽን ያንቁ"</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="bt_setup_new_description" msgid="256690722062003128">"የእርስዎ ቴሌቪዥን ከቴሌቪዥን ሲግናል ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አብዛኛዎቹን ጣቢያዎች ለመቀበል አቀማመጡን ወይም አቅጣጫውን ማስተካከል ሊኖርብዎት ይችላል። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"የዩኤስቢ መቃኛው መሰካቱን እና ከቴሌቪዥን ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"እንደገና ቃኝ"</item>
+ <item msgid="2092797862490235174">"ተከናውኗል"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"የቲቪ ጣቢያዎችን ቃኝ"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"የቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"የዩኤስቢ ቴሌቪዥን መቃኛ ማዋቀር"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"የUSB TV መቃኛ ግንኙነቱ ተቋርጧል።"</string>
+</resources>
diff --git a/usbtuner-res/values-ar/strings.xml b/usbtuner-res/values-ar/strings.xml
new file mode 100644
index 00000000..ecfde3e8
--- /dev/null
+++ b/usbtuner-res/values-ar/strings.xml
@@ -0,0 +1,99 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"تشغيل"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"إيقاف"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"الرجاء الانتظار لحين انتهاء المعالجة"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"تحديد مصدر القنوات"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"لا توجد إشارة"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"أخفق الضبط على <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"أخفق الضبط"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"تم تحديث برنامج الموالف مؤخرًا. الرجاء إعادة البحث عن القنوات."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"يمكنك تشغيل الصوت المحيطي في إعدادات صوت النظام لتفعيل الصوت"</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="bt_setup_new_description" msgid="256690722062003128">"تحقق من توصيل التلفزيون بمصدر إشارة البث التلفزيوني.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فقد تحتاج إلى ضبط موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏تحقق من توصيل الموالف عبر 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\nتحقق من توصيل الموالف عبر USB بمصدر إشارة البث التلفزيوني.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"بحث مرة أخرى"</item>
+ <item msgid="2092797862490235174">"تم"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"البحث عن قنوات تلفزيونية"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"إعداد موالف التلفزيون"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"‏إعداد موالف التلفزيون عبر USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"‏تم فصل موالف التلفزيون عبر USB."</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..f5305817
--- /dev/null
+++ b/usbtuner-res/values-az-rAZ/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Aktiv"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Deaktiv"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lütfən, prosesi başa çatdırmaq üçün gözləyin"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Kanal mənbəyinizi seçin"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Siqnal Yoxdur"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> kanalına sazlamaq mümkün olmadı"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Sazlamaq uğursuz oldu"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"TV kanalları üçün skan"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV Kökləyici quraşdırması"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV Kökləyici quraşdırması"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..0854c09e
--- /dev/null
+++ b/usbtuner-res/values-bg/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Включване"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Изключване"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Моля, изчакайте обработването да завърши"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Изберете източник на канали"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Няма сигнал"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Превключването към „<xliff:g id="CHANNEL_NAME">%s</xliff:g>“ не бе успешно"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Превключването не бе успешно"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтуерът на тунера е актуализиран наскоро. Моля, сканирайте отново каналите."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Активирайте обемния звук от настройките за системния, за да включите аудиото"</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="bt_setup_new_description" msgid="256690722062003128">"Уверете се, че телевизорът ви е свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите оптимален брой канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Уверете се, че 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\nУверете се, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Повторно сканиране"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Сканиране за телевизионни канали"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Настройване на телевизионния тунер"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Настройване на телевизионния USB тунер"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Връзката с телевизионния USB тунер е прекратена."</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..236e2d96
--- /dev/null
+++ b/usbtuner-res/values-bn-rBD/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"চালু আছে"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"বন্ধ করুন"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"প্রক্রিয়াকরণ সম্পূর্ণ না হওয়া পর্যন্ত অনুগ্রহ করে অপেক্ষা করুন"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"আপনার চ্যানেলের উৎস নির্বাচন করুন"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"কোনো সংকেত নেই"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> এ টিউন করতে ব্যর্থ হয়েছে"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"টিউন করতে ব্যর্থ হয়েছে"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"টিউনার সফ্টওয়্যার সম্প্রতি আপডেট করা হয়েছে৷ অনুগ্রহ করে চ্যানেলগুলি পুনরায় স্ক্যান করুন৷"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"অডিও সক্ষম করতে সিস্টেম সাউন্ড সেটিংসে সারাউন্ড সাউন্ড সক্ষম করুন"</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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"আবার স্ক্যান করুন"</item>
+ <item msgid="2092797862490235174">"সম্পন্ন"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"টিভি চ্যানেলগুলি স্ক্যান করুন"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV টিউনার সেট আপ"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB টিভি টিউনার সেট আপ"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB টিভি টিউনারের সংযোগ বিচ্ছিন্ন হয়েছে।"</string>
+</resources>
diff --git a/usbtuner-res/values-ca/strings.xml b/usbtuner-res/values-ca/strings.xml
new file mode 100644
index 00000000..af90c3d6
--- /dev/null
+++ b/usbtuner-res/values-ca/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activa"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desactiva"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera per finalitzar el processament"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecciona la font del canal"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sense senyal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"No s\'ha pogut sintonitzar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"No s\'ha pogut sintonitzar"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Cerca canals de televisió"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuració del sintonitzador de televisió"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuració del sintonitzador de televisió USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"El sintonitzador de televisió USB 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..151083c6
--- /dev/null
+++ b/usbtuner-res/values-cs/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">"Televizní tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Televizní tuner USB"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Zapnout"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Vypnout"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vyčkejte prosím, než bude zpracování dokončeno"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Vyberte zdroj kanálu"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Žádný signál"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kanál <xliff:g id="CHANNEL_NAME">%s</xliff:g> se nepodařilo naladit"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Nelze naladit"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Znovu vyhledat"</item>
+ <item msgid="2092797862490235174">"Hotovo"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Vyhledejte televizní kanály"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Nastavení televizního tuneru"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Nastavení televizního tuneru USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Televizní tuner USB 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..cea5d3c3
--- /dev/null
+++ b/usbtuner-res/values-da/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Til"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Fra"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vent, mens behandlingen afsluttes"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Vælg din kanalkilde"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Intet signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> kunne ikke indlæses"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Indlæsningen lykkedes ikke"</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="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="bt_setup_new_description" msgid="256690722062003128">"Kontrollér, 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">"Kontrollér, 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-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\nKontrollér, 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\nKontrollér, 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-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="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. Kontrollér, 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. Kontrollér, 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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Scan efter tv-kanaler"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Konfiguration med TV Tuner"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Konfiguration af USB-TV Tuner"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-tuneren til fjernsynet af frakoblet."</string>
+</resources>
diff --git a/usbtuner-res/values-de/strings.xml b/usbtuner-res/values-de/strings.xml
new file mode 100644
index 00000000..eab5fb1d
--- /dev/null
+++ b/usbtuner-res/values-de/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"An"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Aus"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Bitte warten Sie, bis die Verarbeitung abgeschlossen ist"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Kanalquelle auswählen"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Kein Signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"\"<xliff:g id="CHANNEL_NAME">%s</xliff:g>\" konnte nicht eingestellt werden"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Fehler beim Einstellen"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Nach TV-Kanälen suchen"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV-Tuner einrichten"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB-TV-Tuner einrichten"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Verbindung zum USB-TV-Empfänger 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..6a033e3c
--- /dev/null
+++ b/usbtuner-res/values-el/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Ενεργό"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Ανενεργό"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Περιμένετε να ολοκληρωθεί η επεξεργασία"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Επιλέξτε την πηγή του καναλιού σας"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Χωρίς σήμα"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Αποτυχία συντονισμού <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Αποτυχία συντονισμού"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Το λογισμικό δέκτη ενημερώθηκε πρόσφατα. Επαναλάβετε τη σάρωση των καναλιών."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ενεργοποιήστε τον περιφερειακό ήχο στις ρυθμίσεις ήχου συστήματος για να ενεργοποιήσετε τον ήχο"</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="bt_setup_new_description" msgid="256690722062003128">"Βεβαιωθείτε ότι η τηλεόρασή σας είναι συνδεδεμένη σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Βεβαιωθείτε ότι ο δέκτης 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\nΒεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Εκ νέου σάρωση"</item>
+ <item msgid="2092797862490235174">"Ολοκληρώθηκε"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Σάρωση για τηλεοπτικά κανάλια"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Ρύθμιση δέκτη τηλεόρασης"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Ρύθμιση δέκτη τηλεόρασης USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Ο δέκτης τηλεόρασης USB έχει αποσυνδεθεί."</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..11e639fd
--- /dev/null
+++ b/usbtuner-res/values-en-rAU/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"On"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Off"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Select your channel source"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"No Signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Failed to tune"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Scan for TV channels"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV Tuner setup"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV Tuner setup"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..11e639fd
--- /dev/null
+++ b/usbtuner-res/values-en-rGB/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"On"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Off"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Select your channel source"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"No Signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Failed to tune"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Scan for TV channels"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV Tuner setup"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV Tuner setup"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..11e639fd
--- /dev/null
+++ b/usbtuner-res/values-en-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"On"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Off"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Please wait to finish processing"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Select your channel source"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"No Signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Failed to tune"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Scan again"</item>
+ <item msgid="2092797862490235174">"Finished"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Scan for TV channels"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV Tuner setup"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV Tuner setup"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..da7ec699
--- /dev/null
+++ b/usbtuner-res/values-es-rUS/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activar"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desactivar"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera a que finalice el procesamiento"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Seleccionar la fuente del canal"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sin señal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"No se pudo sintonizar el canal <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"No se pudo sintonizar el canal"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Busca canales de TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuración del sintonizador de TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuración del sintonizador de TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Se desconectó el sintonizador de TV USB."</string>
+</resources>
diff --git a/usbtuner-res/values-es/strings.xml b/usbtuner-res/values-es/strings.xml
new file mode 100644
index 00000000..e8e34cb2
--- /dev/null
+++ b/usbtuner-res/values-es/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activar"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desactivar"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera hasta que finalice el procesamiento"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecciona la fuente de canales"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sin señal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"No se ha podido sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"No se podido sintonizar"</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="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="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 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-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-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="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 ubicació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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Busca canales de TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuración del sintonizador de canales"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuración de sintonizador de canales USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Sintonizador de canales USB 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..70cb238a
--- /dev/null
+++ b/usbtuner-res/values-et-rEE/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Sees"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Väljas"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Oodake, kuni töötlemine on lõppenud"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Valige kanali allikas"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Pole signaali"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kanalile <xliff:g id="CHANNEL_NAME">%s</xliff:g> häälestamine ebaõnnestus"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Häälestamine ebaõnnestus"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Otsi uuesti"</item>
+ <item msgid="2092797862490235174">"Valmis"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Otsige telekanaleid"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Telerituuneri seadistus"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB-telerituuneri seadistus"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-telerituuner 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..a0d456eb
--- /dev/null
+++ b/usbtuner-res/values-eu-rES/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Aktibatuta"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desaktibatuta"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Itxaron prozesatzen amaitu arte"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Hautatu kanalaren iturburua"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ez dago seinalerik"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Ezin izan da sintonizatu <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Ezin izan da sintonizatu"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Bilatu berriro"</item>
+ <item msgid="2092797862490235174">"Eginda"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Bilatu telebista-kanalak"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Sintonizadorearen konfigurazioa"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB bidezko sintonizadorearen konfigurazioa"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB bidezko sintonizadorea deskonektatu da."</string>
+</resources>
diff --git a/usbtuner-res/values-fa/strings.xml b/usbtuner-res/values-fa/strings.xml
new file mode 100644
index 00000000..8a51a4fc
--- /dev/null
+++ b/usbtuner-res/values-fa/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"روشن"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"خاموش"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"لطفاً تا پایان پردازش صبر کنید"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"منبع کانال را انتخاب کنید"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"بدون سیگنال"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"تنظیم به <xliff:g id="CHANNEL_NAME">%s</xliff:g> انجام نشد"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"تنظیم ناموفق بود"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"نرم‌افزار تنظیم‌کننده اخیراً به‌روزرسانی شده است. لطفاً کانال‌ها را دوباره اسکن کنید."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"برای فعال کردن صدا، صدای فراگیر را در تنظیمات صدای سیستم فعال کنید"</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="bt_setup_new_description" msgid="256690722062003128">"مطمئن شوید تلویزیونتان به منبع سیگنال تلویزیونی متصل است.\n\nدر صورت استفاده از آنتن بی‌سیم شاید لازم باشد برای دریافت کانال‌های بیشتر، موقعیت یا جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏مطمئن شوید تنظیم‌کننده 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\nمطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"اسکن دوباره"</item>
+ <item msgid="2092797862490235174">"تمام"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"اسکن کانال‌های تلویزیون"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"راه‌اندازی تنظیم‌کننده تلویزیون"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"‏راه‌اندازی تنظیم‌کننده تلویزیون USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"‏تیونر تلویزیون USB قطع شد."</string>
+</resources>
diff --git a/usbtuner-res/values-fi/strings.xml b/usbtuner-res/values-fi/strings.xml
new file mode 100644
index 00000000..79d0c7f5
--- /dev/null
+++ b/usbtuner-res/values-fi/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Ota käyttöön"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Poista käytöstä"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Odota, että käsittely on valmis."</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Valitse kanavalähde."</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ei signaalia"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kanavan <xliff:g id="CHANNEL_NAME">%s</xliff:g> virittäminen epäonnistui."</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Virittäminen epäonnistui."</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Hae uudelleen"</item>
+ <item msgid="2092797862490235174">"Valmis"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Hae TV-kanavia"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV-virittimen määritys"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB-TV-virittimen määritys"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-TV-viritin 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..54e8759e
--- /dev/null
+++ b/usbtuner-res/values-fr-rCA/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activer"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Désactivé"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Veuillez patienter jusqu\'à la fin du traitement"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Sélectionnez votre source de chaînes"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Aucun signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Impossible de syntoniser <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Échec de syntonisation"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Rechercher à nouveau"</item>
+ <item msgid="2092797862490235174">"Terminé"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Rechercher les chaînes de télévision"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuration du syntoniseur télé"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configurer le syntoniseur télé USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Le syntoniseur télé USB est débranché."</string>
+</resources>
diff --git a/usbtuner-res/values-fr/strings.xml b/usbtuner-res/values-fr/strings.xml
new file mode 100644
index 00000000..4cb551f7
--- /dev/null
+++ b/usbtuner-res/values-fr/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activé"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Désactivé"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Veuillez patienter jusqu\'à la fin du traitement."</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Sélectionnez la source de la chaîne."</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Aucun signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Échec de sélection de la chaîne <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Échec de la sélection de la chaîne"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Rechercher à nouveau"</item>
+ <item msgid="2092797862490235174">"OK"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Rechercher les chaînes de télévision"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuration du tuner TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuration du tuner TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Le tuner TV USB est 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..58c14605
--- /dev/null
+++ b/usbtuner-res/values-gl-rES/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Activar"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desactivar"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Espera a que finalice o procesamento"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecciona a fonte da túa canle"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sen sinal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Produciuse un erro ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Produciuse un erro ao sintonizar"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Busca canles de televisión"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuración do sintonizador de televisión"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuración do sintonizador USB de televisión"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Desconectouse o sintonizador de televisión USB."</string>
+</resources>
diff --git a/usbtuner-res/values-hi/strings.xml b/usbtuner-res/values-hi/strings.xml
new file mode 100644
index 00000000..ea0d51c1
--- /dev/null
+++ b/usbtuner-res/values-hi/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"चालू करें"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"बंद करें"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया पूरी होने का इंतज़ार करें"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"अपना चैनल स्रोत चुनें"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"कोई सिग्नल नहीं"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> को ट्यून करने में विफल रहा"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ट्यून करने में विफल रहा"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्यूनर सॉफ़्टवेयर को हाल ही में अपडेट किया गया है. कृपया चैनलों के लिए दोबारा स्कैन करें."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ऑडियो सक्षम करने के लिए सिस्टम साउंड सेटिंग में सराउंड साउंड सक्षम करें"</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="bt_setup_new_description" msgid="256690722062003128">"पुष्टि करें कि आपका टीवी किसी टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\n\nयदि ओवर द एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल पाने के लिए आपको उसकी स्थिति या दिशा समायोजित करने की आवश्यकता हो सकती है. सबसे अच्छे परिणामों के लिए, उसे ऊंचाई पर और किसी खिड़की के पास लगाएं."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"पुष्टि करें कि 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\nपुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट किया हुआ है.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"दोबारा स्‍कैन करें"</item>
+ <item msgid="2092797862490235174">"हो गया"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"टीवी चैनलों के लिए स्‍कैन करें"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"टीवी ट्यूनर सेटअप"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB टीवी ट्यूनर सेटअप"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB टीवी ट्यूनर डिस्कनेक्ट किया गया."</string>
+</resources>
diff --git a/usbtuner-res/values-hr/strings.xml b/usbtuner-res/values-hr/strings.xml
new file mode 100644
index 00000000..4a00deaf
--- /dev/null
+++ b/usbtuner-res/values-hr/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 prijemnik"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV prijemnik"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Uključeno"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Isključeno"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Pričekajte da obrada završi"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Odaberite izvor kanala"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Nema signala"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Namještanje na kanal <xliff:g id="CHANNEL_NAME">%s</xliff:g> nije uspjelo"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Namještanje nije uspjelo"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Pretražite TV kanale"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Postavljanje TV prijemnika"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Postavljanje USB TV prijemnika"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..e2bca51c
--- /dev/null
+++ b/usbtuner-res/values-hu/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Be"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Ki"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Kérjük, várja meg a folyamat befejezését"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Válassza ki a csatornaforrást"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Nincs jel"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Nem sikerült behangolni a(z) <xliff:g id="CHANNEL_NAME">%s</xliff:g> csatornát"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Nem sikerült a hangolás"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Tévécsatornák keresése"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Tévétuner beállítása"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB-s tévétuner beállítása"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Megszakadt a kapcsolat az USB-s tévé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..a8e33eac
--- /dev/null
+++ b/usbtuner-res/values-hy-rAM/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Միացնել"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Անջատել"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Սպասեք՝ մինչ որոնումը ավարտվի"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Ընտրեք ալիքի աղբյուրը"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ազդանշան չկա"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Չհաջողվեց անցնել <xliff:g id="CHANNEL_NAME">%s</xliff:g> ալիքին"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Չհաջողվեց անցնել ալիքին"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Ընդունիչի ծրագրակազմը վերջերս թարմացվել է: Նորից որոնեք ալիքները:"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Ձայնը միացնելու համար համակարգի ձայնի կարգավորումներում ակտիվացրեք ծավալային ձայնը"</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="bt_setup_new_description" msgid="256690722062003128">"Համոզվեք, որ հեռուստացույցը միացված է հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Համոզվեք, որ 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\nՀամոզվեք, որ USB կարգավորիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Կրկին որոնել"</item>
+ <item msgid="2092797862490235174">"Պատրաստ է"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Հեռուստաալիքների որոնում"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Հեռուստակարգավորիչի տեղադրում"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB հեռուստակարգավորիչի տեղադրում"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB հեռուստակարգավորիչն անջատված է:"</string>
+</resources>
diff --git a/usbtuner-res/values-in/strings.xml b/usbtuner-res/values-in/strings.xml
new file mode 100644
index 00000000..e534c9c6
--- /dev/null
+++ b/usbtuner-res/values-in/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Aktif"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Nonaktif"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Harap tunggu sampai pemrosesan selesai"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Pilih sumber saluran Anda"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Tidak Ada Sinyal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Gagal menyetel ke <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Gagal menyetel"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Perangkat lunak 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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Pindai lagi"</item>
+ <item msgid="2092797862490235174">"Selesai"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Pindai saluran TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Penyiapan Tuner TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Penyiapan Tuner TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Koneksi tuner TV USB 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..f63d9810
--- /dev/null
+++ b/usbtuner-res/values-is-rIS/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Kveikja"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Slökkva"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Bíddu þar til vinnslu lýkur"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Veldu inntak rása"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ekkert merki"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Mistókst að stilla á <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Mistókst að stilla"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Leita aftur"</item>
+ <item msgid="2092797862490235174">"Lokið"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Skanna eftir sjónvarpsstöðvum"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Uppsetning sjónvarpsmóttakara"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Uppsetning USB-sjónvarpsmóttakara"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-sjónvarpsmó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..7787d019
--- /dev/null
+++ b/usbtuner-res/values-it/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Attiva"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Disattiva"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Attendi il completamento dell\'elaborazione"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Seleziona la tua fonte canale"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Nessun segnale"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Sintonizzazione su <xliff:g id="CHANNEL_NAME">%s</xliff:g> non riuscita"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Sintonizzazione non riuscita"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Cerca canali TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configurazione del sintonizzatore TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configurazione del sintonizzatore TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Sintonizzatore TV USB 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..5dab5f15
--- /dev/null
+++ b/usbtuner-res/values-iw/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="ut_setup_on" msgid="7755608253387551795">"מופעל"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"כבוי"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"המתן לסיום העיבוד"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"בחר את מקור הערוצים"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"אין אות"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"לא ניתן היה לכוון לערוץ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"הכוונון נכשל"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"תוכנת הטיונר עודכנה לאחרונה. סרוק מחדש את הערוצים."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"הפעל סראונד בהגדרות צלילי מערכת כדי להפעיל אודיו"</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="bt_setup_new_description" msgid="256690722062003128">"ודא שהטלוויזיה מחוברת למקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לשנות את המיקום או את הכיוון שלה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה ליד חלון."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"‏ודא שטיונר 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\nודא שטיונר USB מחובר למקור אות בטלוויזיה.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"סרוק שוב"</item>
+ <item msgid="2092797862490235174">"סיום"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"סריקה לאיתור ערוצי טלוויזיה"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"הגדרת טיונר טלוויזיה"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"‏הגדרת טיונר ה-USB בטלוויזיה"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"‏טיונר ה-USB שבטלוויזיה מנותק."</string>
+</resources>
diff --git a/usbtuner-res/values-ja/strings.xml b/usbtuner-res/values-ja/strings.xml
new file mode 100644
index 00000000..88af255a
--- /dev/null
+++ b/usbtuner-res/values-ja/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ON"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"OFF"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"処理が完了するまでこのままお待ちください"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"チャンネル ソースを選択してください"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"信号がありません"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"「<xliff:g id="CHANNEL_NAME">%s</xliff:g>」に合わせることができませんでした"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"合わせることができませんでした"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"最近チューナー ソフトウェアが更新されています。チャンネルをもう一度スキャンしてください。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"音声を有効にするには、システムのサウンド設定でサラウンド サウンドをオンにしてください"</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="bt_setup_new_description" msgid="256690722062003128">"テレビがテレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"再スキャン"</item>
+ <item msgid="2092797862490235174">"完了"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"テレビのチャンネルをスキャン"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"テレビ チューナーのセットアップ"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB テレビ チューナーのセットアップ"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV チューナーの接続が解除されています。"</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..e09428d7
--- /dev/null
+++ b/usbtuner-res/values-ka-rGE/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ჩართვა"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"გამორთვა"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"გთხოვთ, მოითმინოთ დამუშავების დასრულებამდე"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"აირჩიეთ არხების წყარო"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"სიგნალი არ არის"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>-ზე გადართვა ვერ მოხერხდა"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"არხზე გადართვა ვერ მოხერხდა"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ტუნერის პროგრამული უზრუნველყოფა ახლახან განახლდა. გთხოვთ, ხელახლა დაასკანიროთ არხები."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"აუდიოს ჩასართავად, სისტემის ხმის პარამეტრებში ჩართეთ მოცულობითი ხმა"</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="bt_setup_new_description" msgid="256690722062003128">"დარწმუნდით, რომ თქვენი ტელევიზორი მიერთებულია სატელევიზიო სიგნალის წყაროსთან..\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"დარწმუნდით, რომ 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">"ეს მოქმედება ამოშლის TV ტუნერით ნაპოვნ არხებს და ახალი არხების სკანირება ხელახლა მოხდება.\n\nდარწმუნდით, რომ თქვენი ტელევიზორი მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების უმეტესობის მისაღებად, მისი განლაგების ან მიმართულების დარეგულება მოგიწევთ. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"ეს მოქმედება ამოშლის USB ტუნერით ნაპოვნ არხებს და ხელახლა მოხდება ახალი არხების სკანირება.\n\nდარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ხელახლა სკანირება"</item>
+ <item msgid="2092797862490235174">"მზადაა"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"სატელევიზიო არხების სკანირება"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV-ტუნერის დაყენება"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV-ტუნერის დაყენება"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV-ტუნერი გაითიშა."</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..3c2ba4f3
--- /dev/null
+++ b/usbtuner-res/values-kk-rKZ/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Қосу"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Өшіру"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Өңдеу аяқталғанша күте тұрыңыз"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Арна көзін таңдаңыз"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Сигнал жоқ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> арнасына реттелмеді"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Реттелмеді"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Тюнердің бағдарламалық құралы жақында жаңартылды. Арналарды қайта іздеңіз."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Аудиомазмұнды қосу үшін жүйенің параметрлерінде көлемдік дыбысты қосыңыз"</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="bt_setup_new_description" msgid="256690722062003128">"Теледидардың ТД сигнал көзіне қосылғанын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Қайта іздеу"</item>
+ <item msgid="2092797862490235174">"Орындалды"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"ТД арналарын іздеу"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ТД тюнерін орнату"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TД тюнерін орнату"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TД тюнері ажыратылды."</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..904f3e5d
--- /dev/null
+++ b/usbtuner-res/values-km-rKH/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"បើក"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"បិទ"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"សូមរង់ចាំដើម្បីបញ្ចប់ដំណើរការ"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"ជ្រើសប្រភពប៉ុស្តិ៍របស់អ្នក"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"គ្មានរលកសញ្ញាទេ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"បានបរាជ័យក្នុងការបើកប៉ុស្តិ៍ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"បរាជ័យក្នុងការរាវប៉ុស្តិ៍"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"កម្មវិធីអង្គរាវប៉ុស្តិ៍បានអាប់ដេតថ្មីៗនេះ។ សូមស្កេនរកប៉ុស្តិ៍ទាំងនេះម្តងទៀត។"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"បើកដំណើរការសំឡេងជុំវិញនៅក្នុងការកំណត់សំឡេងប្រព័ន្ធដើម្បីបើកដំណើរការអូឌីយ៉ូ"</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="bt_setup_new_description" msgid="256690722062003128">"សូមផ្ទៀងផ្ទាត់ថាប៉ុស្តិ៍ទូរទស្សន៍របស់អ្នកត្រូវបានភ្ជាប់ទៅប្រភពរលកសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង ឬទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងខ្ពស់ និងនៅជិតបង្អួច។"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"ផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ 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\nផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB រាវប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ស្កេនម្តងទៀត"</item>
+ <item msgid="2092797862490235174">"រួចរាល់"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"ស្កេនរកប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ការដំឡើងអង្គរាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"ការដំឡើងឧបករណ៍ USB រាវប៉ុស្តិ៍ទូរទស្សន៍"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"អង្គរាវប៉ុស្តិ៍ USB សម្រាប់ទូរទស្សន៍ត្រូវបានផ្តាច់"</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..fb97ae2b
--- /dev/null
+++ b/usbtuner-res/values-kn-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ಆನ್"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ಆಫ್"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವುದನ್ನು ಪೂರೈಸಲು ದಯವಿಟ್ಟು ಕಾಯಿರಿ"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"ನಿಮ್ಮ ಚಾನಲ್ ಮೂಲವನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"ಯಾವುದೇ ಸಂಕೇತವಿಲ್ಲ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> ಗೆ ಟ್ಯೂನ್ ಮಾಡುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ಟ್ಯೂನ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ಟ್ಯೂನರ್ ಸಾಫ್ಟ್‌ವೇರ್‍ ಅನ್ನು ಇತ್ತೀಚಿಗೆ ಅಪ್‌ಡೇಟ್ ಮಾಡಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಚಾನಲ್‌ಗಳನ್ನು ಮರು-ಸ್ಕ್ಯಾನ್‌ ಮಾಡಿ."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ಆಡಿಯೊ ಸಕ್ರಿಯಗೊಳಿಸಲು ಸಿಸ್ಟಂ ಧ್ವನಿ ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಸರೌಂಡ್ ಧ್ವನಿಯನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</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="bt_setup_new_description" msgid="256690722062003128">"ನಿಮ್ಮ ಟಿವಿಯನ್ನು ಟಿವಿ ಸಿಗ್ನಲ್‌ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಾನ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡು"</item>
+ <item msgid="2092797862490235174">"ಮುಗಿದಿದೆ"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"ಟಿವಿ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB ಟಿವಿ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB ಟಿವಿ ಟ್ಯೂನರ್ ಸಂಪರ್ಕ ಕಡಿತಗೊಂಡಿದೆ."</string>
+</resources>
diff --git a/usbtuner-res/values-ko/strings.xml b/usbtuner-res/values-ko/strings.xml
new file mode 100644
index 00000000..2c67ab6f
--- /dev/null
+++ b/usbtuner-res/values-ko/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"사용"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"사용 안함"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"처리가 완료될 때까지 기다려 주세요."</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"채널 소스 선택"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"신호 없음"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>에 맞추지 못함"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"조정 실패"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"튜너 소프트웨어가 최근 업데이트되었습니다. 채널을 다시 스캔하세요."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"오디오를 사용하려면 시스템 사운드 설정에서 서라운드 사운드를 사용 설정하세요."</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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"다시 스캔"</item>
+ <item msgid="2092797862490235174">"완료"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"TV 채널 스캔"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV 튜너 설정"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV 튜너 설정"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 튜너 연결 끊어짐"</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..39e9d1df
--- /dev/null
+++ b/usbtuner-res/values-ky-rKG/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Күйүк"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Өчүк"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Иштетүүнү бүтүрүү үчүн күтө туруңуз"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Каналыңыздын булагын тандаңыз"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Сигнал жок"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> каналы кармалган жок"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Канал кармалбай койду"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Күүлөгүчтүн программасы жакында жаңыртылды. Каналдарды кайрадан издеңиз."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Каналдын үнүн чыгаруу үчүн тутумдун үн жөндөөлөрүнө өтүп, көлөмдүү добушту иштетүү керек"</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="bt_setup_new_description" msgid="256690722062003128">"Сыналдыңыз сыналгынын сигнал булагына туташтырылганын текшериңиз. \n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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\nIЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
+ <string name="ut_setup_again_description" msgid="7837706010887799255">"Ушуну менен USB күүлөгүчтөн табылган каналдар алынып салынып, жаңы каналдар кайра изделет.\n\nUSB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Кайра издөө"</item>
+ <item msgid="2092797862490235174">"Бүттү"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Сыналгы каналдарын издөө"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Сыналгы күүлөгүчүн жөндөө"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB күүлөгүчүнүн жөндөөсү"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV күүлөгүчү ажыратылды."</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..954baabe
--- /dev/null
+++ b/usbtuner-res/values-lo-rLA/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ເປີດ"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ປິດ"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"ກະລຸນາລໍຖ້າເພື່ອປະມວນຜົນໃຫ້ສຳເລັດ"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"ເລືອກແຫຼ່ງສັນຍານຊ່ອງຂອງທ່ານ"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"ບໍ່ມີສັນຍານ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"ປັບຫາ <xliff:g id="CHANNEL_NAME">%s</xliff:g> ບໍ່ສຳເລັດ"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ປັບຊ່ອງບໍ່ສຳເລັດ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ຊອບແວຕົວປັບສັນຍານໄດ້ຮັບການອັບເດດເມື່ອບໍ່ດົນມານີ້ແລ້ວ. ກະລຸນາສະແກນຫາຊ່ອງຄືນໃໝ່."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ເປີດໃຊ້ສຽງຮອບທິດທາງໃນການຕັ້ງຄ່າລະບົບສຽງເພື່ອເປີດໃຊ້ສຽງ."</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="bt_setup_new_description" msgid="256690722062003128">"ໃຫ້ກວດສອບວ່າທ່ານເຊື່ອມຕໍ່ໂທລະພາບຂອງທ່ານຫາແຫລ່ງສັນຍານໂທລະພາບແລ້ວ.\n\nຫາກໃຊ້ເສົາອາກາດ, ໃຫ້ຍ້າຍບ້ອນວາງ ຫຼື ທິດທາງຂອງມັນ. ເພື່ອໃຫ້ໄດ້ຜົນທີ່ດີທີ່ສຸດ, ໃຫ້ວາງໄວ້ບ່ອນສູງໃກ້ໆປ່ອງຢ້ຽມ ແລ້ວລອງສະແກນໃໝ່."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານ 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\nໃຫ້ກວດສອບເບິ່ງເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້ສຽບສາຍ ແລະ ເຊື່ອມຕໍ່ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວຫຼືຍັງ.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ສະແກນອີກ"</item>
+ <item msgid="2092797862490235174">"ແລ້ວໆ"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"ສະແກນຫາຊ່ອງໂທລະພາບ"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະພາບ"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"ຕັ້ງຄ່າຕົວຮັບສັນຍານໂທລະພາບແບບ USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"ການເຊື່ອມຕໍ່ USB TV tuner ຖືກຕັດແລ້ວ."</string>
+</resources>
diff --git a/usbtuner-res/values-lt/strings.xml b/usbtuner-res/values-lt/strings.xml
new file mode 100644
index 00000000..3ce2efc7
--- /dev/null
+++ b/usbtuner-res/values-lt/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 imtuvas"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV imtuvas"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Įjungta"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Išjungti"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Palaukite, kol baigsis apdorojimas"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Pasirinkite kanalo šaltinį"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Nėra signalo"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Nepavyko įjungti kanalo „<xliff:g id="CHANNEL_NAME">%s</xliff:g>“"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Nepavyko suderinti"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Vykdykite TV kanalų nuskaitymą"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV imtuvo sąranka"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV imtuvo sąranka"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..9337e7b3
--- /dev/null
+++ b/usbtuner-res/values-lv/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 kanālu meklētājs"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"USB TV kanālu meklētājs"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Ieslēgta"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Izslēgta"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lūdzu, uzgaidiet, līdz tiks pabeigta apstrāde!"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Atlasiet kanāla avotu"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Nav signāla"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Neizdevās atrast kanālu <xliff:g id="CHANNEL_NAME">%s</xliff:g>."</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Neizdevās atrast"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"TV kanālu meklēšana"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV kanālu meklētāja iestatīšana"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV kanālu meklētāja iestatīšana"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..fb2e71e7
--- /dev/null
+++ b/usbtuner-res/values-mk-rMK/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Вклучено"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Исклучено"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Почекајте да заврши обработувањето"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Изберете го изворот на каналот"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Нема сигнал"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Не успеа да се избере <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Не успеа да се избере"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтверот на приемникот неодамна е ажуриран. Скенирајте ги каналите повторно."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Овозможете опкружувачки звук во поставките за звуци на системот за да овозможите аудио"</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="bt_setup_new_description" msgid="256690722062003128">"Потврдете дека телевизорот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, можеби ќе треба да ја приспособите поставеноста или насоката за да примате најмногу канали. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Потврдете дека 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\nПотврдете дека USB-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Скенирај пак"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Скенирај ТВ-канали"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Поставување ТВ приемник"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Поставување ТВ приемник со USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"TV приемникот преку USB е исклучен."</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..d025ec7b
--- /dev/null
+++ b/usbtuner-res/values-ml-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ഓണാക്കുക"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ഓഫാക്കുക"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"പ്രോസസ്സുചെയ്യൽ പൂർത്തിയാകുന്നത് വരെ കാത്തിരിക്കുക"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"നിങ്ങളുടെ ചാനൽ ഉറവിടം തിരഞ്ഞെടുക്കുക"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"സിഗ്‌നൽ ഇല്ല"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> എന്നതിലേക്ക് ട്യൂൺ ചെയ്യുന്നത് പരാജയപ്പെട്ടു"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ട്യൂൺ ചെയ്യുന്നത് പരാജയപ്പെട്ടു"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ട്യൂണർ സോഫ്‌റ്റ്‌വെയർ അടുത്തിടെ അപ്‌ഡേറ്റുചെയ്‌തു. ചാനലുകൾ വീണ്ടും സ്‌കാൻ ചെയ്യുക."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ഓഡിയോ പ്രവർത്തനക്ഷമമാക്കുന്നതിന് സിസ്റ്റം ശബ്ദ ക്രമീകരണത്തിൽ സറൗണ്ട് ശബ്‌ദം പ്രവർത്തനക്ഷമമാക്കുക"</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="bt_setup_new_description" msgid="256690722062003128">"ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് നിങ്ങളുടെ ടിവി കണക്റ്റുചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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\nസ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"വീണ്ടും സ്കാൻ ചെയ്യുക"</item>
+ <item msgid="2092797862490235174">"പൂർത്തിയായി"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"ടിവി ചാനലുകൾക്കായി സ്കാൻ ചെയ്യുക"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB ടിവി ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB ടിവി ട്യൂണർ വിച്ഛേദിച്ചു."</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..51f7a8dd
--- /dev/null
+++ b/usbtuner-res/values-mn-rMN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Идэвхтэй"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Идэвхгүй"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Боловсруулж дуусах хүртэл хүлээнэ үү"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Сувгийн эх үүсвэрээ сонгоно уу"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Дохио алга"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>-д тохируулж чадсангүй"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Тохируулж чадсангүй"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Тохируулагчийн програмыг саяхан шинэчилсэн байна. Дахин суваг хайна уу."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Аудиог идэвхжүүлэхийн тулд орчны дууны системийг дууны тохиргоонд идэвхжүүлнэ үү"</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="bt_setup_new_description" msgid="256690722062003128">"ТВ-ээ ТВ дохионы үүсвэртэй холбосон эсэхээ батална уу.\n\nХэрэв агаарын антен хэрэглэж байгаа бол олон суваг авахын тулд антены байршил эсвэл чиглэлийг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Дахин хайх"</item>
+ <item msgid="2092797862490235174">"Дууссан"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"TВ-н суваг хайх"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ТВ тохируулагчийн тохиргоо"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB ТВ тохируулагчийн тохиргоо"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB ТВ тохируулагч салсан байна."</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..2ea242f1
--- /dev/null
+++ b/usbtuner-res/values-mr-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"चालू"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"बंद"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया पूर्ण होण्‍याची प्रतीक्षा करा"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"आपला चॅनेल स्रोत निवडा"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"सिग्नल नाही"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> वर ट्यून करण्‍यात अयशस्वी झाले"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ट्यून करण्यात अयशस्वी झाले"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्यूनर सॉफ्टवेअर अलीकडे अद्यतनित केले आहे. कृपया चॅनेल पुन्हा स्कॅन करा."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ऑडिओ सक्षम करण्यासाठी सिस्टीम ध्वनी सेटिंग्ज मध्ये सराउंड ध्वनी सक्षम करा"</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="bt_setup_new_description" msgid="256690722062003128">"टीव्ही सिग्नल स्रोताशी आपला टीव्ही कनेक्ट केला असल्याची खात्री करा. \n\n बिनतारी अँटेना वापरत असल्‍यास, आपल्‍याला कदाचित सर्वाधिक चॅनेल मिळविण्‍यासाठी त्याचे स्थान किंवा दिशा समायोजित करावी लागेल. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"USB ट्यूनर प्लगिन केले आणि 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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"पुन्हा स्कॅन करा"</item>
+ <item msgid="2092797862490235174">"पूर्ण झाले"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"टीव्ही चॅनेलसाठी स्कॅन करा"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"टीव्ही ट्यूनर सेटअप"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB टीव्ही ट्यूनर सेटअप"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV ट्यूनर डिस्कनेक्ट केला."</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..578e8ae5
--- /dev/null
+++ b/usbtuner-res/values-ms-rMY/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Hidupkan"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Matikan"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Sila tunggu sehingga proses selesai"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Pilih sumber saluran anda"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Tiada Isyarat"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Gagal menala ke <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Gagal menala"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Imbas lagi"</item>
+ <item msgid="2092797862490235174">"Selesai"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Imbas saluran TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Persediaan Penala TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Persediaan Penala TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Penala TV USB 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..56a29e51
--- /dev/null
+++ b/usbtuner-res/values-my-rMM/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ဖွင့်ပါ"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ပိတ်ပါ"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"စီမံဆောင်ရွက်မှု အဆုံးသတ်ရန် ခဏစောင့်ပါ"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"သင့်ချန်နယ်လိုင်းထုတ်လွှင့်ရာ အရင်းအမြစ်ကို ရွေးပါ"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"လိုင်းမမိပါ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> သို့ ချိန်ညှိခြင်း မအောင်မြင်ပါ"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ချိန်ညှိ၍ မရခဲ့ပါ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ချန်နယ်ချိန်ဆော့ဖ်ဝဲကို မကြာသေးမီက အပ်ဒိတ်လုပ်ခဲ့သည်။ ချန်နယ်လိုင်းများကို ပြန်ရှာပါ။"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"အသံဖွင့်ရန် ပတ်ပတ်လည်အသံစနစ်ဆက်တင်များကို ဖွင့်ပါ"</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="bt_setup_new_description" msgid="256690722062003128">"သင့်တီဗီသည် တီဗီချန်နယ်ထုတ်လွှင့်ရာ အရင်းအမြစ်တစ်ခုနှင့် ချိတ်ဆက်ထားကြောင်း အတည်ပြုပါ။\n\nအကယ်၍ ကောင်းကင်အန်တန်နာတိုင်ကို အသုံးပြုနေပါက ချန်နယ်အများစုကို ဖမ်းယူနိုင်ရန် ၎င်း၏အနေအထား (သို့) ဦးတည်ဘက်ကို ချိန်ညှိရန် လိုပါသည်။ ရလဒ်များအကောင်းဆုံး ဖြစ်စေရန် ၎င်းကို ပြတင်းပေါက်နားတွင် မြင့်မြင့်ထားပါ။"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"ထပ်ရှာရန်"</item>
+ <item msgid="2092797862490235174">"ပြီးသွားပြီ"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"တီဗီချန်နယ်များကို ရှာပါ"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"တီဗီချန်နယ်ချိန် ကိရိယာအက်ပ် ထည့်သွင်းမှု"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB တီဗီချန်နယ်ချိန်အက်ပ် ထည့်သွင်းမှု"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB တီဗီချိန်စက်ကို ဖြုတ်လိုက်ပါပြီ"</string>
+</resources>
diff --git a/usbtuner-res/values-nb/strings.xml b/usbtuner-res/values-nb/strings.xml
new file mode 100644
index 00000000..bce9e176
--- /dev/null
+++ b/usbtuner-res/values-nb/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"På"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Av"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vent til behandlingen er fullført"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Velg en kanalkilde"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ikke noe signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kunne ikke bytte kanal til <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Kunne ikke bytte kanal"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Skann etter TV-kanaler"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Konfigurasjon av TV-tuneren"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Konfigurasjon av USB-tuner for TV"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-tuneren for TV 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..07d68e2c
--- /dev/null
+++ b/usbtuner-res/values-ne-rNP/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"सक्रिय"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"निष्क्रिय"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"कृपया प्रक्रिया सम्पन्न हुने प्रतीक्षा गर्नुहोस्"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"आफ्नो च्यानलको स्रोत चयन गर्नुहोस्"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"कुनै सिग्‍नल छैन"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> मा ट्युन गर्न सकिएन"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ट्युन गर्न सकिएन"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ट्युनरको सफ्टवेयरलाई हालसालै अद्यावधिक गरिएको छ। कृपया च्यानलहरू पुन:स्क्यान गर्नुहोस्।"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"अडियोलाई सक्षम पार्न प्रणालीको ध्वनि सम्बन्धी सेटिङहरूमा गई सराउन्ड साउन्डलाई सक्षम पार्नुहोस्"</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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"फेरि स्क्यान गर्नुहोस्"</item>
+ <item msgid="2092797862490235174">"सम्पन्न भयो"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"TV च्यानलहरू भेट्टाउन स्क्यान गर्नुहोस्"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV ट्युनरको सेटअप"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV ट्युनरको सेटअप"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV ट्युनरलाई विच्छेद गरियो।"</string>
+</resources>
diff --git a/usbtuner-res/values-nl/strings.xml b/usbtuner-res/values-nl/strings.xml
new file mode 100644
index 00000000..b9e18682
--- /dev/null
+++ b/usbtuner-res/values-nl/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Aan"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Uit"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Wacht tot het proces is voltooid"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecteer je kanaalbron"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Geen signaal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Kan niet afstemmen op <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Kan niet afstemmen"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Opnieuw scannen"</item>
+ <item msgid="2092797862490235174">"Gereed"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Scannen naar tv-kanalen"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Tv-tuner instellen"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB-tv-tuner instellen"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-tv-tuner ontkoppeld."</string>
+</resources>
diff --git a/usbtuner-res/values-pl/strings.xml b/usbtuner-res/values-pl/strings.xml
new file mode 100644
index 00000000..0bc7e734
--- /dev/null
+++ b/usbtuner-res/values-pl/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="ut_setup_on" msgid="7755608253387551795">"Włącz"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Wyłącz"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Poczekaj na zakończenie przetwarzania"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Wybierz źródło kanału"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Brak sygnału"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Nie udało się dostroić kanału <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Nie udało się dostroić kanału"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Skanuj ponownie"</item>
+ <item msgid="2092797862490235174">"Gotowe"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Wyszukaj kanały TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Konfiguracja tunera TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Konfiguracja tunera TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Tuner TV USB odłą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..c78c92c1
--- /dev/null
+++ b/usbtuner-res/values-pt-rPT/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Ativar"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desativar"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Aguarde enquanto o processamento é terminado"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecione a origem do canal"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sem sinal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Falha ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Falha ao sintonizar"</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="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="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-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-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="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="other">%1$d canais encontrados</item>
+ <item quantity="one">%1$d canal encontrado</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="other">%1$d canais encontrados</item>
+ <item quantity="one">%1$d canal encontrado</item>
+ </plurals>
+ <plurals name="ut_result_found_description" formatted="false" msgid="4132691388395648565">
+ <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>
+ <item quantity="one">Boa! Foi encontrado %1$d canal 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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Procurar canais de TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuração do sintonizador de TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuração do sintonizador de TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Sintonizador de TV USB 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..3dfd30c0
--- /dev/null
+++ b/usbtuner-res/values-pt/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Ativar"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Desativar"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Aguarde a conclusão do processamento"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selecione a fonte do canal"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sem sinal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Falha ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Falha ao sintonizar"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Procurar canais de TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configuração do Sintonizador de TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configuração do Sintonizador de TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Sintonizador de TV USB 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..57f1ca48
--- /dev/null
+++ b/usbtuner-res/values-ro/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="ut_setup_on" msgid="7755608253387551795">"Activați"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Dezactivați"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Așteptați ca procesarea să fie finalizată"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Selectați sursa canalului"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Fără semnal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Canalul <xliff:g id="CHANNEL_NAME">%s</xliff:g> nu a putut fi selectat"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Canalul nu a putut fi selectat"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Căutați canale TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Configurarea tunerului TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Configurarea tunerului TV USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Tunerul TV USB a fost 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..7509ff19
--- /dev/null
+++ b/usbtuner-res/values-ru/strings.xml
@@ -0,0 +1,89 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Вкл."</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Выкл."</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Дождитесь окончания обработки"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Выберите источник каналов"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Нет сигнала"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Не удалось настроиться на канал \"<xliff:g id="CHANNEL_NAME">%s</xliff:g>\""</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Не удалось настроиться на канал"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Программное обеспечение тюнера было обновлено. Повторите сканирование."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Включите объемный звук в системных настройках"</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="bt_setup_new_description" msgid="256690722062003128">"Убедитесь, что телевизор подключен к источнику сигнала.\n\nЕсли вы используете телеантенну, переместите или перенаправьте ее. Рекомендуем расположить ее высоко и рядом с окном."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Убедитесь, что 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\nУбедитесь, что USB-тюнер включен в сеть и подсоединен к источнику сигнала.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Искать повторно"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Сканирование телеканалов"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Настройка ТВ-тюнера"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Настройка USB-тюнера"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-тюнер отключен."</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..a792b2c0
--- /dev/null
+++ b/usbtuner-res/values-si-rLK/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ක්‍රියාත්මක කරන්න"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ක්‍රියාවිරහිත කරන්න"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"සැකසීම අවසන් කිරීමට කරුණාකර රැඳී සිටින්න"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"ඔබගේ නාලිකා මූලාශ්‍රය තෝරන්න"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"සංඥාවක් නැත"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> වෙත සුසර කිරීම අසාර්ථක විය"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"සුසර කිරීම අසාර්ථක විය"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"සුසරක මෘදුකාංගය පසුගියදා යාවත්කාලීන කර ඇත. කරුණාකර නාලිකා නැවත ස්කෑන් කරන්න."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ශ්‍රව්‍ය සබල කිරීමට හඬ සැකසීම් තුළ අවට හඬ සබල කරන්න"</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="bt_setup_new_description" msgid="256690722062003128">"ඔබේ TV, TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"සුසරකය පේනුගත කර ඇති බව සහ 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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"නැවත ස්කෑන් කරන්න"</item>
+ <item msgid="2092797862490235174">"නිමයි"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"TV නාලිකා සඳහා ස්කෑන් කරන්න"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV සුසරක පිහිටුවීම"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV සුසරක පිහිටුවීම"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV සුසරකය විසන්ධි කරන ලදී."</string>
+</resources>
diff --git a/usbtuner-res/values-sk/strings.xml b/usbtuner-res/values-sk/strings.xml
new file mode 100644
index 00000000..67f9829e
--- /dev/null
+++ b/usbtuner-res/values-sk/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">"Televízny tuner"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Televízny tuner s rozhraním USB"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Zapnúť"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Vypnúť"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Počkajte, kým bude spracovanie dokončené"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Vyberte zdroj kanála"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Žiadny signál"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Nepodarilo sa naladiť kanál <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Ladenie zlyhalo"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Vyhľadajte televízne kanály"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Nastavenie televízneho tunera"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Nastavenie televízneho tunera s rozhraním USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"TV tuner s rozhraním USB je 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..e454e971
--- /dev/null
+++ b/usbtuner-res/values-sl/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">"Sprejemnik TV-kanalov"</string>
+ <string name="ut_app_name" msgid="8557698013780762454">"Sprejemnik TV-kanalov USB"</string>
+ <string name="ut_setup_on" msgid="7755608253387551795">"Vklop"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Izklop"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Počakajte, da se dokonča obdelava"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Izberite vir kanalov"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ni signala"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Iskanje kanala <xliff:g id="CHANNEL_NAME">%s</xliff:g> ni uspelo"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Iskanje kanala ni uspelo"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Iskanje TV-kanalov"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Nastavitev sprejemnika TV-kanalov"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Nastavitev sprejemnika TV-kanalov USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Povezava s sprejemnikom za TV-kanale USB 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..6c1fa1bf
--- /dev/null
+++ b/usbtuner-res/values-sr/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="ut_setup_on" msgid="7755608253387551795">"Укључи"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Искључи"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Сачекајте да се заврши обрада"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Изаберите извор канала"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Нема сигнала"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Укључивање канала <xliff:g id="CHANNEL_NAME">%s</xliff:g> није успело"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Укључивање канала није успело"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Софтвер тјунера је недавно ажуриран. Претражите канале поново."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Омогући звучни систем у подешавањима звука да бисте омогућили аудио"</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="bt_setup_new_description" msgid="256690722062003128">"Проверите да ли је ТВ повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда треба да прилагодите њен положај или смер да бисте имали највише канала. Ако желите најбоље резултате, поставите је високо и близу прозора."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Проверите да ли је 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\nПроверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Претражи поново"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Потражите ТВ канале"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Подешавање тјунера за ТВ"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Подешавање USB тјунера за ТВ"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB тјунер за ТВ није прикључен."</string>
+</resources>
diff --git a/usbtuner-res/values-sv/strings.xml b/usbtuner-res/values-sv/strings.xml
new file mode 100644
index 00000000..dea421bb
--- /dev/null
+++ b/usbtuner-res/values-sv/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"På"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Av"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vänta tills sökningen är klar"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Välj kanalkälla"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ingen signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Det gick inte att ställa in <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Det gick inte att ställa in kanalen"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Sök efter TV-kanaler"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Konfiguration av TV-mottagare"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Konfiguration av USB-TV-mottagare"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-TV-mottagaren 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..1ade7516
--- /dev/null
+++ b/usbtuner-res/values-sw/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Washa"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Zima"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Tafadhali subiri ili shughuli imalizike"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Chagua chanzo cha kituo"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Hakuna Mawimbi"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Imeshindwa kupata kituo cha <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Imeshindwa kupata kituo"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Tafuta tena"</item>
+ <item msgid="2092797862490235174">"Nimemaliza"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Tafuta vituo vya TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Kuweka mipangilio ya kitafutaji cha vituo vya TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Kuweka mipangilio ya Kitafutaji cha Vituo cha USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Umeondoa kichagua programu cha USB cha TV."</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..dd09420d
--- /dev/null
+++ b/usbtuner-res/values-ta-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"இயக்கு"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"முடக்கு"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"செயலாக்கம் முடியும் வரை காத்திருக்கவும்"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"சேனல் மூலத்தைத் தேர்ந்தெடுக்கவும்"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"சிக்னல் இல்லை"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>க்கு ட்யூன் செய்ய முடியவில்லை"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ட்யூன் செய்ய முடியவில்லை"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ட்யூனர் மென்பொருள் சமீபத்தில் புதுப்பிக்கப்பட்டது. சேனல்களை மீண்டும் ஸ்கேன் செய்யவும்."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ஆடியோவை இயக்க, சாதன ஒலி அமைப்புகளில் \"சரவுண்ட் சவுண்ட்\" என்பதை இயக்கவும்"</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="bt_setup_new_description" msgid="256690722062003128">"டிவி சிக்னல் மூலத்துடன் உங்கள் டிவி இணைக்கப்பட்டுள்ளதைச் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். இன்னும் சிறப்பான முடிவுகளுக்கு, அதை உயரமான இடத்தில் ஜன்னலுக்கு அருகே வைக்கவும்."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"மீண்டும் ஸ்கேன் செய்"</item>
+ <item msgid="2092797862490235174">"முடிந்தது"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"டிவி சேனல்களை ஸ்கேன் செய்"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"டிவி ட்யூனர் அமைவு"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB டிவி ட்யூனர் அமைவு"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB டிவி ட்யூனர் வெளியே எடுக்கப்பட்டது."</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..a80bd1c7
--- /dev/null
+++ b/usbtuner-res/values-te-rIN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"ఆన్ చేయి"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ఆఫ్ చేయి"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"దయచేసి ప్రాసెస్ చేయడం పూర్తయ్యే వరకు వేచి ఉండండి"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"మీ ఛానెల్ మూలాన్ని ఎంచుకోండి"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"సిగ్నల్ లేదు"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>కి ట్యూన్ చేయడంలో విఫలమైంది"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ట్యూన్ చేయడంలో విఫలమైంది"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ట్యూనర్ సాఫ్ట్‌వేర్ ఇటీవల నవీకరించబడింది. దయచేసి ఛానెల్‌లను మళ్లీ స్కాన్ చేయండి."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"ఆడియోను ప్రారంభించడానికి సిస్టమ్ శబ్ద సెట్టింగ్‌ల్లో పరిసర వ్యాప్త శబ్దాన్ని ప్రారంభించండి"</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="bt_setup_new_description" msgid="256690722062003128">"టీవీ.సిగ్నల్ సోర్స్‌కు మీ టీవీ కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి రావచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"మళ్లీ స్కాన్ చేయి"</item>
+ <item msgid="2092797862490235174">"పూర్తయింది"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"టీవీ ఛానెల్‌ల కోసం స్కాన్ చేయండి"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB టీవీ ట్యూనర్ సెటప్"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB టీవీ ట్యూనర్ డిస్‌కనెక్ట్ చేయబడింది."</string>
+</resources>
diff --git a/usbtuner-res/values-th/strings.xml b/usbtuner-res/values-th/strings.xml
new file mode 100644
index 00000000..217520df
--- /dev/null
+++ b/usbtuner-res/values-th/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"เปิด"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"ปิด"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"โปรดรอให้การดำเนินการหยุดลงสักครู่"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"เลือกแหล่งที่มาของช่อง"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"ไม่มีสัญญาณ"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"ไม่สามารถรับสัญญาณ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ไม่สามารถรับสัญญาณ"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ซอฟต์แวร์ตัวรับสัญญาณมีการอัปเดตเมื่อเร็วๆ นี้ โปรดสแกนช่องอีกครั้ง"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"เปิดใช้เสียงเซอร์ราวด์ในการตั้งค่าเสียงของระบบเพื่อเปิดใช้เสียง"</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="bt_setup_new_description" msgid="256690722062003128">"โปรดตรวจสอบว่าทีวีของคุณเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งและทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"โปรดตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ 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\nโปรดตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\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">"เลือกเสาอากาศหากมีการเชื่อมต่อเสาอากาศภายนอกกับตัวรับสัญญาณ เลือกเคเบิลหากช่องของคุณมาจากผู้ให้บริการเคเบิล หากคุณไม่แน่ใจ ระบบจะสแกนทั้ง 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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"สแกนอีกครั้ง"</item>
+ <item msgid="2092797862490235174">"เสร็จสิ้น"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"สแกนหาช่องทีวี"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"ตั้งค่าตัวรับสัญญาณทีวี"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"ตั้งค่าตัวรับสัญญาณทีวีแบบ USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"ยกเลิกการเชื่อมต่อตัวรับสัญญาณทีวีผ่าน USB แล้ว"</string>
+</resources>
diff --git a/usbtuner-res/values-tl/strings.xml b/usbtuner-res/values-tl/strings.xml
new file mode 100644
index 00000000..7a0ce826
--- /dev/null
+++ b/usbtuner-res/values-tl/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"I-on"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"I-off"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Mangyaring maghintay na matapos ang pagpoproseso"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Piliin ang pinagmulan ng iyong channel"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Walang Signal"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Hindi na-tune sa <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Hindi na-tune"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Mag-scan ng mga channel sa TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Setup ng TV Tuner"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Setup ng USB TV Tuner"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Nadiskonekta ang USB TV 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..29910f9e
--- /dev/null
+++ b/usbtuner-res/values-tr/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Açık"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Kapalı"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Lütfen işlemin tamamlanmasını bekleyin"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Kanal kaynağınızı seçin"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Sinyal Yok"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> adlı kanala ayarlanamadı"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Kanal ayarlanamadı"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Yeniden tara"</item>
+ <item msgid="2092797862490235174">"Bitti"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"TV kanallarını tarayın"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV Kanal Ayarlayıcı kurulumu"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB TV 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..cf7cc85e
--- /dev/null
+++ b/usbtuner-res/values-uk/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="ut_setup_on" msgid="7755608253387551795">"Увімкнути"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Вимкнути"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Зачекайте, доки завершиться пошук"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Виберіть джерело каналу"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Немає сигналу"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Не вдалося налаштувати канал <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Не вдалося налаштувати"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"Програмне забезпечення тюнера нещодавно оновлено. Проскануйте канали знову."</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"Увімкнути об’ємний звук у налаштуваннях системи, щоб слухати аудіо"</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="bt_setup_new_description" msgid="256690722062003128">"Переконайтеся, що ви під’єднали телевізор до джерела вхідного телевізійного сигналу.\n\nЯкщо ви користуєтесь ефірною антеною, змініть її положення,щоб знайти більше каналів. Розмістіть антену вище та біля вікна."</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"Переконайтеся, що ви підключили 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\nПереконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Шукати знову"</item>
+ <item msgid="2092797862490235174">"Готово"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Пошук телевізійних каналів"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Налаштування ТВ-тюнера"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Налаштування ТВ-тюнера USB"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"ТВ-тюнер USB від’єднано."</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..68c85d05
--- /dev/null
+++ b/usbtuner-res/values-ur-rPK/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"آن"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"آف"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"براہ کرم کارروائی ختم ہونے کا انتظار کریں"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"اپنے چینل کا ماخذ منتخب کریں"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"کوئی سگنل نہیں ہے"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> پر ٹیون ہونے میں ناکام ہوگیا"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"ٹیون کرنے میں ناکام ہو گیا"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"ٹیونر سافٹ ویئر حال ہی میں اپ ڈیٹ کیا گیا ہے۔ براہ کرم چینلز کو دوبارہ اسکین کریں۔"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"آڈیو کو فعال کرنے کیلئے سسٹم کی آواز کی ترتیبات میں محیط آواز فعال کریں"</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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"دوبارہ اسکین کریں"</item>
+ <item msgid="2092797862490235174">"ہو گیا"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"‏TV چینلز کے لیے اسکین کریں"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"‏TV ٹیونر سیٹ اپ"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"‏USB TV ٹیونر سیٹ اپ"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"‏USB TV ٹیونر غیر منسلک ہے۔"</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..9aefd57b
--- /dev/null
+++ b/usbtuner-res/values-uz-rUZ/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Yoqish"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"O‘chirib qo‘yish"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Iltimos, jarayon tugashini kuting"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Kanal manbasini tanlang"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Signal yo‘q"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"“<xliff:g id="CHANNEL_NAME">%s</xliff:g>” kanaliga sozlab bo‘lmadi"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Sozlab bo‘lmadi"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Yana qidirish"</item>
+ <item msgid="2092797862490235174">"Tayyor"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Telekanallarni qidiring"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"TV-tyunerni sozlash"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB TV-tyunerni sozlang"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB-tyuner o‘chirib 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..605234e4
--- /dev/null
+++ b/usbtuner-res/values-vi/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Bật"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Tắt"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Vui lòng đợi để hoàn tất xử lý"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Chọn nguồn kênh của bạn"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Không có tín hiệu"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Dò tới <xliff:g id="CHANNEL_NAME">%s</xliff:g> không thành công"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Dò không thành công"</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="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="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-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-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="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-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_recommendation_card_focused_title" msgid="7434151993964505386">"Quét tìm các kênh TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Thiết lập bộ dò TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Thiết lập bộ dò TV USB."</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Đã ngắt kết nối bộ điều chỉnh TV USB."</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..a4f6da22
--- /dev/null
+++ b/usbtuner-res/values-zh-rCN/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"开启"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"关闭"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"请耐心等待处理完毕"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"选择您的频道来源"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"无信号"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"无法调到<xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"无法调到相应频道"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"调谐器软件近期已更新。请重新扫描频道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"在系统声音设置中启用环绕声即可启用音频"</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="bt_setup_new_description" msgid="256690722062003128">"请检查您的电视是否已连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"请检查 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\n请检查 USB 调谐器是否已插好并连接到电视信号源。\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新扫描"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"扫描电视频道"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"电视调谐器设置"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB 电视调谐器设置"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB 电视调谐器已断开连接。"</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..6d40401e
--- /dev/null
+++ b/usbtuner-res/values-zh-rHK/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"開啟"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"關閉"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"請等待系統完成處理程序"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"請選擇您的頻道來源"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"無訊號"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"無法調校至<xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"無法調校頻道"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"調諧器軟件最近已更新。請重新掃瞄頻道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"在系統音效設定中啟用環迴立體聲功能即可啟用音效"</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="bt_setup_new_description" msgid="256690722062003128">"請確定電視已連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收最多頻道。您亦可將天線放在較高位置並靠近窗戶,以獲得最佳效果。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"請確定 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\n請確定 USB 調諧器已接駁並連接至電視訊號來源。\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新掃瞄"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"掃瞄電視頻道"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"電視調諧器設定"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB 電視調諧器設定"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"已解除 USB 電視調諧器的連接。"</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..802d8b73
--- /dev/null
+++ b/usbtuner-res/values-zh-rTW/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"開啟"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"關閉"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"請等待處理程序完成"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"選取你的頻道來源"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"無訊號"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"無法轉到「<xliff:g id="CHANNEL_NAME">%s</xliff:g>」"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"無法轉台"</string>
+ <string name="ut_rescan_needed" msgid="2273655435759849436">"調諧器軟體最近已更新。請重新掃描頻道。"</string>
+ <string name="ut_surround_sound_disabled" msgid="6465044734143962900">"前往系統音效設定開啟環繞音效即可啟用音訊"</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="bt_setup_new_description" msgid="256690722062003128">"請確認你的電視已連接到電視訊號來源。\n\n如果你使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
+ <string name="ut_setup_new_description" msgid="2610122936163002137">"請確認 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\n請確認 USB 調諧器已插入並連接到電視訊號來源。\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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"重新掃描"</item>
+ <item msgid="2092797862490235174">"完成"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"掃描電視頻道"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"電視調諧器設定"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"USB 電視調諧器設定"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"USB 電視調諧器已中斷連結。"</string>
+</resources>
diff --git a/usbtuner-res/values-zu/strings.xml b/usbtuner-res/values-zu/strings.xml
new file mode 100644
index 00000000..905e9a16
--- /dev/null
+++ b/usbtuner-res/values-zu/strings.xml
@@ -0,0 +1,87 @@
+<?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="ut_setup_on" msgid="7755608253387551795">"Vuliwe"</string>
+ <string name="ut_setup_off" msgid="1333878787059290524">"Valiwe"</string>
+ <string name="ut_setup_cancel" msgid="5318292052302751909">"Sicela ulinde ukuze uqede ukucubungula"</string>
+ <string name="ut_select_channel_map" msgid="4831940000362338865">"Khetha umthombo wesiteshi sakho"</string>
+ <string name="ut_no_signal" msgid="7390099185275997984">"Ayikho isignali"</string>
+ <string name="ut_fail_to_tune" msgid="2964582177222053143">"Yehlulekile ukushunela ku-<xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
+ <string name="ut_fail_to_tune_to_unknown_channel" msgid="7078953579048783762">"Yehlulekile ukushuna"</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="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="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-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-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="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-array name="ut_result_not_found_choices">
+ <item msgid="5436884968471542030">"Skena futhi"</item>
+ <item msgid="2092797862490235174">"Kwenziwe"</item>
+ </string-array>
+ <string name="ut_setup_recommendation_card_focused_title" msgid="7434151993964505386">"Skenela iziteshi ze-TV"</string>
+ <string name="bt_setup_recommendation_card_title" msgid="1026906771141769829">"Ukusethwa kweshuna ye-TV"</string>
+ <string name="ut_setup_recommendation_card_title" msgid="1093869817128338226">"Ukusetha kweshuna ye-USB TV"</string>
+ <string name="msg_usb_device_detached" msgid="5123930566630230724">"Isishuni se-USB TV sinqanyuliwe."</string>
+</resources>
diff --git a/usbtuner/res/values/attrs.xml b/usbtuner-res/values/attrs.xml
index 4249ed2f..4249ed2f 100644
--- a/usbtuner/res/values/attrs.xml
+++ b/usbtuner-res/values/attrs.xml
diff --git a/usbtuner/res/values/colors.xml b/usbtuner-res/values/colors.xml
index bbcc431f..bbcc431f 100644
--- a/usbtuner/res/values/colors.xml
+++ b/usbtuner-res/values/colors.xml
diff --git a/usbtuner/res/values/dimens.xml b/usbtuner-res/values/dimens.xml
index 0a09b062..0a09b062 100644
--- a/usbtuner/res/values/dimens.xml
+++ b/usbtuner-res/values/dimens.xml
diff --git a/usbtuner/res/values/integers.xml b/usbtuner-res/values/integers.xml
index 21b438e9..21b438e9 100644
--- a/usbtuner/res/values/integers.xml
+++ b/usbtuner-res/values/integers.xml
diff --git a/usbtuner/res/values/strings.xml b/usbtuner-res/values/strings.xml
index 34626bcc..e3a8586d 100644
--- a/usbtuner/res/values/strings.xml
+++ b/usbtuner-res/values/strings.xml
@@ -17,7 +17,10 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<!-- Name of this application. It appears in TV app UI, as one of available TV inputs. -->
- <string name="ut_app_name">USB Tuner TV Input</string>
+ <string name="bt_app_name">TV Tuner</string>
+ <!-- Name of this application when one uses USB tuner. It appears in TV app UI, as one of
+ available TV inputs. -->
+ <string name="ut_app_name">USB TV Tuner</string>
<!-- Title for an action which turns a feature on [CHAR LIMIT=30] -->
<string name="ut_setup_on">On</string>
<!-- Title for an action which turns a feature off [CHAR LIMIT=30] -->
@@ -28,7 +31,8 @@
<!-- Message that asks a user to select the type of signal to be used for input among
the choices like terrestrial, cable, or satellite -->
<string name="ut_select_channel_map">Select your channel source</string>
- <!-- Message that indicates TV input signal is lost due to physical disconnection or bad reception -->
+ <!-- Message that indicates TV input signal is lost due to physical disconnection or bad
+ reception -->
<string name="ut_no_signal">No Signal</string>
<!-- Message that says TV failed to change to a channel (or tune) -->
<string name="ut_fail_to_tune">Failed to tune to <xliff:g id="channel_name">%s</xliff:g></string>
@@ -36,15 +40,22 @@
<string name="ut_fail_to_tune_to_unknown_channel">Failed to tune</string>
<!-- Message shown when the scanned channels became invalid due to incompatible changes
found across application versions, hence a user is required to rescan the channels -->
- <string name="ut_rescan_needed">USB tuner software has been recently updated. Please re-scan the
- channels.</string>
- <!-- Message that says audio of the current channel is not available due to TV device
- lacking the support of the feature AC3 audio passthrough -->
- <string name="ut_ac3_passthrough_unavailable">AC3 audio not available</string>
+ <string name="ut_rescan_needed">Tuner software has been recently updated. Please re-scan the
+ channels.</string>
+ <!-- Message that says audio of the current channel is not available due to surround sound
+ of TV device disabled -->
+ <string name="ut_surround_sound_disabled">Enable surround sound in system sound settings to enable audio</string>
<!-- Usb Tuner setup common UI breadcrumb -->
<string name="ut_setup_breadcrumb">Channel tuner setup</string>
+ <!-- Title for TV Tuner main setup menu when no channel exists -->
+ <string name="bt_setup_new_title">TV Tuner setup</string>
<!-- Title for USB tuner main setup menu when no channel exists -->
- <string name="ut_setup_new_title">USB channel tunner setup</string>
+ <string name="ut_setup_new_title">USB channel tuner setup</string>
+ <!-- Description for TV tuner main setup menu when no channel exists -->
+ <string name="bt_setup_new_description">Verify your TV is 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>
<!-- Description for USB tuner main setup menu when no channel exists -->
<string name="ut_setup_new_description">Verify 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
@@ -57,8 +68,14 @@
<!-- Exit setup -->
<item>Not now</item>
</string-array>
- <!-- Title for USB tuner main setup menu when channel exists already -->
- <string name="ut_setup_again_title">Rerun channel setup?</string>
+ <!-- Title for tuner main setup menu when channel exists already -->
+ <string name="bt_setup_again_title">Rerun channel setup?</string>
+ <!-- Description for TV tuner main setup menu when channel exists already -->
+ <string name="bt_setup_again_description">This will remove the channels found from the TV
+ tuner and scan for new channels again.\n\nVerify your TV is 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>
<!-- Description for USB tuner main setup menu when channel exists already -->
<string name="ut_setup_again_description">This will remove the channels found from the USB
tuner and scan for new channels again.\n\nVerify the USB tuner is plugged in and connected
@@ -88,10 +105,15 @@
<item>Not sure</item>
<item translatable="false">Development only</item>
</string-array>
- <!-- Title for channel scanning menu -->
+ <!-- Title for channel scanning menu. Use this title with built-in tuners -->
+ <string name="bt_channel_scan">TV tuner setup</string>
+ <!-- Title for channel scanning menu. Use this title with USB tuners -->
<string name="ut_channel_scan">USB channel tuner setup</string>
<!-- Message that says channel is not yet scanned during channel scanning process -->
<string name="ut_channel_scan_time">This may take several minutes</string>
+ <!-- Message that says Tuner is not available -->
+ <string name="ut_channel_scan_tuner_unavailable">Tuner is temporarily not available or already
+ used by recording.</string>
<!-- Message that says channels are found during channel scanning process -->
<plurals name="ut_channel_scan_message">
<item quantity="one">%1$d channel found</item>
@@ -119,6 +141,11 @@
<!-- Title for channel scanning result menu when no channel was found -->
<string name="ut_result_not_found_title">No Channels found</string>
<!-- Description for channel scanning result menu when no channel was found -->
+ <string name="bt_result_not_found_description">The scan did not find any channels. Verify
+ your TV is 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>
+ <!-- Description for channel scanning result menu when no channel was found -->
<string name="ut_result_not_found_description">The scan did not find any channels. Verify the
USB tuner is plugged in 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
@@ -135,6 +162,12 @@
focused. -->
<string name="ut_setup_recommendation_card_focused_title">Scan for TV channels</string>
<!-- Content text and info of the recommendation card to launch the setup application of
+ built-in tuner TV input for scanning channels. -->
+ <string name="bt_setup_recommendation_card_title">TV Tuner setup</string>
+ <!-- Content text and info of the recommendation card to launch the setup application of
USB tuner TV input for scanning channels. -->
- <string name="ut_setup_recommendation_card_title">USB channel tuner setup</string>
+ <string name="ut_setup_recommendation_card_title">USB TV Tuner setup</string>
+
+ <!-- Message when usb tuner device is unplugged. [CHAR LIMIT=NONE] -->
+ <string name="msg_usb_device_detached">USB TV tuner disconnected.</string>
</resources>
diff --git a/usbtuner/res/values/styles.xml b/usbtuner-res/values/styles.xml
index c79319ba..c79319ba 100644
--- a/usbtuner/res/values/styles.xml
+++ b/usbtuner-res/values/styles.xml
diff --git a/usbtuner/res/xml/ut_tvinputservice.xml b/usbtuner-res/xml/ut_tvinputservice.xml
index 54f56878..29c234e0 100644
--- a/usbtuner/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.usbtuner.setup.TunerSetupActivity"
+ android:setupActivity="com.google.android.tv.tuner.setup.TunerSetupActivity"
android:canRecord="true"
android:tunerCount="1" />
diff --git a/usbtuner/Android.mk b/usbtuner/Android.mk
deleted file mode 100644
index 72a0204c..00000000
--- a/usbtuner/Android.mk
+++ /dev/null
@@ -1,110 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# --------------------------------------------------------------
-# Build the apk. This generates an standalone apk for USB tuner
-# input service.
-include $(CLEAR_VARS)
-
-LOCAL_PACKAGE_NAME := UsbTunerTvInput
-LOCAL_MODULE_TAGS := optional
-# It's not required but keep it for a compatibility with the previous version.
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_SDK_VERSION := system_current
-LOCAL_MIN_SDK_VERSION := 23 # M
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
- lib-exoplayer \
- usbtuner-tvinput
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res \
- $(LOCAL_PATH)/../common/res \
- $(TOP)/prebuilts/sdk/current/support/v7/recyclerview/res \
- $(TOP)/prebuilts/sdk/current/support/v17/leanback/res
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages android.support.v7.recyclerview \
- --extra-packages android.support.v17.leanback \
- --extra-packages com.android.tv.common
-
-LOCAL_JNI_SHARED_LIBRARIES := \
- libtunertvinput_jni
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-include $(BUILD_PACKAGE)
-
-# --------------------------------------------------------------
-# The final static library that apps can link against.
-# The R class is automatically excluded from the generated library.
-# Applications that use this library must specify LOCAL_RESOURCE_DIR
-# in their makefiles to include the resources in their package.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := usbtuner-tvinput
-LOCAL_MODULE_TAGS := optional
-LOCAL_SRC_FILES := \
- $(call all-java-files-under, src) \
- $(call all-proto-files-under, proto)
-LOCAL_SDK_VERSION := system_current
-LOCAL_STATIC_JAVA_LIBRARIES := \
- android-support-v4 \
- android-support-v7-recyclerview \
- android-support-v17-leanback \
- icu4j-usbtuner \
- lib-exoplayer \
- libprotobuf-java-nano \
- tv-common
-
-
-LOCAL_PROGUARD_ENABLED := disabled
-
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res \
- $(LOCAL_PATH)/../common/res \
- $(TOP)/prebuilts/sdk/current/support/v7/recyclerview/res \
- $(TOP)/prebuilts/sdk/current/support/v17/leanback/res
-
-LOCAL_AAPT_FLAGS := --auto-add-overlay \
- --extra-packages android.support.v17.leanback \
- --extra-packages com.android.tv.common \
-
-LOCAL_PROTOC_OPTIMIZE_TYPE := nano
-LOCAL_PROTOC_FLAGS := --proto_path=$(LOCAL_PATH)/proto/
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-# --------------------------------------------------------------
-# 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
-#############################################################
-
-# --------------------------------------------------------------
-# ExoPlayer library version 1.5.6
-# https://github.com/google/ExoPlayer/archive/r1.5.6.zip
-# TODO: Add ExoPlayer source code to external/ android repository.
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_PREBUILT_STATIC_JAVA_LIBRARIES := \
- lib-exoplayer:libs/exoplayer_1.5.6.jar
-
-include $(BUILD_MULTI_PREBUILT)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/usbtuner/AndroidManifest.xml b/usbtuner/AndroidManifest.xml
deleted file mode 100644
index 200334e8..00000000
--- a/usbtuner/AndroidManifest.xml
+++ /dev/null
@@ -1,55 +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.usbtuner"
- android:versionCode="0"
- android:versionName="0.1" >
-
- <uses-sdk
- android:minSdkVersion="23"
- android:targetSdkVersion="23" />
- <uses-permission android:name="android.permission.DVB_DEVICE" />
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
- <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
- <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
- <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
- <uses-feature android:name="android.hardware.usb.host" />
-
- <application
- android:allowBackup="true">
- <activity
- android:name=".setup.TunerSetupActivity"
- android:label="@string/ut_app_name"
- android:theme="@style/Theme.Setup.GuidedStep"
- android:screenOrientation="landscape">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
- <service
- android:name="com.android.usbtuner.tvinput.UsbTunerTvInputService"
- android:permission="android.permission.BIND_TV_INPUT" >
- <intent-filter>
- <action android:name="android.media.tv.TvInputService" />
- </intent-filter>
- <meta-data android:name="android.media.tv.input"
- android:resource="@xml/ut_tvinputservice" />
- </service>
- </application>
-</manifest>
diff --git a/usbtuner/jni/gen_jni.sh b/usbtuner/jni/gen_jni.sh
deleted file mode 100755
index e81f9cb8..00000000
--- a/usbtuner/jni/gen_jni.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-javah -jni -classpath ../../bin/classes:../../../../../../prebuilts/sdk/current/android.jar -o tunertvinput_jni.h com.android.usbtuner.TunerHal
diff --git a/usbtuner/jni/tunertvinput_jni.h b/usbtuner/jni/tunertvinput_jni.h
deleted file mode 100644
index 5878740e..00000000
--- a/usbtuner/jni/tunertvinput_jni.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/* DO NOT EDIT THIS FILE - it is machine generated */
-#include <jni.h>
-/* Header for class com_android_usbtuner_TunerHal */
-
-#ifndef _Included_com_android_usbtuner_TunerHal
-#define _Included_com_android_usbtuner_TunerHal
-#ifdef __cplusplus
-extern "C" {
-#endif
-#undef com_android_usbtuner_TunerHal_DEBUG
-#define com_android_usbtuner_TunerHal_DEBUG 0L
-#undef com_android_usbtuner_TunerHal_FILTER_TYPE_OTHER
-#define com_android_usbtuner_TunerHal_FILTER_TYPE_OTHER 0L
-#undef com_android_usbtuner_TunerHal_FILTER_TYPE_AUDIO
-#define com_android_usbtuner_TunerHal_FILTER_TYPE_AUDIO 1L
-#undef com_android_usbtuner_TunerHal_FILTER_TYPE_VIDEO
-#define com_android_usbtuner_TunerHal_FILTER_TYPE_VIDEO 2L
-#undef com_android_usbtuner_TunerHal_FILTER_TYPE_PCR
-#define com_android_usbtuner_TunerHal_FILTER_TYPE_PCR 3L
-#undef com_android_usbtuner_TunerHal_PID_PAT
-#define com_android_usbtuner_TunerHal_PID_PAT 0L
-#undef com_android_usbtuner_TunerHal_PID_ATSC_SI_BASE
-#define com_android_usbtuner_TunerHal_PID_ATSC_SI_BASE 8187L
-#undef com_android_usbtuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS
-#define com_android_usbtuner_TunerHal_DEFAULT_VSB_TUNE_TIMEOUT_MS 2000L
-#undef com_android_usbtuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS
-#define com_android_usbtuner_TunerHal_DEFAULT_QAM_TUNE_TIMEOUT_MS 4000L
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeFinalize
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeFinalize
- (JNIEnv *, jobject, jlong);
-
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeTune
- * Signature: (JILjava/lang/String;I)Z
- */
-JNIEXPORT jboolean JNICALL Java_com_android_usbtuner_TunerHal_nativeTune
- (JNIEnv *, jobject, jlong, jint, jstring, jint);
-
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeAddPidFilter
- * Signature: (JII)V
- */
-JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeAddPidFilter
- (JNIEnv *, jobject, jlong, jint, jint);
-
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeCloseAllPidFilters
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeCloseAllPidFilters
- (JNIEnv *, jobject, jlong);
-
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeStopTune
- * Signature: (J)V
- */
-JNIEXPORT void JNICALL Java_com_android_usbtuner_TunerHal_nativeStopTune
- (JNIEnv *, jobject, jlong);
-
-/*
- * Class: com_android_usbtuner_TunerHal
- * Method: nativeWriteInBuffer
- * Signature: (J[BI)I
- */
-JNIEXPORT jint JNICALL Java_com_android_usbtuner_TunerHal_nativeWriteInBuffer
- (JNIEnv *, jobject, jlong, jbyteArray, jint);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
-/* Header for class com_android_usbtuner_TunerHal_FilterType */
-
-#ifndef _Included_com_android_usbtuner_TunerHal_FilterType
-#define _Included_com_android_usbtuner_TunerHal_FilterType
-#ifdef __cplusplus
-extern "C" {
-#endif
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/usbtuner/libs/exoplayer_1.5.6.jar b/usbtuner/libs/exoplayer_1.5.6.jar
deleted file mode 100644
index a0b311c9..00000000
--- a/usbtuner/libs/exoplayer_1.5.6.jar
+++ /dev/null
Binary files differ
diff --git a/usbtuner/res/drawable-xhdpi/ic_setup_antenna.png b/usbtuner/res/drawable-xhdpi/ic_setup_antenna.png
deleted file mode 100644
index 1f9e0673..00000000
--- a/usbtuner/res/drawable-xhdpi/ic_setup_antenna.png
+++ /dev/null
Binary files differ
diff --git a/usbtuner/res/drawable-xhdpi/recommendation_antenna.png b/usbtuner/res/drawable-xhdpi/recommendation_antenna.png
deleted file mode 100644
index 31516b69..00000000
--- a/usbtuner/res/drawable-xhdpi/recommendation_antenna.png
+++ /dev/null
Binary files differ
diff --git a/usbtuner/res/drawable-xhdpi/usb_antenna.png b/usbtuner/res/drawable-xhdpi/usb_antenna.png
deleted file mode 100644
index ba7bde19..00000000
--- a/usbtuner/res/drawable-xhdpi/usb_antenna.png
+++ /dev/null
Binary files differ
diff --git a/usbtuner/res/raw/ut_us_atsc_center_frequencies_8vsb b/usbtuner/res/raw/ut_us_atsc_center_frequencies_8vsb
deleted file mode 100644
index f4983d3e..00000000
--- a/usbtuner/res/raw/ut_us_atsc_center_frequencies_8vsb
+++ /dev/null
@@ -1,71 +0,0 @@
-# US ATSC center frequencies
-# TODO: Verify this.
-
-A 57028615 8VSB
-A 63028615 8VSB
-A 69028615 8VSB
-A 79028615 8VSB
-A 85028615 8VSB
-A 177028615 8VSB
-A 183028615 8VSB
-A 189028615 8VSB
-A 195028615 8VSB
-A 201028615 8VSB
-A 207028615 8VSB
-A 213028615 8VSB
-A 473028615 8VSB
-A 479028615 8VSB
-A 485028615 8VSB
-A 491028615 8VSB
-A 497028615 8VSB
-A 503028615 8VSB
-A 509028615 8VSB
-A 515028615 8VSB
-A 521028615 8VSB
-A 527028615 8VSB
-A 533028615 8VSB
-A 539028615 8VSB
-A 545028615 8VSB
-A 551028615 8VSB
-A 557028615 8VSB
-A 563028615 8VSB
-A 569028615 8VSB
-A 575028615 8VSB
-A 581028615 8VSB
-A 587028615 8VSB
-A 593028615 8VSB
-A 599028615 8VSB
-A 605028615 8VSB
-A 611028615 8VSB
-A 617028615 8VSB
-A 623028615 8VSB
-A 629028615 8VSB
-A 635028615 8VSB
-A 641028615 8VSB
-A 647028615 8VSB
-A 653028615 8VSB
-A 659028615 8VSB
-A 665028615 8VSB
-A 671028615 8VSB
-A 677028615 8VSB
-A 683028615 8VSB
-A 689028615 8VSB
-A 695028615 8VSB
-A 701028615 8VSB
-A 707028615 8VSB
-A 713028615 8VSB
-A 719028615 8VSB
-A 725028615 8VSB
-A 731028615 8VSB
-A 737028615 8VSB
-A 743028615 8VSB
-A 749028615 8VSB
-A 755028615 8VSB
-A 761028615 8VSB
-A 767028615 8VSB
-A 773028615 8VSB
-A 779028615 8VSB
-A 785028615 8VSB
-A 791028615 8VSB
-A 797028615 8VSB
-A 803028615 8VSB
diff --git a/usbtuner/res/values-af/strings.xml b/usbtuner/res/values-af/strings.xml
deleted file mode 100644
index 67571ec2..00000000
--- a/usbtuner/res/values-af/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-ontvanger-TV-invoer"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aan"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Af"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Wag asseblief dat verwerking voltooi word"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Kies jou kanaalbron"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Geen sein nie"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kon nie op <xliff:g id="CHANNEL_NAME">%s</xliff:g> inskakel nie"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Kon nie instel nie"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB-ontvangersagteware is onlangs opgedateer. Herskandeer die kanale asseblief."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-oudio is nie beskikbaar nie"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Opstelling van kanaalinstemmer"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Opstelling van USB-kanaalinstemmer"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verifieer dat die USB-instemmer ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n deur-die-lug-antenna gebruik, sal jy dalk sy posisie of rigting moet verstel om die meeste kanale te ontvang. Plaas dit hoog en naby \'n venster om die beste resultate te behaal."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Gaan voort"</item>
- <item msgid="7745727658174773453">"Nie nou nie"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Doen kanaalopstelling weer?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Dit sal die kanale wat gevind is, uit die USB-instemmer verwyder en weer vir nuwe kanale skandeer.\n\nVerifieer dat die USB-instemmer ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n deur-die-lug-antenna gebruik, sal jy dalk sy posisie of rigting moet verstel om die meeste kanale te ontvang. Plaas dit hoog en naby \'n venster om die beste resultate te behaal."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Gaan voort"</item>
- <item msgid="4432431398374089710">"Kanselleer"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Kies die soort verbinding"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Kies Antenna as \'n eksterne antenna aan die instemmer 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="1633072563555330217">"Antenna"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Nie seker nie"</item>
- <item msgid="3613410733017077040">"Net ontwikkeling"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Opstelling van USB-kanaalinstemmer"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Dit kan \'n paar minute neem"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"STOP KANAALSKANDERING"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Klaar"</item>
- <item msgid="496688122303154468">"Skandeer weer"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Geen kanale gevind nie"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Die skandering het geen kanale gevind nie. Verifieer dat die USB-instemmer ingeprop en aan \'n TV-seinbron gekoppel is.\n\nAs jy \'n deur-die-lug-antenna gebruik, verstel sy posisie of rigting. Plaas dit hoog en naby \'n venster om die beste resultate te behaal en skandeer weer."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Skandeer weer"</item>
- <item msgid="6784975565864102291">"Klaar"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Skandeer vir TV-kanale"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Opstelling van USB-kanaalinstemmer"</string>
-</resources>
diff --git a/usbtuner/res/values-am/strings.xml b/usbtuner/res/values-am/strings.xml
deleted file mode 100644
index cfcfed06..00000000
--- a/usbtuner/res/values-am/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"የዩኤስቢ ማስተካከያ የቴሌቪዥን ግብዓት"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"በርቷል"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ጠፍቷል"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"ማስኬድን ለማጠናቀቅ እባክዎ ይጠብቁ"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"የሰርጥ ምንጭዎን ይምረጡ"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"ምንም ሲግናል የለም"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"ወደ <xliff:g id="CHANNEL_NAME">%s</xliff:g> ማስተካከል አልተሳካም"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"መቃኘት አልተሳካም"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"የዩኤስቢ ማስተካከያ ሶፍትዌር በቅርብ ጊዜ ዘምኗል። እባክዎ ሰርጦቹን እንደገና ይቃኙዋቸው።"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ኦዲዮ አይገኝም"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"የጣቢያ ማስተካከያ ማዋቀር"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"የዩኤስቢ ጣቢያ ማስተካከያ ማዋቀር"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"የዩኤስቢ ማስተካከያ መሰካቱን እና ከቴሌቪዥን ምልክት ምንጭ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"ቀጥል"</item>
- <item msgid="7745727658174773453">"አሁን አይደለም"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"የጣቢያ ቅንብር እንደገና እንዲሄድ ይደረግ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"ይሄ ከዩኤስቢ ማስተካከያ የተገኙ ጣቢያዎችን አስወግዶ አዲስ ጣቢያዎችን እንደገና ይቃኛል።\n\nየዩኤስቢ ማስተካከያው መሰካቱን እና ከቴሌቪዥን ምልክት ምንጩ መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት።"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"ቀጥል"</item>
- <item msgid="4432431398374089710">"ተወው"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"የግንኙነት ዓይነትን ይምረጡ"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ከማስተካከያው ጋር የተገናኘ ውጫዊ አንቴና ካለ አንቴናን ይምረጡ። የእርስዎ ጣቢያዎች ከገመድ አገልግሎት አቅራቢ የሚመጡ ከሆነ ገመድን ይምረጡ። እርግጠኛ ካልሆኑ ሁለቱም ዓይነቶች ይቃኛሉ፣ ሆኖም ግን ይሄ ረዘም ያለ ጊዜ ሊወስድ ይችላል።"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"አንቴና"</item>
- <item msgid="2445879869338877559">"ገመድ"</item>
- <item msgid="597328838068074806">"እርግጠኛ አይደሉም"</item>
- <item msgid="3613410733017077040">"ግንባታ ብቻ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"የዩኤስቢ ሰርጥ ማስተካከያ ቅንብር"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ይሄ በርካታ ደቂቃዎችን ሊወስድ ይችላል"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d ሰርጦች ተገኝቷል</item>
- <item quantity="other">%1$d ሰርጦች ተገኝቷል</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"የጣቢያ ቅኝትን አቁም"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$d ሰርጦች ተገኝተዋል</item>
- <item quantity="other">%1$d ሰርጦች ተገኝተዋል</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">ግሩም! በሰርጥ ቅኝት ጊዜ %1$d ሰርጦች ተገኝተዋል። ትክክል የማይመስል ከሆነ የአንቴናውን አቀማመጥ አስተካክለው እንደገና ለመቃኘት ይሞክሩ።</item>
- <item quantity="other">ግሩም! በሰርጥ ቅኝት ጊዜ %1$d ሰርጦች ተገኝተዋል። ትክክል የማይመስል ከሆነ የአንቴናውን አቀማመጥ አስተካክለው እንደገና ለመቃኘት ይሞክሩ።</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"ተከናውኗል"</item>
- <item msgid="496688122303154468">"እንደገና ቃኝ"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ምንም አይነት ጣቢያዎች አልተገኙም።"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ቅኝቱ ምንም ጣቢያዎችን አላገኘም። የዩኤስቢ ማስተካከያው መሰካቱን እና ከቴሌቪዥን ምልክት ምንጩ ጋር መገናኘቱን ያረጋግጡ።\n\nየአየር ላይ አንቴና የሚጠቀሙ ከሆነ አቀማመጡን ወይም አቅጣጫውን ያስተካክሉ። ለተሻሉ ውጤቶች ከፍ አድርገው ከመስኮት አጠገብ ያስቀምጡት እና እንደገና ይቃኙ።"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"እንደገና ቃኝ"</item>
- <item msgid="6784975565864102291">"ተከናውኗል"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"የቲቪ ሰርጦችን ቃኝ"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"የዩኤስቢ ሰርጥ ማስተካከያ ቅንብር"</string>
-</resources>
diff --git a/usbtuner/res/values-ar/strings.xml b/usbtuner/res/values-ar/strings.xml
deleted file mode 100644
index 7210ec13..00000000
--- a/usbtuner/res/values-ar/strings.xml
+++ /dev/null
@@ -1,90 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"‏إدخال موالف تلفزيون USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"تشغيل"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"إيقاف"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"الرجاء الانتظار لحين انتهاء المعالجة"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"حدد القناة المصدر"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"لا توجد إشارة"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"أخفق الضبط على <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"أخفق الضبط"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"‏تم تحديث برنامج موالف USB مؤخرًا. الرجاء إعادة البحث عن القنوات."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"‏لا يتوفر صوت AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"إعداد موالف القنوات"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"‏إعداد موالف القنوات من النوع USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"‏تحقق من توصيل الموالف من نوع USB بمصدر إشارة التلفزيون.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فربما يلزمك تعديل موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"متابعة"</item>
- <item msgid="7745727658174773453">"ليس الآن"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"هل تريد إعادة تشغيل إعداد القنوات؟"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"‏سيؤدي هذا إلى إزالة القنوات التي تم العثور عليها من الموالف من النوع USB والبحث ثانية عن قنوات جديدة.\n\nتحقق من توصيل الموالف من نوع USB بمصدر إشارة التلفزيون.\n\nإذا كنت تستخدم هوائي للتحديث عبر الهواء، فربما يلزمك تعديل موضعه أو اتجاهه لاستقبال معظم القنوات، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"متابعة"</item>
- <item msgid="4432431398374089710">"إلغاء"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"تحديد نوع الاتصال"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"اختر \"الهوائي\" في حال توصيل هوائي خارجي بالموالف، واختر \"الكابل\" في حال كان مصدر القنوات هو مقدم خدمة عبر الكابل، أما إذا لم تكن متأكدًا، فسيتم البحث عن القنوات في النوعين غير أن هذا قد يستغرق وقتًا أطول."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"الهوائي"</item>
- <item msgid="2445879869338877559">"الكابل"</item>
- <item msgid="597328838068074806">"لست متأكدًا"</item>
- <item msgid="3613410733017077040">"للتطوير فقط"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"‏إعداد موالف قنوات USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"قد يستغرق هذا عدة دقائق"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"إيقاف البحث عن القنوات"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"تم"</item>
- <item msgid="496688122303154468">"بحث مرة أخرى"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"لم يتم العثور على قنوات"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"‏لم يتم العثور على أية قنوات أثناء البحث، تحقق من توصيل الموالف من نوع USB بمصدر إشارة التلفزيون.\n\nإذا كنت تستخدم هوائيًا للتحديث عبر الهواء، فعدّل موضعه أو اتجاهه، وللحصول على أفضل النتائج، ضعه عاليًا بالقرب من النافذة ثم أعد البحث."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"بحث مرة أخرى"</item>
- <item msgid="6784975565864102291">"تم"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"البحث عن قنوات تلفزيونية"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"‏إعداد موالف قنوات USB"</string>
-</resources>
diff --git a/usbtuner/res/values-az-rAZ/strings.xml b/usbtuner/res/values-az-rAZ/strings.xml
deleted file mode 100644
index 30da5e32..00000000
--- a/usbtuner/res/values-az-rAZ/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Sazlayıcı TV Daxiletməsi"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aktiv"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Deaktiv"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Lütfən, prosesi başa çatdırmaq üçün gözləyin"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Kanal mənbəyinizi seçin"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Siqnal Yoxdur"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> kanalına sazlamaq mümkün olmadı"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Sazlamaq uğursuz oldu"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB sazlayıcı proqram təminatı yenicə güncəllənib. Kanalları yenidən skan edin."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audiosu mövcud deyil"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanal kökləyici quraşdırması"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB kanal kökləyici quraşdırmas"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Davam edin"</item>
- <item msgid="7745727658174773453">"İndi yox"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kanal quraşdırması yenidən işə salınsın?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Davam edin"</item>
- <item msgid="4432431398374089710">"Ləğv edin"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Bağlantı növünü seçin"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Ə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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Əmin deyiləm"</item>
- <item msgid="3613410733017077040">"Yalnız inkişaf"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB Kanal kökləyici quraşdırması"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Bu bir neçə dəqiqə çəkə bilər"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"KANAL SKANINI DAYANDIRIN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Hazırdır"</item>
- <item msgid="496688122303154468">"Yenidən skan edin"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Kanal tapılmadı"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Yenidən skan edin"</item>
- <item msgid="6784975565864102291">"Hazırdır"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV kanalları üçün Skan"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB Kanal kökləyici quraşdırması"</string>
-</resources>
diff --git a/usbtuner/res/values-bg/strings.xml b/usbtuner/res/values-bg/strings.xml
deleted file mode 100644
index 9f7393a8..00000000
--- a/usbtuner/res/values-bg/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Телевизия през USB тунер"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Включване"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Изключване"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Моля, изчакайте обработването да завърши"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Избиране на източника на канала ви"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Няма сигнал"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Настройването към „<xliff:g id="CHANNEL_NAME">%s</xliff:g>“ не бе успешно"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Промяната не бе успешна"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Софтуерът на USB тунера е актуализиран наскоро. Моля, сканирайте отново каналите."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Не е налице аудио във формат AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Настройване на тунера за канали"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Настройване на USB тунера за канали"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Потвърдете, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите най-много канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Напред"</item>
- <item msgid="7745727658174773453">"Не сега"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Да се стартира ли отново настройването на каналите?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Ще се премахнат каналите, намерени от USB тунера, и ще трябва да сканирате повторно за нови.\n\nПотвърдете, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, може да се наложи да коригирате разположението или посоката й, за да получите най-много канали. За най-добри резултати я поставете високо и близо до прозорец."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Напред"</item>
- <item msgid="4432431398374089710">"Отказ"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Изберете типа на връзката"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Изберете „Антена“, ако с тунера е свързана външна антена. Посочете „Кабел“, ако източникът на каналите ви е доставчик на кабелна услуга. В случай че не сте сигурни, ще се сканира и за двата типа, но това може да отнеме по-дълго време."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антена"</item>
- <item msgid="2445879869338877559">"Кабел"</item>
- <item msgid="597328838068074806">"Не знам със сигурност"</item>
- <item msgid="3613410733017077040">"Само програмиране"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Настройване на USB тунера за канали"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Това може да отнеме няколко минути"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">Намерени са %1$d канала</item>
- <item quantity="one">Намерен е %1$d канал</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"СПИРАНЕ НА СКАНИРАНЕТО ЗА КАНАЛИ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">Намерени са %1$d канала</item>
- <item quantity="one">Намерен е %1$d канал</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">Много добре! По време на сканирането бяха намерени %1$d канала. Ако това не изглежда вярно, опитайте да коригирате позицията на антената и сканирайте отново.</item>
- <item quantity="one">Много добре! По време на сканирането бе намерен %1$d канал. Ако това не изглежда вярно, опитайте да коригирате позицията на антената и сканирайте отново.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Готово"</item>
- <item msgid="496688122303154468">"Повторно сканиране"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Няма намерени канали"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"При сканирането не бяха открити канали. Потвърдете, че USB тунерът е включен и свързан с източник на телевизионен сигнал.\n\nАко използвате безжична антена, коригирайте разположението или посоката й. За най-добри резултати я поставете високо и близо до прозорец и сканирайте отново."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Повторно сканиране"</item>
- <item msgid="6784975565864102291">"Готово"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Сканиране за телевизионни канали"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Настройване на USB тунера за канали"</string>
-</resources>
diff --git a/usbtuner/res/values-bn-rBD/strings.xml b/usbtuner/res/values-bn-rBD/strings.xml
deleted file mode 100644
index e15fefd3..00000000
--- a/usbtuner/res/values-bn-rBD/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB টিউনার TV ইনপুট"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"চালু আছে"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"বন্ধ করুন"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"প্রক্রিয়াকরণ সম্পূর্ণ না হওয়া পর্যন্ত অনুগ্রহ করে অপেক্ষা করুন"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"আপনার চ্যানেল সূত্র নির্বাচন করুন"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"কোনো সংকেত নেই"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> -এ টিউন করতে ব্যর্থ হয়েছে"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"টিউন করতে ব্যর্থ হয়েছে"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB টিউনার সফ্টওয়্যার সম্প্রতি আপডেট করা হয়েছে৷ অনুগ্রহ করে চ্যানেলগুলি পুনরায় স্ক্যান করুন৷"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 অডিও অনুপলব্ধ"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"চ্যানেল টিউনার সেট আপ"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB চ্যানেল টিউনার সেট আপ"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"চালিয়ে যান"</item>
- <item msgid="7745727658174773453">"এখনই নয়"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"চ্যানেলের সেট আপ পুনরায় রান করতে চান?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"এটি USB টিউনার থেকে পাওয়া চ্যানেলগুলিকে মুছবে এবং নতুন চ্যানেলগুলির জন্য আবার স্ক্যান করবে৷\n\nUSB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে অধিকাংশ চ্যানেল পাওয়ার জন্য আপনাকে সেটির অবস্থান এবং দিক ঠিক করতে হতে পারে৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"চালিয়ে যান"</item>
- <item msgid="4432431398374089710">"বাতিল করুন"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"সংযোগের প্রকার নির্বাচন করুন"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"যদি আপনার টিউনারের সাথে কোনো বাহ্যিক অ্যান্টেনা সংযুক্ত থাকে তাহলে অ্যান্টেনা বাছুন৷ আপনার চ্যানেলগুলি যদি কোনো কেবল পরিষেবা প্রদানকারীর থেকে আসে তাহলে কেবল বাছুন৷ আপনি যদি নিশ্চিত না হন তাহলে উভয় প্রকারের স্ক্যান করা হবে, কিন্তু এটি অনেক সময় নিতে পারে৷"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"অ্যান্টেনা"</item>
- <item msgid="2445879869338877559">"কেবল"</item>
- <item msgid="597328838068074806">"নিশ্চিত নই"</item>
- <item msgid="3613410733017077040">"শুধুমাত্র বিকাশের উদ্দেশ্য"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB চ্যানেল টিউনার সেটআপ"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"এটি কয়েক মিনিট সময় নিতে পারে"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$dটি চ্যানেল পাওয়া গেছে</item>
- <item quantity="other">%1$dটি চ্যানেল পাওয়া গেছে</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"চ্যানেল স্ক্যান করা থামান"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$dটি চ্যানেল পাওয়া গেছে</item>
- <item quantity="other">%1$dটি চ্যানেল পাওয়া গেছে</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">সুন্দর! চ্যানেল স্ক্যান করার সময়ে %1$dটি চ্যানেল পাওয়া গেছে। এটিকে যদি ঠিক বলে না মনে হয়, তাহলে অ্যান্টেনার অবস্থান ঠিক করার চেষ্টা করুন ও আবার স্ক্যান করুন।</item>
- <item quantity="other">সুন্দর! চ্যানেল স্ক্যান করার সময়ে %1$dটি চ্যানেল পাওয়া গেছে। এটিকে যদি ঠিক বলে না মনে হয়, তাহলে অ্যান্টেনার অবস্থান ঠিক করার চেষ্টা করুন ও আবার স্ক্যান করুন।</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"সম্পন্ন"</item>
- <item msgid="496688122303154468">"আবার স্ক্যান করুন"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"কোনো চ্যানেল খুঁজে পাওয়া যায়নি"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"স্ক্যান করে কোনো চ্যানেল খুঁজে পাওয়া যায়নি৷ USB টিউনার প্ল্যাগ ইন রয়েছে এবং একটি TV সিগন্যাল উৎসের সাথে সংযুক্ত রয়েছে তা যাচাই করুন৷\n\nযদি কোনো ওভার-দ্য-এয়ার অ্যান্টেনা ব্যবহার করা হয় তাহলে সেটির অবস্থান এবং দিক ঠিক করুন৷ আরো ভাল ফলাফলের জন্য, এটিকে উচুঁতে কোনো জানলার সামনে রাখুন এবং আবার স্ক্যান করুন৷"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"আবার স্ক্যান করুন"</item>
- <item msgid="6784975565864102291">"সম্পন্ন"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"টিভি চ্যানেলগুলি স্ক্যান করুন"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB চ্যানেল টিউনার সেটআপ"</string>
-</resources>
diff --git a/usbtuner/res/values-ca/strings.xml b/usbtuner/res/values-ca/strings.xml
deleted file mode 100644
index 026ad147..00000000
--- a/usbtuner/res/values-ca/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada de televisió de sintonitzador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activa"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desactiva"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Espera per finalitzar el processament"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecciona la font del canal"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sense senyal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"No s\'ha pogut sintonitzar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"No s\'ha pogut sintonitzar"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"El programari del sintonitzador USB s\'ha actualitzat fa poc. Torna a cercar els canals."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"L\'àudio AC3 no està disponible"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuració del sintonitzador de canals"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuració del sintonitzador de canals USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de TV.\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="4294610848989236664">"Continua"</item>
- <item msgid="7745727658174773453">"Ara no"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Vols tornar a executar la configuració de canals?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Això farà que se suprimeixin del sintonitzador USB els canals trobats i que se\'n tornin a cercar de nous.\n\nVerifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de TV.\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="8729290093918719208">"Continua"</item>
- <item msgid="4432431398374089710">"Cancel·la"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selecciona el tipus de connexió"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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 ho saps del cert, se cercaran els dos tipus de canals però el procés pot tardar més."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"No ho sé"</item>
- <item msgid="3613410733017077040">"Només per a desenvolupament"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuració del sintonitzador de canals USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Aquesta acció pot tardar uns quants minuts"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ATURA LA CERCA DE CANALS"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">Molt bé! S\'han trobat %1$d canals durant la cerca de canals. Si creus que no és correcte, prova d\'ajustar la posició de l\'antena i torna a cercar.</item>
- <item quantity="one">Molt bé! S\'ha trobat %1$d canal durant la cerca de canals. Si creus que no és correcte, prova d\'ajustar la posició de l\'antena i torna a cercar.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Fet"</item>
- <item msgid="496688122303154468">"Torna a cercar"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No s\'ha trobat cap canal"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"No s\'ha trobat cap canal. Verifica que el sintonitzador USB estigui endollat i connectat a una font de senyal de TV.\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="6593834378620684951">"Torna a cercar"</item>
- <item msgid="6784975565864102291">"Fet"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Cerca canals de televisió"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuració del sintonitzador de canals USB"</string>
-</resources>
diff --git a/usbtuner/res/values-cs/strings.xml b/usbtuner/res/values-cs/strings.xml
deleted file mode 100644
index 6a6c94b2..00000000
--- a/usbtuner/res/values-cs/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Tuner USB – televizní vstup"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Zapnout"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Vypnout"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Vyčkejte prosím, než bude zpracování dokončeno"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Vyberte zdroj kanálu"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Žádný signál"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kanál <xliff:g id="CHANNEL_NAME">%s</xliff:g> se nepodařilo naladit"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Nelze naladit"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Software tuneru USB byl nedávno aktualizován. Znovu vyhledejte kanály."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Zvuk AC3 není k dispozici"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Nastavení tuneru kanálů"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Nastavení tuneru kanálů USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Pokračovat"</item>
- <item msgid="7745727658174773453">"Teď ne"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Znovu spustit nastavení kanálů?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Tímto odeberete 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Pokračovat"</item>
- <item msgid="4432431398374089710">"Zrušit"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Vyberte typ připojení"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Anténa"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Nevím"</item>
- <item msgid="3613410733017077040">"Pouze pro vývojáře"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Nastavení tuneru kanálů USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Tato akce může trvat několik minut"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ZASTAVIT VYHLEDÁVÁNÍ KANÁLŮ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="few">Úspěch! 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">Úspěch! 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">Úspěch! 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">Úspěch! 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="979481834388007277">"Hotovo"</item>
- <item msgid="496688122303154468">"Znovu prohledat"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nebyly nalezeny žádné kanály"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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é znovu spusťte vyhledávání."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Znovu prohledat"</item>
- <item msgid="6784975565864102291">"Hotovo"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Vyhledejte televizní kanály"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Nastavení tuneru kanálů USB"</string>
-</resources>
diff --git a/usbtuner/res/values-da/strings.xml b/usbtuner/res/values-da/strings.xml
deleted file mode 100644
index 1eb72373..00000000
--- a/usbtuner/res/values-da/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Indgang til USB-tuner på fjernsynet"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Til"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Fra"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Vent, mens behandlingen afsluttes"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Vælg din kanalkilde"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Intet signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> kunne ikke indlæses"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Indlæsningen lykkedes ikke"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Softwaren til USB-tuneren er blevet opdateret for nylig. Scan efter kanalerne igen."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-lyd er ikke tilgængelig"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Konfiguration af kanaltuneren"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Konfiguration af USB-kanaltuneren"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Kontrollér, 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Fortsæt"</item>
- <item msgid="7745727658174773453">"Ikke nu"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Vil du gentage kanalkonfigurationen?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Denne handling fjerner de kanaler, der blev fundet af USB-tuneren, og starter en ny scanning efter kanaler.\n\nKontrollér, 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Fortsæt"</item>
- <item msgid="4432431398374089710">"Annuller"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Vælg forbindelsestype"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Jeg er ikke sikker"</item>
- <item msgid="3613410733017077040">"Kun til udvikling"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Konfiguration af USB-kanaltuneren"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Dette kan tage flere minutter"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"STOP KANALSCANNINGEN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="one">Sådan! Der blev fundet %1$d kanal ved kanalsøgningen. Hvis du mener, det er forkert, kan du prøve at justere antennens position og søge igen.</item>
- <item quantity="other">Sådan! Der blev fundet %1$d kanaler ved kanalsøgningen. Hvis du mener, det er forkert, kan du prøve at justere antennens position og søge igen.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Udført"</item>
- <item msgid="496688122303154468">"Scan igen"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Der blev ikke fundet nogen kanaler"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Der blev ikke fundet nogen kanaler under scanningen. Kontrollér, 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Scan igen"</item>
- <item msgid="6784975565864102291">"Udført"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Scan efter tv-kanaler"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Konfiguration af USB-kanaltuneren"</string>
-</resources>
diff --git a/usbtuner/res/values-de/strings.xml b/usbtuner/res/values-de/strings.xml
deleted file mode 100644
index 85c54fed..00000000
--- a/usbtuner/res/values-de/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-Tuner – TV-Eingabe"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"An"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Aus"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Bitte warten Sie, bis die Verarbeitung abgeschlossen ist."</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Kanalquelle auswählen"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Kein Signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> konnte nicht eingestellt werden."</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Fehler beim Einstellen"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Die USB-Tunersoftware wurde kürzlich aktualisiert. Bitte führen Sie die Kanalsuche erneut durch."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC-3-Audio nicht verfügbar"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanaleinrichtung über den Tuner"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Kanaleinrichtung über den USB-Tuner"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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 eine erhöhte Position in Fensternähe stellen."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Weiter"</item>
- <item msgid="7745727658174773453">"Jetzt nicht"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kanaleinrichtung erneut durchführen?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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 eine erhöhte Position in Fensternähe stellen."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Weiter"</item>
- <item msgid="4432431398374089710">"Abbrechen"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Verbindungstyp auswählen"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Nicht sicher"</item>
- <item msgid="3613410733017077040">"Nur Entwicklung"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Kanaleinrichtung über den USB-Tuner"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Dies kann einige Minuten dauern."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"KANALSUCHE STOPPEN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">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">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="979481834388007277">"Fertig"</item>
- <item msgid="496688122303154468">"Erneut suchen"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Keine Kanäle gefunden"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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 eine erhöhte Position in Fensternähe stellen. Suchen Sie dann erneut."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Erneut suchen"</item>
- <item msgid="6784975565864102291">"Fertig"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Nach TV-Kanälen suchen"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Kanaleinrichtung über den USB-Tuner"</string>
-</resources>
diff --git a/usbtuner/res/values-el/strings.xml b/usbtuner/res/values-el/strings.xml
deleted file mode 100644
index f447ef7e..00000000
--- a/usbtuner/res/values-el/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Δέκτης USB εισόδου τηλεόρασης"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Ενεργό"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Ανενεργό"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Παρακαλώ περιμένετε να ολοκληρωθεί η επεξεργασία"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Επιλέξτε την πηγή του καναλιού σας"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Χωρίς σήμα"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Αποτυχία συντονισμού <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Αποτυχία συντονισμού"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Το λογισμικό δέκτη USB ενημερώθηκε πρόσφατα. Επαναλάβετε τη σάρωση καναλιών."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Δεν υπάρχει διαθέσιμος ήχος AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Ρύθμιση του δέκτη καναλιών"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Ρύθμιση δέκτη καναλιών USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Βεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Συνέχεια"</item>
- <item msgid="7745727658174773453">"Όχι τώρα"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Επανάληψη ρύθμισης καναλιών;"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Με αυτόν τον τρόπο θα καταργηθούν τα κανάλια που εντοπίστηκαν από το δέκτη USB και θα γίνει ξανά σάρωση για νέα κανάλια.\n\nΒεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Συνέχεια"</item>
- <item msgid="4432431398374089710">"Ακύρωση"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Επιλέξτε τον τύπο σύνδεσης"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Επιλέξτε \"Κεραία\" εάν έχει συνδεθεί μια εξωτερική κεραία στο δέκτη. Επιλέξτε \"Καλωδιακή\" εάν τα κανάλια σας προέρχονται από έναν πάροχο υπηρεσιών καλωδιακής τηλεόρασης. Εάν δεν είστε βέβαιοι, θα γίνει σάρωση και για τους δύο τύπους, αλλά αυτό ενδέχεται να διαρκέσει περισσότερο."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Κεραία"</item>
- <item msgid="2445879869338877559">"Καλωδιακή"</item>
- <item msgid="597328838068074806">"Ίσως"</item>
- <item msgid="3613410733017077040">"Μόνο ανάπτυξη"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Ρύθμιση δέκτη καναλιών USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Αυτό μπορεί να διαρκέσει αρκετά λεπτά"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">Βρέθηκαν %1$d κανάλια</item>
- <item quantity="one">Βρέθηκε %1$d κανάλι</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ΔΙΑΚΟΠΗ ΣΑΡΩΣΗΣ ΚΑΝΑΛΙΩΝ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">Βρέθηκαν %1$d κανάλια</item>
- <item quantity="one">Βρέθηκε %1$d κανάλι</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">Ωραία! Βρέθηκαν %1$d κανάλια κατά τη σάρωση καναλιών. Εάν αυτό δεν φαίνεται σωστό, δοκιμάστε να ρυθμίσετε τη θέση της κεραίας και επαναλάβετε τη σάρωση.</item>
- <item quantity="one">Ωραία! Βρέθηκε %1$d κανάλι κατά τη σάρωση καναλιών. Εάν αυτό δεν φαίνεται σωστό, δοκιμάστε να ρυθμίσετε τη θέση της κεραίας και επαναλάβετε τη σάρωση.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Τέλος"</item>
- <item msgid="496688122303154468">"Εκ νέου σάρωση"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Δεν βρέθηκαν κανάλια"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Δεν βρέθηκαν κανάλια κατά τη σάρωση. Βεβαιωθείτε ότι ο δέκτης USB είναι συνδεδεμένος στην πρίζα και σε μια πηγή τηλεοπτικού σήματος.\n\nΕάν χρησιμοποιείτε ασύρματη κεραία, ίσως χρειαστεί να προσαρμόσετε την τοποθέτηση ή την κατεύθυνσή της για να λάβετε περισσότερα κανάλια. Για καλύτερα αποτελέσματα, τοποθετήστε την ψηλά και κοντά σε ένα παράθυρο."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Εκ νέου σάρωση"</item>
- <item msgid="6784975565864102291">"Τέλος"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Σάρωση για τηλεοπτικά κανάλια"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Ρύθμιση δέκτη καναλιών USB"</string>
-</resources>
diff --git a/usbtuner/res/values-en-rAU/strings.xml b/usbtuner/res/values-en-rAU/strings.xml
deleted file mode 100644
index 78e4598b..00000000
--- a/usbtuner/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TV Input"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"On"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Off"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Please wait to finish processing"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Select your channel source"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"No Signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Failed to tune"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB tuner software has been recently updated. Please re-scan the channels."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audio not available"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Channel tuner setup"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB channel tunner setup"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verify 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continue"</item>
- <item msgid="7745727658174773453">"Not now"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Rerun channel setup?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nVerify 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continue"</item>
- <item msgid="4432431398374089710">"Cancel"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Select the connection type"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Aerial"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"Not sure"</item>
- <item msgid="3613410733017077040">"Development only"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB channel tuner setup"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"This may take several minutes"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d channels found</item>
- <item quantity="one">%1$d channel found</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"STOP CHANNEL SCAN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Finished"</item>
- <item msgid="496688122303154468">"Scan again"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No Channels found"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"The scan did not find any channels. Verify 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Scan again"</item>
- <item msgid="6784975565864102291">"Finished"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Scan for TV channels"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB channel tuner setup"</string>
-</resources>
diff --git a/usbtuner/res/values-en-rGB/strings.xml b/usbtuner/res/values-en-rGB/strings.xml
deleted file mode 100644
index 78e4598b..00000000
--- a/usbtuner/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TV Input"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"On"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Off"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Please wait to finish processing"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Select your channel source"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"No Signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Failed to tune"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB tuner software has been recently updated. Please re-scan the channels."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audio not available"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Channel tuner setup"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB channel tunner setup"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verify 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continue"</item>
- <item msgid="7745727658174773453">"Not now"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Rerun channel setup?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nVerify 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continue"</item>
- <item msgid="4432431398374089710">"Cancel"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Select the connection type"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Aerial"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"Not sure"</item>
- <item msgid="3613410733017077040">"Development only"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB channel tuner setup"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"This may take several minutes"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d channels found</item>
- <item quantity="one">%1$d channel found</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"STOP CHANNEL SCAN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Finished"</item>
- <item msgid="496688122303154468">"Scan again"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No Channels found"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"The scan did not find any channels. Verify 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Scan again"</item>
- <item msgid="6784975565864102291">"Finished"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Scan for TV channels"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB channel tuner setup"</string>
-</resources>
diff --git a/usbtuner/res/values-en-rIN/strings.xml b/usbtuner/res/values-en-rIN/strings.xml
deleted file mode 100644
index 78e4598b..00000000
--- a/usbtuner/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TV Input"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"On"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Off"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Please wait to finish processing"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Select your channel source"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"No Signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Failed to tune to <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Failed to tune"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB tuner software has been recently updated. Please re-scan the channels."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audio not available"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Channel tuner setup"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB channel tunner setup"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verify 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continue"</item>
- <item msgid="7745727658174773453">"Not now"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Rerun channel setup?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"This will remove the channels found from the USB tuner and scan for new channels again.\n\nVerify 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continue"</item>
- <item msgid="4432431398374089710">"Cancel"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Select the connection type"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Aerial"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"Not sure"</item>
- <item msgid="3613410733017077040">"Development only"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB channel tuner setup"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"This may take several minutes"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d channels found</item>
- <item quantity="one">%1$d channel found</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"STOP CHANNEL SCAN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Finished"</item>
- <item msgid="496688122303154468">"Scan again"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No Channels found"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"The scan did not find any channels. Verify 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Scan again"</item>
- <item msgid="6784975565864102291">"Finished"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Scan for TV channels"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB channel tuner setup"</string>
-</resources>
diff --git a/usbtuner/res/values-es-rUS/strings.xml b/usbtuner/res/values-es-rUS/strings.xml
deleted file mode 100644
index cf2a28d4..00000000
--- a/usbtuner/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada de TV de sintonizador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activar"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desactivar"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Espera a que finalice el procesamiento"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Seleccionar la fuente del canal"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sin señal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"No se pudo sintonizar el canal <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"No se pudo sintonizar el canal"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"El software del sintonizador USB se actualizó recientemente. Vuelve a buscar los canales."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"El audio AC-3 no está disponible"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuración del sintonizador de canales"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuración del sintonizador de canales USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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 la 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuar"</item>
- <item msgid="7745727658174773453">"Ahora no"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"¿Quieres volver a configurar los canales?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Esta acción quitará los canales que se encontraron del sintonizador USB, y se hará una nueva búsqueda de canales.\n\nComprueba 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 la 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuar"</item>
- <item msgid="4432431398374089710">"Cancelar"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selecciona el tipo de conexión"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"No estoy seguro"</item>
- <item msgid="3613410733017077040">"Solo para desarrollo"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuración del sintonizador de canales USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Este proceso podría demorar varios minutos"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"DETENER LA BÚSQUEDA DE CANALES"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Listo"</item>
- <item msgid="496688122303154468">"Volver a buscar"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No se encontraron canales"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"No se encontraron canales en la búsqueda. Comprueba que el sintonizador USB esté enchufado y conectado a una fuente de señal de TV.\n\nSi usas una antena inalámbrica, ajusta la ubicación o dirección. Para obtener mejores resultados, ubícala en un lugar alto y cerca de una ventana y, luego, vuelve a realizar la búsqueda."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Volver a buscar"</item>
- <item msgid="6784975565864102291">"Listo"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Buscar canales de TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuración del sintonizador de canales USB"</string>
-</resources>
diff --git a/usbtuner/res/values-es/strings.xml b/usbtuner/res/values-es/strings.xml
deleted file mode 100644
index 00913ad0..00000000
--- a/usbtuner/res/values-es/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada de TV de sintonizador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activar"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desactivada"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Espera para finalizar el procesamiento"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecciona la fuente de canales"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sin señal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Error al sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Error al sintonizar"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"El software del sintonizador USB se ha actualizado recientemente. Vuelve a buscar los canales."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Audio AC3 no disponible"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuración de sintonizador de canales"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuración de sintonizador de canales USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Comprueba que el sintonizador USB esté enchufado y conectado.\n\nSi utilizas una antena inalámbrica, puede que tengas que cambiar su ubicación o dirección para recibir la mayoría de los canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuar"</item>
- <item msgid="7745727658174773453">"Ahora no"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"¿Quieres volver a ejecutar la configuración del canal?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Se eliminarán los canales encontrados con el sintetizador 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ía de los canales. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuar"</item>
- <item msgid="4432431398374089710">"Cancelar"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selecciona un tipo de conexión"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"No lo sé con seguridad"</item>
- <item msgid="3613410733017077040">"Solo desarrollo"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuración de sintonizador de canales USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Este proceso puede tardar varios minutos"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d canales encontrados</item>
- <item quantity="one">%1$d canal encontrado</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"DETENER LA BÚSQUEDA DE CANALES"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">¡Genial! Se han encontrado %1$d canales durante la búsqueda de canales. Si no se ven correctamente, modifica 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 se ve correctamente, modifica la posición de la antena y vuelve a realizar la búsqueda.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Listo"</item>
- <item msgid="496688122303154468">"Volver a buscar"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"No se han encontrado canales"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"La búsqueda no 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 ubicación o dirección. Para conseguir los mejores resultados, colócala en alto y cerca de una ventana y, a continuación, vuelve a realizar la búsqueda."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Volver a buscar"</item>
- <item msgid="6784975565864102291">"Listo"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Busca canales de TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuración de sintonizador de canales USB"</string>
-</resources>
diff --git a/usbtuner/res/values-et-rEE/strings.xml b/usbtuner/res/values-et-rEE/strings.xml
deleted file mode 100644
index 9ffb7227..00000000
--- a/usbtuner/res/values-et-rEE/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-tuuneri TV-sisend"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Sees"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Väljas"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Oodake, kuni töötlemine on lõppenud"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Valige kanali allikas"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Pole signaali"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kanalile <xliff:g id="CHANNEL_NAME">%s</xliff:g> häälestamine ebaõnnestus"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Häälestamine ebaõnnestus"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB-tuuneri tarkvara värskendati hiljuti. Otsige kanaleid uuesti."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-heli pole saadaval"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanalituuneri seadistus"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB-kanalituuneri seadistus"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Veenduge, et USB-tuuner oleks pistikus ja ü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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Jätka"</item>
- <item msgid="7745727658174773453">"Mitte praegu"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kas käitada kanali seadistust uuesti?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Jätka"</item>
- <item msgid="4432431398374089710">"Tühista"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Valige ühenduse tüüp"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenn"</item>
- <item msgid="2445879869338877559">"Kaabel"</item>
- <item msgid="597328838068074806">"Ei ole kindel"</item>
- <item msgid="3613410733017077040">"Ainult arenduseks"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB-kanalituuneri seadistus"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"See võib võtta mitu minutit"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">Leiti %1$d kanalit</item>
- <item quantity="one">Leiti %1$d kanal</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"PEATA KANALITE OTSIMINE"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Valmis"</item>
- <item msgid="496688122303154468">"Otsi uuesti"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Ühtegi kanalit ei leitud"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Otsi uuesti"</item>
- <item msgid="6784975565864102291">"Valmis"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Otsige telekanaleid"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB-kanalituuneri seadistus"</string>
-</resources>
diff --git a/usbtuner/res/values-eu-rES/strings.xml b/usbtuner/res/values-eu-rES/strings.xml
deleted file mode 100644
index 4f81259e..00000000
--- a/usbtuner/res/values-eu-rES/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB sintonizadorearen telebista-sarrera"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aktibatuta"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desaktibatuta"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Itxaron prozesatzen amaitu arte"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Hautatu kanalaren iturburua"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ez dago seinalerik"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Ezin izan da sintonizatu <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Ezin izan da sintonizatu"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB sintonizadorearen softwarea berriki eguneratu da. Bilatu kanalak berriro."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audioa ez dago erabilgarri"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanal-sintonizadorearen konfigurazioa"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB kanal-sintonizadorearen konfigurazioa"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Jarraitu"</item>
- <item msgid="7745727658174773453">"Orain ez"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Berriro abiarazi nahi duzu kanalen konfigurazioa?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"USB sintonizadoreak aurkitutako kanalak kenduko dira eta berriro bilatuko dira kanalak.\n\nEgiaztatu 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Jarraitu"</item>
- <item msgid="4432431398374089710">"Utzi"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Hautatu konexio mota"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kablea"</item>
- <item msgid="597328838068074806">"Ez dakit ziur"</item>
- <item msgid="3613410733017077040">"Garapenerako soilik"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB kanal-sintonizadorearen konfigurazioa"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Zenbait minutu beharko dira"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"UTZI KANALAK BILATZEARI"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Eginda"</item>
- <item msgid="496688122303154468">"Bilatu berriro"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Ez da aurkitu kanalik"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Ez du kanalik aurkitu bilaketak. 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Bilatu berriro"</item>
- <item msgid="6784975565864102291">"Eginda"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Bilatu telebista-kanalak"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB kanal-sintonizadorearen konfigurazioa"</string>
-</resources>
diff --git a/usbtuner/res/values-fa/strings.xml b/usbtuner/res/values-fa/strings.xml
deleted file mode 100644
index 899e4f67..00000000
--- a/usbtuner/res/values-fa/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"‏ورودی USB تنظیم‌کننده در تلویزیون"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"روشن"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"خاموش"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"لطفاً تا پایان پردازش صبر کنید"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"منبع کانال را انتخاب کنید"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"بدون سیگنال"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"تنظیم به <xliff:g id="CHANNEL_NAME">%s</xliff:g> انجام نشد"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"تنظیم ناموفق بود"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"‏نرم‌افزار USB تنظیم‌کننده اخیراً به‌روز شده است. لطفاً کانال‌ها را دوباره اسکن کنید."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"‏صوت AC3 دردسترس نیست"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"راه‌اندازی تنظیم‌کننده کانال"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"‏راه‌اندازی تنظیم‌کننده کانال USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"‏مطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر شرایط استفاده از آنتن بی‌سیم، موقعیت و جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"ادامه"</item>
- <item msgid="7745727658174773453">"فعلاً نه"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"تنظیم کانال دوباره اجرا شود؟"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"‏این کار کانال‌های پیدا شده از تنظیم‌کننده USB را حذف می‌کند و دوباره برای کانال‌های جدید اسکن می‌کند.\n\nمطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر شرایط استفاده از آنتن بی‌سیم، موقعیت و جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"ادامه"</item>
- <item msgid="4432431398374089710">"لغو"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"انتخاب نوع اتصال"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"اگر یک آنتن خارجی به تنظیم‌کننده وصل است، «آنتن» را انتخاب کنید. اگر کانال‌های شما از یک ارائه‌دهنده سرویس کابلی ارائه می‌شوند، «کابل» را انتخاب کنید. اگر مطمئن نیستید، هر دو نوع اسکن می‌شوند اما بیشتر طول می‌کشد."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"آنتن"</item>
- <item msgid="2445879869338877559">"کابل"</item>
- <item msgid="597328838068074806">"مطمئن نیستم"</item>
- <item msgid="3613410733017077040">"فقط برای برنامه‌نویسی"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"‏نصب تنظیم‌کننده کانال USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ممکن است چند دقیقه طول بکشد"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">‏%1$d کانال پیدا شد</item>
- <item quantity="other">‏%1$d کانال پیدا شد</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"توقف اسکن کانال"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">‏%1$d کانال پیدا شد</item>
- <item quantity="other">‏%1$d کانال پیدا شد</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">‏خوب است! در طول اسکن کانال %1$d کانال پیدا شد. اگر این تعداد درست به نظر نمی‌رسد، موقعیت آنتن را تنظیم کنید و دوباره اسکن کنید.</item>
- <item quantity="other">‏خوب است! در طول اسکن کانال %1$d کانال پیدا شد. اگر این تعداد درست به نظر نمی‌رسد، موقعیت آنتن را تنظیم کنید و دوباره اسکن کنید.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"تمام"</item>
- <item msgid="496688122303154468">"اسکن دوباره"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"کانالی پیدا نشد"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"‏اسکن هیچ کانالی پیدا نکرد. مطمئن شوید تنظیم‌کننده USB به منبع نیرو و منبع سیگنال تلویزیونی متصل است.\n\nدر شرایط استفاده از آنتن بی‌سیم، موقعیت و جهت آن را تنظیم کنید. برای بهترین نتایج، آن را در جای بلند و نزدیک پنجره قرار دهید و دوباره اسکن کنید."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"اسکن دوباره"</item>
- <item msgid="6784975565864102291">"تمام"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"اسکن کانال‌های تلویزیون"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"‏نصب تنظیم‌کننده کانال USB"</string>
-</resources>
diff --git a/usbtuner/res/values-fi/strings.xml b/usbtuner/res/values-fi/strings.xml
deleted file mode 100644
index 35be3248..00000000
--- a/usbtuner/res/values-fi/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-virittimen TV-tulo"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Käytössä"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Ei käytössä"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Odota, että käsittely on valmis."</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Valitse kanavalähde"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ei signaalia"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kanavan <xliff:g id="CHANNEL_NAME">%s</xliff:g> virittäminen epäonnistui."</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Virittäminen epäonnistui."</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB-viritinohjelmisto on päivitetty äskettäin. Hae kanavat uudelleen."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-ääni ei ole käytettävissä."</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanavavirittimen määritys"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB-kanavavirittimen määritys"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Tarkista, että USB-viritin on kytketty oikein ja liitetty TV-signaalilähteeseen.\n\nJos käytät antennia, saatat joutua muuttamaan sen paikkaa tai suuntaa löytääksesi enemmän kanavia. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Jatka"</item>
- <item msgid="7745727658174773453">"Ei nyt"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Haetaanko kanavia uudelleen?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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, saatat joutua muuttamaan sen paikkaa tai suuntaa löytääksesi enemmän kanavia. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Jatka"</item>
- <item msgid="4432431398374089710">"Peruuta"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Valitse yhteystyyppi"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenni"</item>
- <item msgid="2445879869338877559">"Kaapeli"</item>
- <item msgid="597328838068074806">"En ole varma"</item>
- <item msgid="3613410733017077040">"Vain kehitystä varten"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB-kanavavirittimen määritys"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Tämä voi kestää useita minuutteja."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"LOPETA KANAVAHAKU"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Valmis"</item>
- <item msgid="496688122303154468">"Hae uudelleen"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Kanavia ei löytynyt"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Haulla ei löytynyt 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 suuntaa. Saat parhaan tuloksen asettamalla antennin korkealle ja lähelle ikkunaa. Tee haku sitten uudelleen."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Hae uudelleen"</item>
- <item msgid="6784975565864102291">"Valmis"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Hae TV-kanavia"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB-kanavavirittimen määritys"</string>
-</resources>
diff --git a/usbtuner/res/values-fr-rCA/strings.xml b/usbtuner/res/values-fr-rCA/strings.xml
deleted file mode 100644
index 557aee53..00000000
--- a/usbtuner/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrée télé de type syntoniseur USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activer"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Désactiver"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Veuillez patienter jusqu\'à la fin du traitement"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Sélectionnez votre source de chaînes"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Aucun signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Impossible de syntoniser <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Échec de syntonisation"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Le logiciel du syntoniseur USB a été mis à jour récemment. Veuillez rechercher les chaînes à nouveau."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"L\'audio au format AC3 n\'est pas disponible"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuration du syntoniseur de chaînes"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuration du syntoniseur de chaînes USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuer"</item>
- <item msgid="7745727658174773453">"Pas maintenant"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Relancer la configuration des chaînes?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuer"</item>
- <item msgid="4432431398374089710">"Annuler"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Sélectionnez le type de connexion"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Câble"</item>
- <item msgid="597328838068074806">"Pas certain"</item>
- <item msgid="3613410733017077040">"Développement seulement"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configurer les chaînes du syntoniseur USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Cela peut prendre plusieurs minutes"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ARRÊTER LA RECHERCHE DE CHAÎNES"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="one">Excellent! %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">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="979481834388007277">"Terminé"</item>
- <item msgid="496688122303154468">"Rechercher à nouveau"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Aucune chaîne"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Rechercher à nouveau"</item>
- <item msgid="6784975565864102291">"Terminé"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Rechercher les chaînes de télévision"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configurer les chaînes du syntoniseur USB"</string>
-</resources>
diff --git a/usbtuner/res/values-fr/strings.xml b/usbtuner/res/values-fr/strings.xml
deleted file mode 100644
index 8227dd84..00000000
--- a/usbtuner/res/values-fr/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrée TV de type tuner USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activé"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Désactivé"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Veuillez patienter jusqu\'à la fin du traitement."</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Sélectionnez la source de la chaîne."</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Aucun signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Échec de sélection de la chaîne <xliff:g id="CHANNEL_NAME">%s</xliff:g>."</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Échec du réglage."</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Le logiciel du tuner USB a été mis à jour récemment. Veuillez rechercher les chaînes à nouveau."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Audio au format AC3 indisponible."</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuration du tuner de chaînes"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuration du tuner de chaînes USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuer"</item>
- <item msgid="7745727658174773453">"Pas maintenant"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Relancer la configuration de la chaîne ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuer"</item>
- <item msgid="4432431398374089710">"Annuler"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Sélectionner le type de connexion"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Câble"</item>
- <item msgid="597328838068074806">"Je ne sais pas"</item>
- <item msgid="3613410733017077040">"Développement uniquement"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuration du tuner de chaînes USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Cette opération peut prendre plusieurs minutes."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ARRÊTER LA RECHERCHE DE CHAÎNES"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="one">Bravo ! %1$d chaîne a été détectée pendant la recherche de chaînes. Si cela vous semble incorrect, veuillez ajuster la position de l\'antenne et effectuez 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, veuillez ajuster la position de l\'antenne et effectuez une nouvelle recherche.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"OK"</item>
- <item msgid="496688122303154468">"Rechercher à nouveau"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Aucune chaîne n\'a été détectée"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Rechercher à nouveau"</item>
- <item msgid="6784975565864102291">"OK"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Rechercher les chaînes de télévision"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuration du tuner de chaînes USB"</string>
-</resources>
diff --git a/usbtuner/res/values-gl-rES/strings.xml b/usbtuner/res/values-gl-rES/strings.xml
deleted file mode 100644
index 89e2e827..00000000
--- a/usbtuner/res/values-gl-rES/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada do televisor con sintonizador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activar"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desactivar"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Espere a que finalice o procesamento"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecciona a fonte da túa canle"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sen sinal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Produciuse un erro ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Produciuse un erro ao sintonizar"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"O software do sintonizador USB actualizouse recentemente. Volve buscar canles."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Non está dispoñible o audio AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuración do sintonizador de canles"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuración do sintonizador de canles USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Comproba se o sintonizador USB está enchufado e conéctao 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="4294610848989236664">"Continuar"</item>
- <item msgid="7745727658174773453">"Agora non"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Queres volver executar a configuración da canle?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Esta acción eliminará as canles que atopaches co sintonizador USB e busca outras novas.\n\nComproba se o sintonizador USB está enchufado e conéctao 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_again_choices">
- <item msgid="8729290093918719208">"Continuar"</item>
- <item msgid="4432431398374089710">"Cancelar"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Seleccionar tipo de conexión"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"Non estou seguro"</item>
- <item msgid="3613410733017077040">"Só desenvolvemento"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuración do sintonizador de canles USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Esta acción pode tardar varios minutos"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"DETER BUSCA DE CANLES"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Feito"</item>
- <item msgid="496688122303154468">"Buscar de novo"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Non se atopou ningunha canle"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"A busca non atopou ningunha canle. Comproba se o sintonizador USB está enchufado e conéctao 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 e preto dunha ventá e volve realizar a busca."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Buscar de novo"</item>
- <item msgid="6784975565864102291">"Feito"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Buscar canles de televisión"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuración do sintonizador de canles USB"</string>
-</resources>
diff --git a/usbtuner/res/values-hi/strings.xml b/usbtuner/res/values-hi/strings.xml
deleted file mode 100644
index 6118629e..00000000
--- a/usbtuner/res/values-hi/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ट्यूनर टीवी इनपुट"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"चालू करें"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"बंद करें"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"कृपया संसाधन समाप्‍त होने की प्रतीक्षा करें"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"अपना चैनल स्रोत चुनें"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"कोई सिग्नल नहीं"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> को ट्यून करने में विफल रहा"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ट्यून करने में विफल रहा"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ट्यूनर सॉफ़्टवेयर को हाल ही में अपडेट किया गया है. कृपया चैनलों को पुनः स्कैन करें."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ऑडियो उपलब्‍ध नहीं है"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"चैनल ट्यूनर सेटअप"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB चैनल ट्यूनर सेटअप"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"पुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट है.\n\nयदि आप ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल प्राप्त करने के लिए आपको इसका प्लेसमेंट या दिशा एडजस्‍ट करना पड़ सकती है. अच्छे परिणामों के लिए, इसे ऊंचाई पर और किसी खिड़की के पास रखें."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"जारी रखें"</item>
- <item msgid="7745727658174773453">"अभी नहीं"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"चैनल सेटअप फिर से चलाएं?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"इससे USB ट्यूनर से मिले चैनल निकाल दिए जाएंगे और नए चैनलों के लिए स्कैन किया जाएगा.\n\nपुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट है.\n\nयदि आप ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो अधिकांश चैनल प्राप्त करने के लिए आपको इसका प्लेसमेंट या दिशा एडजस्‍ट करनी पड़ सकती है. अच्छे परिणामों के लिए, इसे ऊंचाई पर और किसी खिड़की के पास रखें."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"जारी रखें"</item>
- <item msgid="4432431398374089710">"रहने दें"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"कनेक्शन का प्रकार चुनना"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"यदि ट्यूनर से कोई बाहरी एंटेना कनेक्ट है, तो एंटेना चुनें. यदि आपके चैनल किसी केबल सेवा प्रदाता से आते हैं, तो केबल चुनें. यदि आप सुनिश्चित नहीं हैं, तो दोनों प्रकारों को स्कैन किया जाएगा, लेकिन इसमें अधिक समय लग सकता है."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"एंटेना"</item>
- <item msgid="2445879869338877559">"केबल"</item>
- <item msgid="597328838068074806">"सुनिश्चित नहीं हैं"</item>
- <item msgid="3613410733017077040">"केवल डेवलपमेंट"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB चैनल ट्यूनर सेटअप"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"इसमें कई मिनट लग सकते हैं"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d चैनल मिले</item>
- <item quantity="other">%1$d चैनल मिले</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"चैनल स्कैन रोकें"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$d चैनल मिले</item>
- <item quantity="other">%1$d चैनल मिले</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">बढ़िया! चैनल स्कैन करने के दौरान %1$d चैनल मिले. यदि यह सही नहीं लग रहा है, तो एंटेना की स्थिति एडजस्ट करके देखें और पुनः स्कैन करें.</item>
- <item quantity="other">बढ़िया! चैनल स्कैन करने के दौरान %1$d चैनल मिले. यदि यह सही नहीं लग रहा है, तो एंटेना की स्थिति एडजस्ट करके देखें और पुनः स्कैन करें.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"हो गया"</item>
- <item msgid="496688122303154468">"पुन: स्‍कैन करें"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"कोई चैनल नहीं मिला"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"स्कैन से कोई चैनल नहीं मिला. पुष्टि करें कि USB ट्यूनर प्लग इन है और टीवी सिग्नल स्रोत से कनेक्ट है.\n\nयदि आप ओवर-द-एयर एंटेना का उपयोग कर रहे हैं, तो इसका प्लेसमेंट या दिशा एडजस्ट करें. अच्छे परिणामों के लिए, इसे ऊंचाई पर रखें और पुनः स्कैन करें."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"पुन: स्‍कैन करें"</item>
- <item msgid="6784975565864102291">"हो गया"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"टीवी चैनलों के लिए स्‍कैन करें"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB चैनल ट्यूनर सेटअप"</string>
-</resources>
diff --git a/usbtuner/res/values-hr/strings.xml b/usbtuner/res/values-hr/strings.xml
deleted file mode 100644
index ff7f68b2..00000000
--- a/usbtuner/res/values-hr/strings.xml
+++ /dev/null
@@ -1,81 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"TV ulaz USB prijemnika"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Uključeno"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Isključeno"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Pričekajte da obrada završi"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Odaberite izvor kanala"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Nema signala"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Namještanje na kanal <xliff:g id="CHANNEL_NAME">%s</xliff:g> nije uspjelo"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Namještanje nije uspjelo"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Softver USB prijemnika nedavno je ažuriran. Ponovite traženje kanala."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audio nije dostupan"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Postavljanje prijamnika kanala"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Postavljanje USB prijamnika kanala"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Provjerite je li USB prijamnik 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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Nastavi"</item>
- <item msgid="7745727658174773453">"Ne sada"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Želite li ponovo pokrenuti postavljanje kanala?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Time će se ukloniti kanali pronađeni putem USB prijamnika i ponoviti pretraživanje kanala.\n\nProvjerite je li USB prijamnik 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Nastavi"</item>
- <item msgid="4432431398374089710">"Odustani"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Odaberite vrstu veze"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Ako je s prijamnikom 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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Nisam siguran"</item>
- <item msgid="3613410733017077040">"Samo razvoj"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Postavljanje USB prijamnika za kanale"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"To može potrajati nekoliko minuta"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ZAUSTAVI PRETRAŽIVANJE KANALA"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Gotovo"</item>
- <item msgid="496688122303154468">"Pretraži ponovo"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nije pronađen nijedan kanal"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Pretraživanjem nije pronađen nijedan kanal. Provjerite je li USB prijamnik priključen i povezan s izvorom TV 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Pretraži ponovo"</item>
- <item msgid="6784975565864102291">"Gotovo"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Pretražite TV kanale"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Postavljanje USB prijamnika za kanale"</string>
-</resources>
diff --git a/usbtuner/res/values-hu/strings.xml b/usbtuner/res/values-hu/strings.xml
deleted file mode 100644
index 860ea368..00000000
--- a/usbtuner/res/values-hu/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner tévébemenet"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Bekapcsolva"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Kikapcsolva"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Kérjük, várja meg a folyamat befejezését"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Válassza ki a csatornaforrást"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Nincs jel"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Nem sikerült behangolni a(z) <xliff:g id="CHANNEL_NAME">%s</xliff:g> csatornát"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Sikertelen hangolás"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Az USB tuner szoftverét nemrég frissítették. Kérjük, ismételje meg a csatornakeresést."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Nem érhető el AC3-hang"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Csatornatuner beállítása"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB-csatornatuner beállítása"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Győződjön meg arról, hogy az USB-tuner be van dugva, és csatlakoztatva van egy tévés jelforráshoz.\n\nHa vezeték nélküli műsorszóráshoz használt antennával rendelkezik, a legtöbb csatorna észlelése érdekében állítson annak helyzetén: helyezze magasra és egy ablak közelébe."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Folytatás"</item>
- <item msgid="7745727658174773453">"Most nem"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Ismét végrehajtja a csatornabeállítást?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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 egy tévés jelforráshoz.\n\nHa vezeték nélküli műsorszóráshoz használt antennával rendelkezik, a legtöbb csatorna észlelése érdekében állítson annak helyzetén: helyezze magasra és egy ablak közelébe."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Folytatás"</item>
- <item msgid="4432431398374089710">"Mégse"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Válassza ki a csatlakozás típusát"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Válassza az Antenna lehetőséget, ha a tunerhez külső antenna is csatlakozik. Válassza a Kábel lehetőséget, ha a csatornákat egy kábeles szolgá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="1633072563555330217">"Antenna"</item>
- <item msgid="2445879869338877559">"Kábel"</item>
- <item msgid="597328838068074806">"Nem tudom"</item>
- <item msgid="3613410733017077040">"Csak fejlesztés"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB-csatorna tunerbeállítása"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Ez néhány percet is igénybe vehet"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d csatorna észlelve</item>
- <item quantity="one">%1$d csatorna észlelve</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"CSATORNAKERESÉS LEÁLLÍTÁSA"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Kész"</item>
- <item msgid="496688122303154468">"Keresés újra"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nem található csatorna"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"A kereséskor egy csatornát sem talált a rendszer. Győződjön meg arról, hogy az USB-tuner be van dugva, és csatlakoztatva van egy tévés jelforráshoz.\n\nHa vezeték nélküli műsorszóráshoz használt antennával rendelkezik, állítson annak helyzetén. A leghatékonyabb működés érdekében helyezze az antennát magasra és egy ablak közelébe, majd végezze el újra a keresést."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Keresés újra"</item>
- <item msgid="6784975565864102291">"Kész"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Tévécsatornák keresése"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB-csatorna tunerbeállítása"</string>
-</resources>
diff --git a/usbtuner/res/values-hy-rAM/strings.xml b/usbtuner/res/values-hy-rAM/strings.xml
deleted file mode 100644
index cde49c93..00000000
--- a/usbtuner/res/values-hy-rAM/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB կարգավորիչի հեռուստացույցի մուտք"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Միացնել"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Անջատել"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Սպասեք՝ մինչ որոնումը ավարտվի"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Ընտրեք ալիքի աղբյուրը"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ազդանշան չկա"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Չհաջողվեց համապատասխանեցնել <xliff:g id="CHANNEL_NAME">%s</xliff:g> ալիքին"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Չհաջողվեց որոնել"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB կարգավորիչի ծրագիրը վերջերս թարմացվել է: Նորից որոնեք ալիքները:"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ձայնը անհասանելի է"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Ալիքների կարգավորիչի տեղադրում"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB ալիքների կարգավորիչի տեղադրում"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Համոզվեք, որ USB կարգավորիչը կապակցված է և միացված հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Շարունակել"</item>
- <item msgid="7745727658174773453">"Ոչ հիմա"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Կրկի՞ն կարգավորել ալիքները:"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Այս գործողության արդյունքում կհեռացվեն USB կարգավորիչից ստացված ալիքները և կկատարվի ալիքների նոր որոնում:\n\nՀամոզվեք, որ USB կարգավորիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\n\nԵթերային ալեհավաք օգտագործելիս հնարավոր է՝ անհրաժեշտ լինի կարգավորել դրա դիրքն ու ուղղությունը՝ ավելի շատ ալիքներ գտնելու համար: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ:"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Շարունակել"</item>
- <item msgid="4432431398374089710">"Չեղարկել"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Ընտրեք միացման տեսակը"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Եթե ընդունիչին միացված է արտաքին ալեհավաք, ապա ընտրեք Ալեհավաքը: Եթե ալիքների ազդանշանը ստանում եք մալուխային հեռուստաընկերությունից, ապա ընտրեք Մալուխը: Եթե համոզված չեք, ապա կարող եք որոնել երկու տեսակն էլ, սակայն դա ավելի երկար կտևի:"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Ալեհավաք"</item>
- <item msgid="2445879869338877559">"Մալուխ"</item>
- <item msgid="597328838068074806">"Չգիտեմ"</item>
- <item msgid="3613410733017077040">"Միայն մշակման"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Ալիքների USB կարգավորիչի տեղադրում"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Դա կարող է տևել մի քանի րոպե"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">Գտնվել է %1$d ալիք</item>
- <item quantity="other">Գտնվել է %1$d ալիք</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ԴԱԴԱՐԵՑՆԵԼ ԱԼԻՔՆԵՐԻ ՈՐՈՆՈՒՄԸ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">Գտնվել է %1$d ալիք</item>
- <item quantity="other">Գտնվել է %1$d ալիք</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">Գերազանց է: Ալիքների որոնման արդյունքում գտնվել է %1$d ալիք: Եթե դա բավարար չէ, փորձեք փոխել ալեհավաքի դիրքը և որոնել նորից:</item>
- <item quantity="other">Գերազանց է: Ալիքների որոնման արդյունքում գտնվել է %1$d ալիք: Եթե դա բավարար չէ, փորձեք փոխել ալեհավաքի դիրքը և որոնել նորից:</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Պատրաստ է"</item>
- <item msgid="496688122303154468">"Կրկին որոնել"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Ալիքներ չեն գտնվել"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Որոնման արդյունքում ալիքներ չեն գտնվել: Համոզվեք, որ USB ընդունիչը միացված է ցանցին և հեռուստատեսային ազդանշանի աղբյուրին:\n\nՀեռուստատեսային ալեհավաք օգտագործելիս կարգավորեք դրա դիրքն ու ուղղությունը: Լավագույն արդյունքներն ապահովելու համար այն դրեք բարձր տեղում՝ պատուհանի մոտ, ապա որոնեք նորից:"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Կրկին որոնել"</item>
- <item msgid="6784975565864102291">"Պատրաստ է"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Հեռուստաալիքների որոնում"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB ալիքների կարգավորիչի տեղադրում"</string>
-</resources>
diff --git a/usbtuner/res/values-in/strings.xml b/usbtuner/res/values-in/strings.xml
deleted file mode 100644
index b14710dd..00000000
--- a/usbtuner/res/values-in/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Masukan TV Tuner USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aktif"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Nonaktif"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Harap tunggu sampai pemrosesan selesai"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Pilih sumber saluran Anda"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Tidak Ada Sinyal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Gagal menyetel ke <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Gagal menyetel"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Perangkat lunak tuner USB ini baru saja diperbarui. Pindai ulang saluran Anda."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Audio AC3 tidak tersedia"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Penyiapan penyetel saluran"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Penyiapan penyetel saluran USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Pastikan penyetel USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena, sesuaikan tempat atau arahnya untuk menerima lebih banyak jumlah saluran. Untuk hasil terbaik, letakkan antena di tempat yang tinggi dan dekat jendela."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Lanjutkan"</item>
- <item msgid="7745727658174773453">"Jangan sekarang"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Jalankan lagi penyiapan saluran?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Tindakan ini akan menghapus saluran yang ditemukan dari penyetel USB dan memindai saluran baru lagi.\n\nPastikan penyetel USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena, sesuaikan tempat atau arahnya untuk menerima lebih banyak jumlah saluran. Untuk hasil terbaik, letakkan antena di tempat yang tinggi dan dekat jendela."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Lanjutkan"</item>
- <item msgid="4432431398374089710">"Batal"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Pilih jenis sambungan"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Pilih Antena jika tersedia antena eksternal yang tersambung ke penyetel. Pilih Kabel jika saluran Anda berasal dari penyedia layanan kabel. Jika Anda tidak yakin, kedua jenis tersebut akan dipindai, namun proses ini dapat memakan waktu lebih lama."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Tidak yakin"</item>
- <item msgid="3613410733017077040">"Hanya pengembangan"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Penyiapan tuner saluran USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Proses ini dapat memakan waktu beberapa menit"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d saluran ditemukan</item>
- <item quantity="one">%1$d saluran ditemukan</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"HENTIKAN PEMINDAIAN SALURAN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">Bagus! %1$d saluran ditemukan selama pemindaian saluran. Jika ada yang tidak beres, cobalah menyesuaikan posisi antena dan pindai lagi.</item>
- <item quantity="one">Bagus! %1$d saluran ditemukan selama pemindaian saluran. Jika ada yang tidak beres, cobalah menyesuaikan posisi antena dan pindai lagi.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Selesai"</item>
- <item msgid="496688122303154468">"Pindai lagi"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Tidak ditemukan Saluran"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Pemindaian tidak menemukan saluran apa pun. Pastikan penyetel USB dicolokkan dan tersambung ke sumber sinyal TV.\n\nJika menggunakan antena, sesuaikan penempatan atau arahnya. Untuk hasil terbaik, letakkan antena di tempat yang tinggi dan dekat jendela, lalu pindai lagi."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Pindai lagi"</item>
- <item msgid="6784975565864102291">"Selesai"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Pindai saluran TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Penyiapan tuner saluran USB"</string>
-</resources>
diff --git a/usbtuner/res/values-is-rIS/strings.xml b/usbtuner/res/values-is-rIS/strings.xml
deleted file mode 100644
index 5bdb9e71..00000000
--- a/usbtuner/res/values-is-rIS/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-sjónvarpsmóttakari"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Kveikja"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Slökkva"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Bíddu þar til vinnslu lýkur"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Veldu inntak rása"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ekkert merki"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Mistókst að stilla á <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Mistókst að stilla"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Hugbúnaður USB-sjónvarpsmóttakarans var uppfærður nýlega. Leitaðu aftur að rásum."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-hljóð er ekki í boði"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Uppsetning sjónvarpskorts"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Uppsetning USB-sjónvarpskorts"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Halda áfram"</item>
- <item msgid="7745727658174773453">"Ekki núna"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Viltu keyra rásauppsetningu aftur?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Þ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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Halda áfram"</item>
- <item msgid="4432431398374089710">"Hætta við"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Veldu tengigerðina"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Veldu „Loftnet“ ef utanáliggjandi loftnet er tengt við sjónvarpskortið. Veldu „Kapall“ ef rásir eru í boði í 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="1633072563555330217">"Loftnet"</item>
- <item msgid="2445879869338877559">"Kapall"</item>
- <item msgid="597328838068074806">"Ekki viss"</item>
- <item msgid="3613410733017077040">"Aðeins þróunaraðilar"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Uppsetning USB-sjónvarpsrásakorts"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Þetta getur tekið nokkrar mínútur"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"STÖÐVA RÁSALEIT"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Lokið"</item>
- <item msgid="496688122303154468">"Leita aftur"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Engar rásir fundust"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Leita aftur"</item>
- <item msgid="6784975565864102291">"Lokið"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Skanna eftir sjónvarpsstöðvum"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Uppsetning USB-sjónvarpsrásakorts"</string>
-</resources>
diff --git a/usbtuner/res/values-it/strings.xml b/usbtuner/res/values-it/strings.xml
deleted file mode 100644
index 3c4f7e46..00000000
--- a/usbtuner/res/values-it/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Ingresso TV per sintonizzatore USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Attiva"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Non attiva"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Attendi il completamento dell\'elaborazione"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Seleziona la tua fonte canale"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Nessun segnale"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Sintonizzazione su <xliff:g id="CHANNEL_NAME">%s</xliff:g> non riuscita"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Sintonizzazione non riuscita"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Il software del sintonizzatore USB è stato aggiornato di recente. Effettua nuovamente la scansione dei canali."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Audio AC3 non disponibile"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configurazione del sintonizzatore di canali"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configurazione del sintonizzatore di canali USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continua"</item>
- <item msgid="7745727658174773453">"Non ora"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Eseguire nuovamente la configurazione dei canali?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continua"</item>
- <item msgid="4432431398374089710">"Annulla"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Seleziona il tipo di connessione"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenna"</item>
- <item msgid="2445879869338877559">"Cavo"</item>
- <item msgid="597328838068074806">"Non so"</item>
- <item msgid="3613410733017077040">"Solo per sviluppatori"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configurazione del sintonizzatore di canali USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"L\'operazione potrebbe richiedere alcuni minuti"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d canali trovati</item>
- <item quantity="one">%1$d canale trovato</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"INTERROMPI RICERCA CANALI"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Fine"</item>
- <item msgid="496688122303154468">"Cerca di nuovo"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nessun canale trovato"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Cerca di nuovo"</item>
- <item msgid="6784975565864102291">"Fine"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Cerca canali TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configurazione del sintonizzatore di canali USB"</string>
-</resources>
diff --git a/usbtuner/res/values-iw/strings.xml b/usbtuner/res/values-iw/strings.xml
deleted file mode 100644
index 8e006448..00000000
--- a/usbtuner/res/values-iw/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"‏קלט טלוויזיה של טיונר USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"מופעל"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"כבוי"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"המתן לסיום העיבוד"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"בחר את מקור הערוצים"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"אין אות"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"לא ניתן היה לכוון לערוץ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"הכוונון נכשל"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"‏התוכנה של טיונר ה-USB עודכנה לאחרונה. סרוק מחדש את הערוצים."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"‏אודיו מסוג AC3 אינו זמין"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"הגדרת טיונר ערוצים"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"‏הגדרת טיונר ערוצים בחיבור USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"‏ודא שטיונר USB מחובר להתקן ולמקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שעליך לכוונן את מיקומה או את כיוונה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה וקרוב לחלון."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"המשך"</item>
- <item msgid="7745727658174773453">"לא עכשיו"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"האם להפעיל מחדש את הגדרת הערוצים?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"‏פעולה זו תסיר מטיונר ה-USB את הערוצים שנמצאו, ותבצע סריקה נוספת לאיתור ערוצים חדשים.\n\nודא שטיונר ה-USB מחובר להתקן ולמקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, ייתכן שיהיה עליך לכוונן את מיקומה או את כיוונה כדי לקלוט כמה שיותר ערוצים. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה וקרוב לחלון."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"המשך"</item>
- <item msgid="4432431398374089710">"ביטול"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"בחירת סוג החיבור"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"בחר \'אנטנה\' אם ישנה אנטנה חיצונית שמחוברת לטיונר. בחר \'כבלים\' אם הערוצים מגיעים מספק שירותי כבלים. אם אינך בטוח, שני הסוגים ייסרקו, אך הפעולה עשויה להימשך זמן רב יותר."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"אנטנה"</item>
- <item msgid="2445879869338877559">"כבלים"</item>
- <item msgid="597328838068074806">"לא בטוח"</item>
- <item msgid="3613410733017077040">"פיתוח בלבד"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"‏הגדרת טיונר ערוצים בחיבור USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"פעולה זו עשויה להימשך מספר דקות"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"הפסק סריקת ערוצים"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"בוצע"</item>
- <item msgid="496688122303154468">"סרוק שוב"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"לא נמצאו ערוצים"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"‏לא נמצאו ערוצים בסריקה. ודא שטיונר ה-USB מחובר להתקן ולמקור אות טלוויזיה.\n\nאם אתה משתמש באנטנה אלחוטית, כוונן את מיקומה או את כיוונה. לקבלת התוצאות הטובות ביותר, הצב אותה במקום גבוה וקרוב לחלון וסרוק שוב."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"סרוק שוב"</item>
- <item msgid="6784975565864102291">"בוצע"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"סריקה לאיתור ערוצי טלוויזיה"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"‏הגדרת טיונר ערוצים בחיבור USB"</string>
-</resources>
diff --git a/usbtuner/res/values-ja/strings.xml b/usbtuner/res/values-ja/strings.xml
deleted file mode 100644
index 61a3d7ff..00000000
--- a/usbtuner/res/values-ja/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USBチューナーテレビ入力"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ON"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"OFF"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"処理が完了するまでこのままお待ちください"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"チャンネルソースを選択"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"信号がありません"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"「<xliff:g id="CHANNEL_NAME">%s</xliff:g>」に合わせることができませんでした"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"合わせることができませんでした"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"最近USBチューナーソフトウェアが更新されています。チャンネルを再スキャンしてください。"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 オーディオは利用できません"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"チャンネル チューナーのセットアップ"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB チャンネル チューナーのセットアップ"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"次へ"</item>
- <item msgid="7745727658174773453">"後で"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"もう一度チャンネルを設定しますか?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"USB チューナーで見つかったチャンネルを削除して新しいチャンネルをもう一度スキャンします。\n\nUSB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、チャンネルの多くを受信するためにアンテナの場所や方向の調節が必要になる場合があります。最良の結果を得るには、アンテナを窓際の高い位置に設置します。"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"次へ"</item>
- <item msgid="4432431398374089710">"キャンセル"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"接続タイプの選択"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"チューナーに外部アンテナが接続されている場合は、アンテナを選択してください。ケーブル サービス プロバイダのチャンネルの場合は、ケーブルを選択してください。不明な場合は両方のタイプがスキャンされますが、処理に時間がかかることがあります。"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"アンテナ"</item>
- <item msgid="2445879869338877559">"ケーブル"</item>
- <item msgid="597328838068074806">"不明"</item>
- <item msgid="3613410733017077040">"開発のみ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB チャンネル チューナーのセットアップ"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"この処理には数分かかることがあります"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d 件のチャンネルが見つかりました</item>
- <item quantity="one">%1$d 件のチャンネルが見つかりました</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"チャンネルのスキャンを停止"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d 件のチャンネルが見つかりました</item>
- <item quantity="one">%1$d 件のチャンネルが見つかりました</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">チャンネルのスキャン中に %1$d 件のチャンネルが見つかりました。この件数が正しくないと思われる場合は、アンテナの位置を調整してもう一度スキャンしてください。</item>
- <item quantity="one">チャンネルのスキャン中に %1$d 件のチャンネルが見つかりました。この件数が正しくないと思われる場合は、アンテナの位置を調整してもう一度スキャンしてください。</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"完了"</item>
- <item msgid="496688122303154468">"再スキャン"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"チャンネルが見つかりませんでした"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"スキャンの結果、チャンネルは見つかりませんでした。USB チューナーが電源に接続され、テレビの信号源に接続されていることを確認してください。\n\n無線アンテナを使用している場合は、アンテナの場所や方向を調節してください。最良の結果を得るには、アンテナを窓際の高い位置に設置してから、もう一度スキャンします。"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"再スキャン"</item>
- <item msgid="6784975565864102291">"完了"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"テレビのチャンネルをスキャン"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB チャンネル チューナーのセットアップ"</string>
-</resources>
diff --git a/usbtuner/res/values-ka-rGE/strings.xml b/usbtuner/res/values-ka-rGE/strings.xml
deleted file mode 100644
index cfb7f34f..00000000
--- a/usbtuner/res/values-ka-rGE/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ტუნერის სატელევიზიო შესასვლელი"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ჩართვა"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"გამორთვა"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"გთხოვთ, მოითმინოთ დამუშავების დასრულებამდე"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"აირჩიეთ თქვენი არხის წყარო"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"სიგნალი არ არის"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> არხის დაჭერა ვერ მოხერხდა"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"არხზე გადართვა ვერ მოხერხდა"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ტუნერის პროგრამული უზრუნველყოფა ცოტა ხნის წინ განახლდა. გთხოვთ, ხელახლა დაასკანიროთ არხები."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 აუდიო მიუწვდომელია"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"არხების ტუნერის დაყენება"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"არხების USB ტუნერის დაყენება"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"დარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, არხების მაქსიმალური რაოდენობის მისაღებად შეიძლება დაგჭირდეთ მისი განლაგებისა ან მიმართულების დარეგულირება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"გაგრძელება"</item>
- <item msgid="7745727658174773453">"ახლა არა"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"გსურთ არხების ხელახლა დაყენება?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"ეს მოქმედება ამოშლის USB ტუნერით ნაპოვნ არხებს და ხელახლა მოხდება ახალი არხების სკანირება.\n\nდარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან.\n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, შეიძლება დაგჭირდეთ მისი განლაგებისა ან მიმართულების დარეგულირება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"გაგრძელება"</item>
- <item msgid="4432431398374089710">"გაუქმება"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"აირჩიეთ კავშირის ტიპი"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"აირჩიეთ ანტენა, თუ ტუნერთან მიერთებულია გარე ანტენა. აირჩიეთ საკაბელო, თუ არხებს საკაბელო სერვისის პროვაიდერისგან ღებულობთ. თუ დარწმუნებული არ ხართ, დასკანირდება ორივე ტიპი, მაგრამ ამას შეიძლება მეტი დრო დასჭირდეს."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ანტენა"</item>
- <item msgid="2445879869338877559">"საკაბელო"</item>
- <item msgid="597328838068074806">"არ ვიცი"</item>
- <item msgid="3613410733017077040">"მხოლოდ დეველოპერებისთვის"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"არხების USB ტუნერის დაყენება"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ამას შეიძლება რამდენიმე წუთი დასჭირდეს"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">მოიძებნა %1$d არხი</item>
- <item quantity="one">მოიძებნა %1$d არხი</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"არხების სკანირების შეწყვეტა"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">მოიძებნა %1$d არხი</item>
- <item quantity="one">მოიძებნა %1$d არხი</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">მშვენიერია! არხების სკანირებისას მოიძებნა %1$d არხი. თუ სათანადო შედეგს ვერ მიიღებთ, ცადეთ ანტენის პოზიციის დარეგულირება და ხელახლა დაასკანირეთ.</item>
- <item quantity="one">მშვენიერია! არხების სკანირებისას მოიძებნა %1$d არხი. თუ სათანადო შედეგს ვერ მიიღებთ, ცადეთ ანტენის პოზიციის დარეგულირება და ხელახლა დაასკანირეთ.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"მზადაა"</item>
- <item msgid="496688122303154468">"ხელახლა სკანირება"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"არხები ვერ მოიძებნა"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"სკანირებისას არხები ვერ მოიძებნა. დარწმუნდით, რომ USB ტუნერი ბუდეშია და მიერთებულია სატელევიზიო სიგნალის წყაროსთან. \n\nტერესტრიული ანტენის გამოყენების შემთხვევაში, დაარეგულირეთ მისი განლაგება ან მიმართულება. საუკეთესო შედეგის მისაღებად, განათავსეთ ის სიმაღლეზე, ფანჯარასთან ახლოს და ხელახლა დაასკანირეთ."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"ხელახლა სკანირება"</item>
- <item msgid="6784975565864102291">"მზადაა"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"სატელევიზიო არხების სკანირება"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"არხების USB ტუნერის დაყენება"</string>
-</resources>
diff --git a/usbtuner/res/values-kk-rKZ/strings.xml b/usbtuner/res/values-kk-rKZ/strings.xml
deleted file mode 100644
index 19dbdf7f..00000000
--- a/usbtuner/res/values-kk-rKZ/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB тюнерінің ТД кіріс сигналы"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Қосулы"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Өшірулі"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Өңдеу аяқталғанша күте тұрыңыз"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Арнаңыз дереккөзін таңдау"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Сигнал жоқ"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> арнасына реттелмеді"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Бапталмады"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB тюнерінің бағдарламалық құралы жақында жаңартылды. Арналарды қайта іздеңіз."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 аудиосы қол жетімді емес"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Арна тюнерін орнату"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB арна тюнерін орнату"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB тюнерін жалғанғандығын және ТД сигнал көзіне қосылғандығын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Жалғастыру"</item>
- <item msgid="7745727658174773453">"Қазір емес"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Арналарды қайта орнату қажет пе?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"USB тюнерінде табылған арналар жойылып, жаңа арналар ізделеді.\n\nUSB тюнері жалғанғандығын және ТД сигнал көзіне қосылғандығын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, көптеген арналарды қабылдау үшін оның орнын немесе бағытын реттеу қажет болады. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырыңыз."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Жалғастыру"</item>
- <item msgid="4432431398374089710">"Бас тарту"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Қосылу түрін таңдау"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Тюнерге қосымша антенна қосылған болса, \"Антенна\" опциясын таңдаңыз. Арналар кабельді қызмет провайдерінен алынған болса, \"Кабель\" опциясын таңдаңыз. Нақты білмесеңіз, екі түрі де ізделеді, бірақ бұған көбірек уақыт кетуі мүмкін."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антенна"</item>
- <item msgid="2445879869338877559">"Кабель"</item>
- <item msgid="597328838068074806">"Нақты білмеймін"</item>
- <item msgid="3613410733017077040">"Тек әзірлеу"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB арна тюнерін орнату"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Бұл бірнеше минутты алуы мүмкін"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d арна табылды</item>
- <item quantity="one">%1$d арна табылды</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"АРНА ІЗДЕУДІ ТОҚТАТУ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d арна табылды</item>
- <item quantity="one">%1$d арна табылды</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">Тамаша! Арналарды іздеу кезінде %1$d арна табылды. Жеткіліксіз болса, антеннаның орнын ауыстырып, қайта іздеп көріңіз.</item>
- <item quantity="one">Тамаша! Арналарды іздеу кезінде %1$d арна табылды. Жеткіліксіз болса, антеннаның орнын ауыстырып, қайта іздеп көріңіз.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Орындалды"</item>
- <item msgid="496688122303154468">"Қайта іздеу"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Арналар табылмады"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Іздеу нәтижесінде арналар табылмады. USB тюнері жалғанғандығын және ТД сигнал көзіне қосылғандығын тексеріңіз.\n\nСымсыз антеннаны пайдалансаңыз, орнын немесе бағытын реттеңіз. Ең жақсы нәтижеге қол жеткізу үшін оны жоғарырақ және терезеге жақын орналастырып, қайта іздеп көріңіз."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Қайта іздеу"</item>
- <item msgid="6784975565864102291">"Орындалды"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"ТД арналарын іздеу"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB арна тюнерін орнату"</string>
-</resources>
diff --git a/usbtuner/res/values-km-rKH/strings.xml b/usbtuner/res/values-km-rKH/strings.xml
deleted file mode 100644
index ee8062f1..00000000
--- a/usbtuner/res/values-km-rKH/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"ធាតុបញ្ចូល USB ចាប់ប៉ុស្តិ៍ទូរទស្សន៍"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"បើក"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"បិទ"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"សូមរង់ចាំដើម្បីបញ្ចប់ដំណើរការ"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"ជ្រើសប្រភពប៉ុស្តិ៍របស់អ្នក"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"គ្មានសេវា"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"បានបរាជ័យក្នុងការបើកប៉ុស្តិ៍ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"បរាជ័យក្នុងការចាប់ប៉ុស្តិ៍"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"កម្មវិធី USB ចាប់ប៉ុស្តិ៍បានធ្វើបច្ចុប្បន្នភាពថ្មីៗនេះ។ សូមស្កេនរកប៉ុស្តិ៍ទាំងនេះម្តងទៀត។"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"មិនមានសំឡេង AC3 ទេ"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ការដំឡើងឧបករណ៍ចាប់ប៉ុស្តិ៍"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"ការដំឡើងឧបករណ៍ចាប់ប៉ុស្តិ៍ USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"ផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB ចាប់ប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកប្រហែលជាត្រូវកែសម្រួលទីតាំង និងទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"បន្ត"</item>
- <item msgid="7745727658174773453">"មិនមែនឥឡូវនេះទេ"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ដំណើរការដំឡើងប៉ុស្តិ៍ឡើងវិញឬទេ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"វានឹងយកប៉ុស្តិ៍ដែលបានរកឃើញដោយឧបករណ៍ USB ចាប់ប៉ុស្តិ៍ចេញ ហើយស្កេនរកប៉ុស្តិ៍ថ្មីម្តងទៀត។\n\nផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB ចាប់ប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ អ្នកប្រហែលជាត្រូវសម្រួលទីតាំង និងទិសដៅរបស់វាដើម្បីទទួលបានប៉ុស្តិ៍ច្រើនបំផុត។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច។"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"បន្ត"</item>
- <item msgid="4432431398374089710">"បោះបង់"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"ជ្រើសរើសប្រភេទតភ្ជាប់"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"សូមជ្រើសរើសអង់តែន ប្រសិនបើអ្នកភ្ជាប់អង់តែនខាងក្រៅទៅនឹងឧបករណ៍ចាប់ប៉ុស្តិ៍។ ឬជ្រើសរើសខ្សែកាប ប្រសិនបើប៉ុស្តិ៍របស់អ្នកផ្តល់ដោយក្រុមហ៊ុនផ្តល់សេវាខ្សែកាប។ ប្រសិនបើអ្នកមិនប្រាកដទេ អ្នកអាចជ្រើសរើសប្រភេទទាំងពីរដើម្បីស្កេន ប៉ុន្តែវាអាចចំណាយពេលយូរ។"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"អង់តែន"</item>
- <item msgid="2445879869338877559">"ខ្សែកាប"</item>
- <item msgid="597328838068074806">"មិនប្រាកដ"</item>
- <item msgid="3613410733017077040">"ការអភិវឌ្ឍន៍ប៉ុណ្ណោះ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"ការដំឡើងឧបករណ៍ចាប់ប៉ុស្តិ៍ USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"វាអាចចំណាយពេលច្រើននាទី"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
- <item quantity="one">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"បញ្ឈប់ការស្កេនរកប៉ុស្តិ៍"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
- <item quantity="one">បានរកឃើញប៉ុស្តិ៍ %1$d</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">ល្អណាស់! បានរកឃើញប៉ុស្តិ៍ %1$d អំឡុងពេលស្កេន។ ប្រសិនបើការស្កេននេះរកមិនឃើញប៉ុស្តិ៍ទេ សូមសាកល្បងសម្រួលទីតាំងអង់តែន ហើយស្កេនម្តងទៀត។</item>
- <item quantity="one">ល្អណាស់! បានរកឃើញប៉ុស្តិ៍ %1$d អំឡុងពេលស្កេន។ ប្រសិនបើការស្កេននេះរកមិនឃើញប៉ុស្តិ៍ទេ សូមសាកល្បងសម្រួលទីតាំងអង់តែន ហើយស្កេនម្តងទៀត។</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"រួចរាល់"</item>
- <item msgid="496688122303154468">"ស្កេនម្តងទៀត"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"រកមិនឃើញប៉ុស្តិ៍ទេ"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ការស្កេនរកមិនឃើញប៉ុស្តិ៍ទេ។ ផ្ទៀងផ្ទាត់ថាអ្នកបានដោតឧបករណ៍ USB ចាប់ប៉ុស្តិ៍ និងបានភ្ជាប់ទៅប្រភពសញ្ញាទូរទស្សន៍។\n\nប្រសិនបើអ្នកប្រើអង់តែនឥតខ្សែ សូមសម្រួលទីតាំង និងទិសដៅរបស់វា។ ដើម្បីទទួលបានលទ្ធផលល្អបំផុត សូមដាក់វានៅកន្លែងដែលខ្ពស់ក្បែរបង្អួច ហើយបន្ទាប់មកស្កេនម្តងទៀត។"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"ស្កេនម្តងទៀត"</item>
- <item msgid="6784975565864102291">"រួចរាល់"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"ស្កេនរកប៉ុស្តិ៍ទូរទស្សន៍"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"ការដំឡើងឧបករណ៍ចាប់ប៉ុស្តិ៍ USB"</string>
-</resources>
diff --git a/usbtuner/res/values-kn-rIN/strings.xml b/usbtuner/res/values-kn-rIN/strings.xml
deleted file mode 100644
index 9de7810b..00000000
--- a/usbtuner/res/values-kn-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ಟ್ಯೂನರ್ TV ಇನ್‌ಪುಟ್"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ಆನ್"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ಆಫ್"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವುದನ್ನು ಪೂರೈಸಲು ದಯವಿಟ್ಟು ಕಾಯಿರಿ"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"ನಿಮ್ಮ ಚಾನಲ್ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"ಯಾವುದೇ ಸಂಕೇತವಿಲ್ಲ"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> ಗೆ ಟ್ಯೂನ್ ಮಾಡುವಲ್ಲಿ ವಿಫಲವಾಗಿದೆ"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ಟ್ಯೂನ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ಟ್ಯೂನರ್ ಸಾಫ್ಟ್‌ವೇರ್‍ ಅನ್ನು ಇತ್ತೀಚೆಗೆ ನವೀಕರಿಸಲಾಗಿದೆ. ದಯವಿಟ್ಟು ಚಾನಲ್‌ಗಳನ್ನು ಮರು-ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ಆಡಿಯೊ ಲಭ್ಯವಿಲ್ಲ"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು TV ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಾನ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"ಮುಂದುವರಿಸು"</item>
- <item msgid="7745727658174773453">"ಸದ್ಯಕ್ಕೆ ಬೇಡ"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ಚಾನಲ್ ಸೆಟಪ್ ಅನ್ನು ಮರುರನ್ ಮಾಡುವುದೇ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"USB ಟ್ಯೂನರ್‌ನಿಂದ ಪತ್ತೆ ಮಾಡಲಾದ ಚಾನಲ್‌ಗಳನ್ನು ಇದು ತೆಗೆದುಹಾಕುತ್ತದೆ ಹಾಗೂ ಮತ್ತೆ ಹೊಸ ಚಾನಲ್‌ಗಳಿಗೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತದೆ.\n\nUSB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು TV ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nನೀವು ಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಹೆಚ್ಚಿನ ಚಾನಲ್‌ಗಳನ್ನು ಸ್ವೀಕರಿಸಲು ನೀವು ಅದರ ಸ್ಥಾನ ಅಥವಾ ದಿಕ್ಕನ್ನು ಹೊಂದಿಸಬೇಕಾಗಬಹುದು. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಇದನ್ನು ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"ಮುಂದುವರಿಸು"</item>
- <item msgid="4432431398374089710">"ರದ್ದುಮಾಡು"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"ಸಂಪರ್ಕದ ಪ್ರಕಾರ ಆಯ್ಕೆಮಾಡಿ"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ಟ್ಯೂನರ್‌ಗೆ ಬಾಹ್ಯ ಆಂಟೆನಾವನ್ನು ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದ್ದರೆ ಆಂಟೆನಾ ಆರಿಸಿಕೊಳ್ಳಿ. ನಿಮ್ಮ ಚಾನಲ್‌ಗಳು ಕೇಬಲ್ ಸೇವೆ ಪೂರೈಕೆದಾರರಿಂದ ಬರುತ್ತಿದ್ದರೆ ಕೇಬಲ್ ಆರಿಸಿಕೊಳ್ಳಿ. ನಿಮಗೆ ಯಾವುದು ಎಂದು ಖಚಿತವಿಲ್ಲದಿದ್ದರೆ, ಎರಡೂ ಪ್ರಕಾರಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಲಾಗುತ್ತದೆ, ಆದರೆ ಇದಕ್ಕೆ ಹೆಚ್ಚು ಸಮಯ ತೆಗೆದುಕೊಳ್ಳಬಹುದು."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ಆಂಟೆನಾ"</item>
- <item msgid="2445879869338877559">"ಕೇಬಲ್"</item>
- <item msgid="597328838068074806">"ಖಚಿತವಾಗಿಲ್ಲ"</item>
- <item msgid="3613410733017077040">"ಅಭಿವೃದ್ಧಿ ಮಾತ್ರ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ಇದಕ್ಕೆ ಹಲವಾರು ನಿಮಿಷಗಳನ್ನು ತೆಗೆದುಕೊಳ್ಳಬಹುದು"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
- <item quantity="other">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಮಾಡುವುದನ್ನು ನಿಲ್ಲಿಸು"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
- <item quantity="other">%1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">ಉತ್ತಮ! ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಸಮಯದಲ್ಲಿ %1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ. ಇದು ಸರಿಯಲ್ಲವೆಂದು ತೋರಿದರೆ, ಆಂಟೆನಾ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ.</item>
- <item quantity="other">ಉತ್ತಮ! ಚಾನಲ್ ಸ್ಕ್ಯಾನ್ ಸಮಯದಲ್ಲಿ %1$d ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿವೆ. ಇದು ಸರಿಯಲ್ಲವೆಂದು ತೋರಿದರೆ, ಆಂಟೆನಾ ಸ್ಥಿತಿಯನ್ನು ಹೊಂದಿಸಲು ಪ್ರಯತ್ನಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"ಮುಗಿದಿದೆ"</item>
- <item msgid="496688122303154468">"ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡು"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ಯಾವುದೇ ಚಾನಲ್‌ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ಸ್ಕ್ಯಾನ್ ಯಾವುದೇ ಚಾನಲ್‌ಗಳನ್ನು ಪತ್ತೆ ಮಾಡಿಲ್ಲ. USB ಟ್ಯೂನಲ್ ಅನ್ನು ಪ್ಲಗ್ ಇನ್ ಮಾಡಲಾಗಿದೆಯೇ ಮತ್ತು TV ಸಿಗ್ನಲ್ ಮೂಲಕ್ಕೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆಯೆ ಎಂದು ಪರಿಶೀಲಿಸಿ.\n\nಪ್ರಸಾರದ ಮೂಲಕ ಆಂಟೆನಾ ಬಳಸುತ್ತಿದ್ದರೆ, ಅದರ ಸ್ಥಾನ ಅಥವಾ ದಿಕ್ಕನ್ನು ಸರಿಹೊಂದಿಸಿ. ಉತ್ತಮ ಫಲಿತಾಂಶಗಳಿಗೆ, ಎತ್ತರದಲ್ಲಿ ಮತ್ತು ಕಿಟಕಿಯ ಬಳಿ ಇರಿಸಿ ಹಾಗೂ ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡಿ."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"ಮತ್ತೆ ಸ್ಕ್ಯಾನ್ ಮಾಡು"</item>
- <item msgid="6784975565864102291">"ಮುಗಿದಿದೆ"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV ಚಾನಲ್‌ಗಳನ್ನು ಸ್ಕ್ಯಾನ್ ಮಾಡಿ"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB ಚಾನಲ್ ಟ್ಯೂನರ್ ಸೆಟಪ್"</string>
-</resources>
diff --git a/usbtuner/res/values-ko/strings.xml b/usbtuner/res/values-ko/strings.xml
deleted file mode 100644
index eb213561..00000000
--- a/usbtuner/res/values-ko/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB 튜너 TV 입력"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"사용"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"사용 안함"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"처리가 완료될 때까지 기다려 주세요."</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"채널 소스 선택"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"신호 없음"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>에 맞추지 못함"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"조정 실패"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB 튜너 소프트웨어가 최근 업데이트되었습니다. 채널을 다시 검색하세요."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 오디오를 사용할 수 없습니다."</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"채널 튜너 설정"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB 채널 튜너 설정"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가에 높게 설치하면 가장 좋습니다."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"계속"</item>
- <item msgid="7745727658174773453">"나중에"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"채널 설정을 다시 실행하시겠습니까?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"이 작업을 수행하면 USB 튜너에서 찾은 채널이 삭제되며 새로운 채널을 다시 스캔합니다.\n\nUSB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가에 높게 설치하면 가장 좋습니다."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"계속"</item>
- <item msgid="4432431398374089710">"취소"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"연결 유형 선택"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"튜너에 외부 안테나가 연결된 경우 안테나를 선택하고 케이블 서비스 제공업체에서 채널을 제공하는 경우 케이블을 선택하세요. 잘 모르는 경우 두 가지 유형이 모두 스캔되며 시간이 더 오래 걸릴 수 있습니다."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"안테나"</item>
- <item msgid="2445879869338877559">"케이블"</item>
- <item msgid="597328838068074806">"잘 모르겠음"</item>
- <item msgid="3613410733017077040">"개발자 전용"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB 채널 튜너 설정"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"이 작업은 몇 분 정도 걸릴 수 있습니다."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">채널 %1$d개 발견</item>
- <item quantity="one">채널 %1$d개 발견</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"채널 스캔 중지"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">채널 %1$d개 발견</item>
- <item quantity="one">채널 %1$d개 발견</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">좋습니다. 채널 스캔 중에 채널 %1$d개를 발견했습니다. 맞지 않는 것 같다면 안테나 위치를 조정한 후 다시 스캔하세요.</item>
- <item quantity="one">좋습니다. 채널 스캔 중에 채널 %1$d개를 발견했습니다. 맞지 않는 것 같다면 안테나 위치를 조정한 후 다시 스캔하세요.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"완료"</item>
- <item msgid="496688122303154468">"다시 스캔"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"채널 없음"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"스캔하여 채널을 찾을 수 없습니다. USB 튜너가 전원 및 TV 신호 소스에 연결되어 있는지 확인하세요.\n\n무선 안테나를 사용 중인 경우 안테나 위치나 방향을 조정하세요. 창가에 높게 설치하면 가장 좋습니다. 그런 다음 다시 스캔해 보세요."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"다시 스캔"</item>
- <item msgid="6784975565864102291">"완료"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV 채널 검색"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB 채널 튜너 설정"</string>
-</resources>
diff --git a/usbtuner/res/values-ky-rKG/strings.xml b/usbtuner/res/values-ky-rKG/strings.xml
deleted file mode 100644
index 85c84be4..00000000
--- a/usbtuner/res/values-ky-rKG/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"\"USB тюнер\" түрүндөгү TV киргизме"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Күйүк"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Өчүк"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Иштетүүнү бүтүрүү үчүн күтө туруңуз"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Каналыңыздын булагын тандаңыз"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Сигнал жок"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> каналы кармалган жок"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Канал кармалбай койду"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"\"USB-тюнер\" программасы жакында жаңыртылды. Каналдарды кайрадан кармаңыз."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 аудио жеткиликтүү эмес"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Канал күүлөгүчтү орнотуу"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB канал күүлөгүчүн орнотуу"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Улантуу"</item>
- <item msgid="7745727658174773453">"Азыр эмес"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Каналды орнотуу кайра иштетилсинби?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Ушуну менен USB күүлөгүчтөн табылган каналдар алынып салынып, жаңы каналдар кайра изделет.\n\nUSB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, көпчүлүк каналдарды табуу үчүн анын ордун же багытын тууралашыңыз керек болот. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Улантуу"</item>
- <item msgid="4432431398374089710">"Жокко чыгаруу"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Туташуу түрүн тандаңыз"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Күүлөгүчтө туташтырылган тышкы антенна болсо, Антеннаны тандаңыз. Эгер каналдарыңыз кабелдик кызмат камсыздоочусунан алынса, Кабелди тандаңыз. Эгер так билбесеңиз, эки түрү тең изделет, бирок ал узагыраак созулушу мүмкүн."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антенна"</item>
- <item msgid="2445879869338877559">"Кабель"</item>
- <item msgid="597328838068074806">"Так айта албайм"</item>
- <item msgid="3613410733017077040">"Иштеп чыгуучулар үчүн гана"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB канал тюнер жөндөөсү"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Бир нече мүнөт созулушу мүмкүн"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d канал табылды</item>
- <item quantity="one">%1$d канал табылды</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"КАНАЛ ИЗДӨӨНҮ ТОКТОТУУ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d канал табылды</item>
- <item quantity="one">%1$d канал табылды</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">Сонун! Канал издөө учурунда %1$d канал табылды. Ал туура эмес болсо, антеннанын багытын өзгөртүп, кайра издеп көрүңүз.</item>
- <item quantity="one">Сонун! Канал издөө учурунда %1$d канал табылды. Ал туура эмес болсо, антеннанын багытын өзгөртүп, кайра издеп көрүңүз.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Бүттү"</item>
- <item msgid="496688122303154468">"Кайра издөө"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Эч канал табылган жок"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Издөөдөн эч бир канал табылган жок. USB күүлөгүч сайылып турганын жана сыналгынын сигнал булагына туташтырылганын текшериңиз.\n\nЭгер телеантенна колдонулуп жатса, анын ордун же багытын тууралаңыз. Мыкты кармашы үчүн аны бийик жана терезеге жакын жерге коюп, кайра издеңиз."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Кайра издөө"</item>
- <item msgid="6784975565864102291">"Бүттү"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Сыналгы каналдарын издөө"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB канал тюнер жөндөөсү"</string>
-</resources>
diff --git a/usbtuner/res/values-lo-rLA/strings.xml b/usbtuner/res/values-lo-rLA/strings.xml
deleted file mode 100644
index 8b85bf42..00000000
--- a/usbtuner/res/values-lo-rLA/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"ການປ້ອນເຂົ້າ TV ຂອງປັບ USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"​ເປີດ"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ປິດ"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"ກະ​ລຸ​ນາ​ລໍ​ຖ້າ​ເພື່ອ​ປະ​ມວນ​ຜົນ​ໃຫ້​ສຳ​ເລັດ"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"ເລືອກ​ແຫຼ່ງ​ຊ່ອງ​ຂອງ​ທ່ານ"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"ບໍ່​ມີ​ສັນ​ຍານ"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"ປັບຫາ <xliff:g id="CHANNEL_NAME">%s</xliff:g> ບໍ່​ສຳ​ເລັດ"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ປັບຊ່ອງບໍ່ສຳເລັດ"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"ຊອບ​ແວ​ຕົວປັບ USB ໄດ້​ຮັບ​ການ​ອັບ​ເດດ​ເມື່ອ​ບໍ່​ດົນ​ມາ​ນີ້​ແລ້ວ. ກະ​ລຸ​ນາ​ສະ​ແກນ​ຫາ​ຊ່ອງ​ຄືນ​ໃໝ່."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"ບໍ່​ມີ​ສຽງ AC3 ຢູ່"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ການ​ຕັ້ງ​ເຄື່ອງຮັບສັນຍານ​ຊ່ອງ"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"ການ​ຕັ້ງ​ເຄື່ອງຮັບສັນຍານ​ຊ່ອງ USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"ກວດ​ສອບ​ເບິ່ງ​ເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້​ສຽບ ແລະ ເຊື່ອມ​ຕໍ່​ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວ​ບໍ່.\n\nຖ້າ​ກຳ​ລັງ​ໃຊ້​ເສົາອາກາດ​ຢູ່​ກາງ​ອາ​ກາດ, ທ່ານ​ອາດ​ຈະ​ຕ້ອງ​ໄດ້ປັບ​ຕຳແໜ່ງທີ່​ຕັ້ງ ຫຼື ທິດ​ທາງ​ຂອງ​ມັນ. ເພື່ອ​ໃຫ້​ໄດ້​ຜົນ​ດີ​ທີ່ສຸດ, ໃຫ້ວາງ​ມັນ​ໄວ້​ສູງ ແລະ ໃກ້​ກັບ​ປ່ອງ​ຢ້ຽມ."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"​ສືບ​ຕໍ່"</item>
- <item msgid="7745727658174773453">"ບໍ່​ແມ່ນ​ດຽວ​ນີ້"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ເຮັດ​ການ​ຕັ້ງ​ຊ່ອງ​ຄືນໃໝ່ບໍ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"ອັນ​ນີ້​ຈະ​ເອົາ​ຊ່ອງ​ທີ່​ພົບ​​ອອກ​ໄປ​ຈາກ​ເຄື່ອງຮັບສັນຍານ USB ແລະ ສະ​ແກນ​ຫາ​ຊ່ອງ​ໃໝ່​ອີກ.\n\nກວດ​ສອບ​ເບິ່ງ​ເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້​ສຽບ ແລະ ເຊື່ອມ​ຕໍ່​ກັບແຫຼ່ງສັນຍານໂທລະພາບແລ້ວ​ບໍ່.\n\nຖ້າ​ກຳ​ລັງ​ໃຊ້​ເສົາອາກາດ​ຢູ່​ກາງ​ອາ​ກາດ, ທ່ານ​ອາດ​ຈະ​ຕ້ອງ​ໄດ້ປັບ​ຕຳແໜ່ງທີ່ຕັ້ງ ຫຼື ທິດ​ທາງ​ຂອງ​ມັນ. ເພື່ອ​ໃຫ້​ໄດ້​ຜົນ​ດີທີ່ສຸດ, ໃຫ້ວາງ​ມັນ​ໄວ້ບ່ອນ​ສູງ ແລະ ໃກ້​ກັບ​ປ່ອງ​ຢ້ຽມ."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"​ສືບ​ຕໍ່"</item>
- <item msgid="4432431398374089710">"​ຍົກ​ເລີກ"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"ເລືອກ​ປະ​ເພດ​ການ​ເຊື່ອມ​ຕໍ່"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ເລືອກ​ເສົາອາກາດ ຖ້າ​ມີ​ເສົາອາກາດນອກທີ່ເຊື່ອມ​ຕໍ່​ກັບ​ເຄື່ອງຮັບສັນຍານ​. ເລືອກ​ສາຍເຄເບິ້ນ ຖ້າ​ຊ່ອງ​ຂອງ​ທ່ານ​ມາ​ຈາກ​ຜູ້ໃຫ້ບໍລິການສາຍເຄເບິ້ນ. ຖ້າ​ທ່ານ​ບໍ່​ແນ່​ໃຈ, ຈະ​ມີ​ການ​ສະ​ແກນ​ທັງ​ສອງ​ປະ​ເພດ, ແຕ່​ອັນ​ນີ້​ຈະ​ໃຊ້​ເວ​ລາ​ດົນ​ກ່​ວາ."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ເສົາອາກາດ"</item>
- <item msgid="2445879869338877559">"ສາຍຕໍ່"</item>
- <item msgid="597328838068074806">"ບໍ່​ແນ່​ໃຈ"</item>
- <item msgid="3613410733017077040">"ການ​ພັດ​ທະ​ນາ​ເທົ່າ​ນັ້ນ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"ການ​ຕັ້ງ​ເຄື່ອງຮັບສັນຍານ​ຊ່ອງ USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ອັນ​ນີ້​ອາດ​ຈະ​ໃຊ້​ເວ​ລາ​ຫຼາຍ​ນາ​ທີ"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">ພົບ %1$d ຊ່ອງ</item>
- <item quantity="one">ພົບ %1$d ຊ່ອງ</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ຢຸດ​ການ​ສະ​ແກນ​ຊ່ອງ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">ພົບ %1$d ຊ່ອງ</item>
- <item quantity="one">ພົບ %1$d ຊ່ອງ</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">ດີຫຼາຍ! ພົບ %1$d ຊ່ອງໃນລະຫວ່າງການສະແກນຫາຊ່ອງ. ຖ້ານີ້ປາກົດວ່າບໍ່ຖືກຕ້ອງ, ໃຫ້ລອງປັບຕຳແໜ່ງເສົາອາກາດ ແລ້ວສະແກນໃໝ່.</item>
- <item quantity="one">ດີຫຼາຍ! ພົບ %1$d ຊ່ອງໃນລະຫວ່າງການສະແກນຫາຊ່ອງ. ຖ້ານີ້ປາກົດວ່າບໍ່ຖືກຕ້ອງ, ໃຫ້ລອງປັບຕຳແໜ່ງເສົາອາກາດ ແລ້ວສະແກນໃໝ່.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"ສຳເລັດແລ້ວ"</item>
- <item msgid="496688122303154468">"ສະແກນອີກ"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ບໍ່​ພົບ​ຊ່ອງ​ໃດ"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ການ​ສະ​ແກນ​ບໍ່​ພົບ​ຊ່ອງ​ໃດ. ກວດ​ສອບ​ເບິ່ງ​ເຄື່ອງຮັບສັນຍານ USB ວ່າ ໄດ້​ສຽບ ແລະ ເຊື່ອມ​ຕໍ່​ກັບ​ແຫຼ່ງສັນຍານໂທລະພາບແລ້ວ​ບໍ່.\n\nຖ້າ​ກຳ​ລັງ​ໃຊ້​ເສົາອາກາດ​ຢູ່​ກາງ​ອາ​ກາດ, ປັບ​ການ​ຕັ້ງ ຫຼື ທິດ​ທາງ​ຂອງ​ມັນ. ເພື່ອ​ໃຫ້​ໄດ້​ຜົນ​ດີ​ຂຶ້ນ, ວາງ​ມັນ​ໄວ້​ສູງ ແລະ ໃກ້​ກັບ​ປ່ອງ​ຢ້ຽມ ແລະ ສະ​ແກນ​ອີກ."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"ສະແກນອີກ"</item>
- <item msgid="6784975565864102291">"ສຳເລັດແລ້ວ"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"ສະ​ແກນ​ຫາ​ຊ່ອງໂທລະພາບ"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"ການ​ຕັ້ງ​ເຄື່ອງຮັບສັນຍານ​ຊ່ອງ USB"</string>
-</resources>
diff --git a/usbtuner/res/values-lt/strings.xml b/usbtuner/res/values-lt/strings.xml
deleted file mode 100644
index 33ddddf3..00000000
--- a/usbtuner/res/values-lt/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB derintuvo TV įvestis"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Įjungta"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Išjungta"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Palaukite, kol baigsis apdorojimas"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Pasirinkite kanalo šaltinį"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Nėra signalo"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Nepavyko įjungti kanalo „<xliff:g id="CHANNEL_NAME">%s</xliff:g>“"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Nepavyko suderinti"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB derintuvo programinė įranga buvo neseniai atnaujinta. Iš naujo nuskaitykite kanalus."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 garso įrašas nepasiekiamas"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanalų imtuvo sąranka"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB kanalų imtuvo sąranka"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Į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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Tęsti"</item>
- <item msgid="7745727658174773453">"Ne dabar"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Iš naujo vykdyti kanalų sąranką?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Tęsti"</item>
- <item msgid="4432431398374089710">"Atšaukti"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Pasirinkti ryšio tipą"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Pasirinkite „Antena“, jei prie derintuvo 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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Laidas"</item>
- <item msgid="597328838068074806">"Nežinau"</item>
- <item msgid="3613410733017077040">"Tik kūrimas"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB kanalų imtuvo sąranka"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Tai gali užtrukti kelias minutes"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"SUSTABDYTI KANALŲ NUSKAITYMĄ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Atlikta"</item>
- <item msgid="496688122303154468">"Nuskaityti dar kartą"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nerasta kanalų"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Nuskaitant nerasta kanalų. Patvirtinkite, kad 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Nuskaityti dar kartą"</item>
- <item msgid="6784975565864102291">"Atlikta"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Vykdykite TV kanalų nuskaitymą"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB kanalų imtuvo sąranka"</string>
-</resources>
diff --git a/usbtuner/res/values-lv/strings.xml b/usbtuner/res/values-lv/strings.xml
deleted file mode 100644
index 38d806ac..00000000
--- a/usbtuner/res/values-lv/strings.xml
+++ /dev/null
@@ -1,81 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB kanālu meklētāja TV ieeja"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Ieslēgta"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Izslēgta"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Lūdzu, uzgaidiet, līdz tiks pabeigta apstrāde."</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Atlasiet kanāla avotu"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Nav signāla"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Neizdevās atrast kanālu <xliff:g id="CHANNEL_NAME">%s</xliff:g>."</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Neizdevās atrast"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Nesen tika atjaunināta USB kanālu meklētāja programmatūra. Lūdzu, atkārtoti meklējiet kanālus."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 audio nav pieejams."</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanālu meklētāja iestatīšana"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB kanālu meklētāja iestatīšana"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Pārbaudiet, vai USB kanālu meklētājs ir pievienots strāvas avotam un televizora signāla avotam.\n\nJa izmantojat ārējo antenu, pielāgojiet tās novietojumu un virzienu. Lai vislabāk uztvertu signālu, novietojiet antenu augstu pie loga, un atkārtojiet kanālu meklēšanu."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Turpināt"</item>
- <item msgid="7745727658174773453">"Vēlāk"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Vai atkārtot kanālu iestatīšanu?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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 televizora signāla avotam.\n\nJa izmantojat ārējo antenu, pielāgojiet tās novietojumu un virzienu. Lai vislabāk uztvertu signālu, novietojiet antenu augstu pie loga, un atkārtojiet kanālu meklēšanu."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Turpināt"</item>
- <item msgid="4432431398374089710">"Atcelt"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Atlasiet savienojuma veidu"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabelis"</item>
- <item msgid="597328838068074806">"Neesmu pārliecināts"</item>
- <item msgid="3613410733017077040">"Tikai izstrāde"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB kanālu meklētāja iestatīšana"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Tas var ilgt vairākas minūtes."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="zero">Tika atrasti %1$d kanāli.</item>
- <item quantity="one">Tika atrasts %1$d kanāls.</item>
- <item quantity="other">Tika atrasti %1$d kanāli.</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"APTURĒT KANĀLU MEKLĒŠANU"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Gatavs"</item>
- <item msgid="496688122303154468">"Meklēt vēlreiz"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Netika atrasts neviens kanāls"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Netika atrasts neviens kanāls. Pārbaudiet, vai USB kanālu meklētājs ir pievienots strāvas avotam un televizora signāla avotam.\n\nJa izmantojat ārējo antenu, pielāgojiet tās novietojumu un virzienu. Lai vislabāk uztvertu signālu, novietojiet antenu augstu pie loga, un atkārtojiet kanālu meklēšanu."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Meklēt vēlreiz"</item>
- <item msgid="6784975565864102291">"Gatavs"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV kanālu meklēšana"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB kanālu meklētāja iestatīšana"</string>
-</resources>
diff --git a/usbtuner/res/values-mk-rMK/strings.xml b/usbtuner/res/values-mk-rMK/strings.xml
deleted file mode 100644
index 5c4b0f1f..00000000
--- a/usbtuner/res/values-mk-rMK/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"ТВ-влез за USB-приемник"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Вклучено"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Исклучено"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Почекајте да заврши обработувањето"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Изберете го изворот на канал"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Нема сигнал"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Не успеа да избере <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Не успеа да се синхронизира"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Софтверот на USB-приемникот неодамна е ажуриран. Скенирајте ги каналите повторно."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Аудио преку AC3 не е достапно"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Поставување приемник на канали"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Поставување УСБ-приемник на канали"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Потврдете дека УСБ-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Продолжи"</item>
- <item msgid="7745727658174773453">"Не сега"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Да се изврши поставувањето на каналите повторно?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Ова ќе ги отстрани каналите од УСБ-приемникот и ќе скенира за нови канали повторно.\n\nПотврдете дека УСБ-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Продолжи"</item>
- <item msgid="4432431398374089710">"Откажи"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Изберете го типот врска"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Изберете Антена ако има надворешна антена поврзана со приемникот. Изберете Кабел ако каналите ви ги обезбедува кабелски давател на услуги. Ако не сте сигурни, и двата типа ќе се скенираат, но тоа може да трае подолго."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антена"</item>
- <item msgid="2445879869338877559">"Кабел"</item>
- <item msgid="597328838068074806">"Не сум сигурен"</item>
- <item msgid="3613410733017077040">"Само за програмери"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Поставување на УСБ-приемникот за канали"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Ова може да трае неколку минути"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">Пронајден е %1$d канал</item>
- <item quantity="other">Пронајдени се %1$d канали</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"СОПРИ ГО СКЕНИРАЊЕТО КАНАЛИ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">Пронајден е %1$d канал</item>
- <item quantity="other">Пронајдени се %1$d канали</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">Фино! Пронајден е %1$d канал во текот на скенирањето канали. Ако се чини дека тоа не е во ред, обидете се со приспособување на позицијата на антената и скенирајте повторно.</item>
- <item quantity="other">Фино! Пронајдени се %1$d канали во текот на скенирањето канали. Ако се чини дека тоа не е во ред, обидете се со приспособување на позицијата на антената и скенирајте повторно.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Готово"</item>
- <item msgid="496688122303154468">"Скенирај пак"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Не се пронајдени канали"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Скенирањето не пронајде ниеден канал. Потврдете дека УСБ-приемникот е приклучен и поврзан со изворот на ТВ сигналот.\n\nАко користите безжична антена, приспособете ја поставеноста или насоката. За најдобри резултати, поставете ја високо и во близина на прозорец и скенирајте повторно."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Скенирај пак"</item>
- <item msgid="6784975565864102291">"Готово"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Скенирај ТВ-канали"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Поставување на УСБ-приемникот за канали"</string>
-</resources>
diff --git a/usbtuner/res/values-ml-rIN/strings.xml b/usbtuner/res/values-ml-rIN/strings.xml
deleted file mode 100644
index 5fa3e638..00000000
--- a/usbtuner/res/values-ml-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ട്യൂണർ ടിവി ഇൻപുട്ട്"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ഓണാക്കുക"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ഓഫാക്കുക"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"പ്രോസസ്സുചെയ്യൽ പൂർത്തിയാകുന്നത് വരെ കാത്തിരിക്കുക"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"നിങ്ങളുടെ ചാനൽ ഉറവിടം തിരഞ്ഞെടുക്കുക"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"സിഗ്‌നൽ ഇല്ല"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> ട്യൂൺ ചെയ്യുന്നതിന് പരാജയപ്പെട്ടു"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ട്യൂൺ ചെയ്യുന്നത് പരാജയപ്പെട്ടു"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ട്യൂണർ സോഫ്‌റ്റ്‌വെയർ അടുത്തിടെ അപ്‌ഡേറ്റുചെയ്‌തു. ചാനലുകൾ വീണ്ടും സ്‌കാൻ ചെയ്യുക."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ഓഡിയോ ലഭ്യമല്ല"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB ചാനൽ ട്യൂണർ സജ്ജമാക്കൽ"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"തുടരുക"</item>
- <item msgid="7745727658174773453">"ഇപ്പോൾ വേണ്ട"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ചാനൽ സജ്ജീകരിക്കൽ വീണ്ടും റൺ ചെയ്യണോ?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"USB ട്യൂണറിൽ നിന്ന് കണ്ടെത്തിയ ചാനലുകളെ ഇത് നീക്കംചെയ്യും, പുതിയ ചാനലുകൾക്കായി വീണ്ടും സ്കാൻ ചെയ്യും.\n\nസ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, പരമാവധി ചാനലുകൾ ലഭിക്കുന്നതിന്, അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കേണ്ടി വരാം. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിക്കുക."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"തുടരുക"</item>
- <item msgid="4432431398374089710">"റദ്ദാക്കുക"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"കണക്ഷൻ തരം തിരഞ്ഞെടുക്കുക"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ട്യൂണറിലേക്ക് കണക്റ്റുചെയ്തിട്ടുള്ള ഒരു ബാഹ്യ ആന്റിന ഉണ്ടെങ്കിൽ, ആന്റിന തിരഞ്ഞെടുക്കുക. കേബിൾ സേവന ദാതാവിൽ നിന്നാണ് ചാനലുകൾ ലഭിക്കുന്നതെങ്കിൽ കേബിൾ തിരഞ്ഞെടുക്കുക. ഏതാണ് ഉള്ളതെന്ന് നിങ്ങൾക്ക് അറിയില്ലെങ്കിൽ, രണ്ട് രീതികളും സ്കാൻ ചെയ്യപ്പെടും, എന്നാലിതിന് സമയമെടുക്കും."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ആന്റിന"</item>
- <item msgid="2445879869338877559">"കേബിള്‍"</item>
- <item msgid="597328838068074806">"ഉറപ്പില്ല"</item>
- <item msgid="3613410733017077040">"ഡെവലപ്പ്‌മെന്റ് മാത്രം"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"ഇതിന് കുറച്ച് സമയം എടുത്തേക്കാം"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d ചാനലുകൾ കണ്ടെത്തി</item>
- <item quantity="one">%1$d ചാനൽ കണ്ടെത്തി</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ചാനൽ സ്കാൻ ചെയ്യുന്നത് നിർത്തുക"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d ചാനലുകൾ കണ്ടെത്തി</item>
- <item quantity="one">%1$d ചാനൽ കണ്ടെത്തി</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">കൊള്ളാം! ചാനൽ സ്കാൻ വേളയിൽ %1$d ചാനലുകൾ കണ്ടെത്തി. എന്തോ കുഴപ്പമുണ്ടെന്ന് തോന്നുന്നുവെങ്കിൽ, ആന്റിനയുടെ ദിശ ക്രമീകരിച്ചുകൊണ്ട് വീണ്ടും സ്കാൻ ചെയ്യുക.</item>
- <item quantity="one">കൊള്ളാം! ചാനൽ സ്കാൻ വേളയിൽ %1$d ചാനൽ കണ്ടെത്തി. എന്തോ കുഴപ്പമുണ്ടെന്ന് തോന്നുന്നുവെങ്കിൽ, ആന്റിനയുടെ ദിശ ക്രമീകരിച്ചുകൊണ്ട് വീണ്ടും സ്കാൻ ചെയ്യുക.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"പൂർത്തിയായി"</item>
- <item msgid="496688122303154468">"വീണ്ടും സ്കാൻ ചെയ്യുക"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"സ്കാൻ ചെയ്തപ്പോൾ ചാനലുകളൊന്നും കണ്ടെത്തിയില്ല. USB ട്യൂണർ പ്ലഗിൻ ചെയ്തിട്ടുണ്ടെന്നും ഒരു ടിവി സിഗ്നൽ ഉറവിടത്തിലേക്ക് കണക്റ്റുചെയ്തിട്ടുണ്ടെന്നും ഉറപ്പാക്കുക.\n\nഉയരത്തിൽ വയ്ക്കേണ്ട തരത്തിലുള്ള ആന്റിനയാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ അതിന്റെ ഇരിപ്പോ ദിശയോ ക്രമീകരിക്കുക. മികച്ച ഫലം ലഭിക്കാൻ, കുറച്ചുകൂടി ഉയരത്തിലും ജാലകത്തിന് അരികിലായും അത് സ്ഥാപിച്ച് വീണ്ടും സ്കാൻ ചെയ്യുക."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"വീണ്ടും സ്കാൻ ചെയ്യുക"</item>
- <item msgid="6784975565864102291">"പൂർത്തിയായി"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"ടിവി ചാനലുകൾക്കായി സ്കാൻ ചെയ്യുക"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB ചാനൽ ട്യൂണർ സജ്ജമാക്കല്‍‌"</string>
-</resources>
diff --git a/usbtuner/res/values-mn-rMN/strings.xml b/usbtuner/res/values-mn-rMN/strings.xml
deleted file mode 100644
index 0940b9d4..00000000
--- a/usbtuner/res/values-mn-rMN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TB Оролт"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Идэвхтэй"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Идэвхгүй"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Дуустал нь хүлээнэ үү"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Сувгийн эх үүсвэрээ сонгоно уу"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Дохио алга"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> тааруулж чадсангүй"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Тааруулж чадсангүй"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB-ын тааруулагч програмыг саяхан шинэчилсэн байна. Сувгийг дахин шинжилнэ үү."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 аудио байхгүй байна"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Суваг тохируулагчийн тохиргоо"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB суваг тохируулагчийн тохиргоо"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB тохируулагчийг залгасан бөгөөд ТВ дохио үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв антен хэрэглэж байгаа бол антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй бөгөөд дахин хайна уу."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Үргэлжлүүлэх"</item>
- <item msgid="7745727658174773453">"Одоо биш"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Сувгийн тохиргоог дахин тохируулна уу."</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Энэ нь USB тохируулагчаас олдсон сувгийг устгаад, шинэ суваг хайх болно.\n\nUSB тохируулагчийг залгасан бөгөөд ТВ дохио үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв антен хэрэглэж байгаа бол антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй бөгөөд дахин хайгаад үзнэ үү."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Үргэлжлүүлэх"</item>
- <item msgid="4432431398374089710">"Цуцлах"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Холболтын төрлөө сонгох"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Тохируулагчтай нэмэлт антен холбосон бол Антенаа сонгоно уу. Хэрэв сувгаа кабелийн үйлчилгээ эрхлэгчээс авдаг бол Кабелиа сонгоно уу. Хэрэв та итгэлгүй байвал энэ хоёр төрлийг хоёуланг нь хайх боловч хэсэг хугацаа зарцуулах болно."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антен"</item>
- <item msgid="2445879869338877559">"Кабель"</item>
- <item msgid="597328838068074806">"Итгэлгүй байна"</item>
- <item msgid="3613410733017077040">"Зөвхөн хөгжүүлэлтийн хэрэгцээнд"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB суваг тохируулагчийн тохиргоо"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Хэдэн минут болж магадгүй"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d суваг олдлоо</item>
- <item quantity="one">%1$d суваг олдлоо</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"СУВАГ ХАЙХЫГ ЗОГСООХ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d суваг олдлоо</item>
- <item quantity="one">%1$d суваг олдлоо</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other"> Сайн байна! Суваг хайх явцад %1$d суваг олдлоо. Хэрэв илүү олон суваг хайх бол антенаа хөдөлгөөд, дахин хайна уу.</item>
- <item quantity="one">Сайн байна! Суваг хайх явцад %1$d суваг олдсон байна. Хэрэв илүү олон суваг хайх бол антенаа хөдөлгөөд, дахин хайна уу.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Дууссан"</item>
- <item msgid="496688122303154468">"Дахин хайх"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Ямар ч суваг олдоогүй"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Хайгаад суваг олдсонгүй. USB тохируулагчийг залгасан бөгөөд ТВ дохио үүсвэртэй холбосон эсэхээ шалгана уу.\n\nХэрэв антен хэрэглэж байгаа бол антены байршлыг өөрчилнө үү. Антеныг өндөрт, цонхны дэргэд байрлуулах нь илүү үр дүнтэй бөгөөд дахин хайгаад үзнэ үү."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Дахин хайх"</item>
- <item msgid="6784975565864102291">"Дууссан"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TВ-н суваг хайх"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB суваг тохируулагчийн тохиргоо"</string>
-</resources>
diff --git a/usbtuner/res/values-mr-rIN/strings.xml b/usbtuner/res/values-mr-rIN/strings.xml
deleted file mode 100644
index ea1ffadb..00000000
--- a/usbtuner/res/values-mr-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ट्यूनर TV इनपुट"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"चालू"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"बंद"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"कृपया प्रक्रिया पूर्ण होण्‍याची प्रतीक्षा करा"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"आपला चॅनेल स्त्रोत निवडा"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"सिग्नल नाही"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> वर ट्यून करण्यात अयशस्वी"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ट्यून करण्यात अयशस्वी झाले"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ट्यूनर सॉफ्टवेअर अलीकडेच अद्यतनित केले गेले आहे. कृपया चॅनेल पुन्हा स्कॅन करा."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ऑडिओ उपलब्ध नाही"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"चॅनेल ट्यूनर सेटअप"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB चॅनेल ट्यूनर सेटअप"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB ट्यूनर प्लगिन आणि TV सिग्नल स्त्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अॅंटेना वापरत असल्‍यास, बहुतांश चॅनेल मिळविण्‍यासाठी त्याचे स्थान नियोजन किंवा दिशा निर्देश समायोजित करण्‍याची आपल्‍याला आवश्‍यकता असू शकते. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"सुरू ठेवा"</item>
- <item msgid="7745727658174773453">"सध्या नाही"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"चॅनेल सेटअप वर परत यायचे?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"यामुळे USB ट्यूनर वरून शोधलेले चॅनेल काढले जातील आणि नवीन चॅनेलसाठी पुन्हा स्कॅन केले जाईल.\n\n USB ट्यूनर प्लगिन आणि TV सिग्नल स्त्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अॅंटेना वापरत असल्‍यास, बहुतांश चॅनेल मिळविण्‍यासाठी त्याचे स्थान नियोजन किंवा दिशा निर्देश समायोजित करण्‍याची आपल्‍याला आवश्‍यकता असू शकते. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"सुरू ठेवा"</item>
- <item msgid="4432431398374089710">"रद्द करा"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"कनेक्‍शन प्रकार निवडा"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ट्यूनरशी बाह्य अॅंटेना कनेक्‍ट केला असल्‍यास अॅंटेना निवडा. आपले चॅनेल केबल सेवा प्रदात्याकडून येत असल्‍यास केबल निवडा. आपल्‍याला खात्री नसल्‍यास, दोन्ही प्रकार स्कॅन केले जातील परंतु यास वेळ लागेल."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"अँटेना"</item>
- <item msgid="2445879869338877559">"केबल"</item>
- <item msgid="597328838068074806">"खात्री नाही"</item>
- <item msgid="3613410733017077040">"केवळ विकास"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB चॅनेल ट्यूनर सेटअप"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"यास अनेक मिनिटे लागू शकतात"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d चॅनेल आढळले</item>
- <item quantity="other">%1$d चॅनेल आढळले</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"चॅनेल स्कॅन करणे थांबवा"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$d चॅनेल आढळले</item>
- <item quantity="other">%1$d चॅनेल आढळले</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">छान! चॅनेल स्कॅन करताना %1$d चॅनेल आढळले. हे योग्य वाटत नसल्यास, अॅंटेना स्थिती समायोजित करून पहा आणि पुन्हा स्कॅन करा.</item>
- <item quantity="other">छान! चॅनेल स्कॅन करताना %1$d चॅनेल आढळले. हे योग्य वाटत नसल्यास, अॅंटेना स्थिती समायोजित करून पहा आणि पुन्हा स्कॅन करा.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"पूर्ण झाले"</item>
- <item msgid="496688122303154468">"पुन्हा स्कॅन करा"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"कोणतेही चॅनेल आढळले नाही"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"स्कॅन करताना कोणतेही चॅनेल आढळले नाही. USB ट्यूनर प्लगिन आणि TV सिग्नल स्त्रोताशी कनेक्‍ट केले आहे हे सत्यापित करा.\n\nबिनतारी अॅंटेना वापरत असल्‍यास, त्याचे स्थान नियोजन किंवा दिशा निर्देश समायोजित करा. उत्कृष्‍ट परिणामांसाठी, त्‍यास उंचावर आणि खिडकी जवळ ठेवा आणि पुन्हा स्कॅन करा."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"पुन्हा स्कॅन करा"</item>
- <item msgid="6784975565864102291">"पूर्ण झाले"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"टीव्ही चॅनेलसाठी स्कॅन करा"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB चॅनेल ट्यूनर सेटअप"</string>
-</resources>
diff --git a/usbtuner/res/values-ms-rMY/strings.xml b/usbtuner/res/values-ms-rMY/strings.xml
deleted file mode 100644
index c124bfac..00000000
--- a/usbtuner/res/values-ms-rMY/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Input TV Penala USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Hidupkan"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Dimatikan"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Sila tunggu sehingga proses selesai"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Pilih sumber saluran anda"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Tiada Isyarat"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Gagal menala ke <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Gagal menala"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Perisian penala USB telah dikemas kini baru-baru ini. Sila imbas semula saluran."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Audio AC3 tidak tersedia"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Persediaan penala saluran"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Persediaan penala saluran USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Teruskan"</item>
- <item msgid="7745727658174773453">"Bukan sekarang"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Jalankan semula persediaan saluran?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Teruskan"</item>
- <item msgid="4432431398374089710">"Batal"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Pilih jenis sambungan"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Tidak pasti"</item>
- <item msgid="3613410733017077040">"Pembangunan sahaja"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Persediaan penala saluran USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Proses ini mungkin mengambil masa beberapa minit"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d saluran ditemui</item>
- <item quantity="one">%1$d saluran ditemui</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"HENTIKAN PENGIMBASAN SALURAN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Selesai"</item>
- <item msgid="496688122303154468">"Imbas lagi"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Tiada Saluran ditemui"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Imbas lagi"</item>
- <item msgid="6784975565864102291">"Selesai"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Imbas saluran TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Persediaan penala saluran USB"</string>
-</resources>
diff --git a/usbtuner/res/values-my-rMM/strings.xml b/usbtuner/res/values-my-rMM/strings.xml
deleted file mode 100644
index 0cdd574f..00000000
--- a/usbtuner/res/values-my-rMM/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ချိန်ညှိစက် တီဗီ အဝင်"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ဖွင့်ပါ"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ပိတ်ပါ"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"စီမံ​ဆာင်ရွက်မှု ပြီးဆုံးမှာကို စောင့်ပါ။"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"သင့်လှိုင်းအရင်းမြစ်ကို ရွေးရန်"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"ထုတ်လွှင့်မှု အချက်မပြ"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> သို့ချိန်ခြင်း မအောင်မြင်ပါ"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ချိန်ညှိမရခဲ့ပါ"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ချိန်ညှိစက်ဆော့ဖ်ဝဲ မကြာသေးမှီက အသစ်မွမ်းမံခဲ့သည်။ လိုင်းများကို ကျေးဇူးပြု၍ ထပ်မံရှာဖွေပါ။"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 အသံ မရှိပါ"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ချန်နယ် တျူနား စဖွင့်သတ်မှတ်ပါ"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB ချန်နယ် တျူနား စဖွင့်သတ်မှတ်ပါ"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB တျူနားကို ပလပ်ထိုးထားကာ TV အချက်ပေးမှု ရင်းမြစ်ဆီကို ချိတ်ဆက်ထားကြောင်း စစ်ကြည့်ပါ။\n\n ဝေဟင် ဧရီယာကို သုံးနေလျှင်၊ ၎င်း၏ ထားရှိသည့် နေရာ သို့မဟုတ် ဦးလှည့်ထားမှုကို ညှိကြည့်ပါ။ အကောင်းဆုံး ရလဒ်များ အတွက်၊ မြင့်သည့်နေရာ နှင့် ပြူတင်းပေါက် အနီးမှာ ထားကြည့်လျက် ထပ် စမ်းကြည့်ပါ။"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"ဆက်လုပ်ပါ"</item>
- <item msgid="7745727658174773453">"မလုပ်သေးပါ"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ချန်နယ် သတ်မှတ်မှုကို ပြန်လုပ်ရမလား?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"ဒီလိုလုပ်မှုက USB တျူနားမှ ရှာတွေ့သည့် ချန်နယ်များကို ဖယ်ရှားပစ်လိုက်ကာ ချန်နယ် အသစ်များကို ထပ်ရှာပါမည်။\n\n USB တျူနားကို ပလပ်ထိုးထားကာ TV အချက်ပေးမှု ရင်းမြစ်ဆီကို ချိတ်ဆက်ထားကြောင်း စစ်ကြည့်ပါ။\n\n ဝေဟင် ဧရီယာကို သုံးနေလျှင်၊ ၎င်း၏ ထားရှိသည့် နေရာ သို့မဟုတ် ဦးလှည့်ထားမှုကို ညှိကြည့်ပါ။ အကောင်းဆုံး ရလဒ်များ အတွက်၊ မြင့်သည့်နေရာ နှင့် ပြူတင်းပေါက် အနီးမှာ ထားကြည့်လျက် ထပ် စမ်းကြည့်ပါ။"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"ဆက်လုပ်ပါ"</item>
- <item msgid="4432431398374089710">"ဖျက်သိမ်းပါ"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"ချိတ်ဆက်မှု အမျိုးအစားကို ရွေးပါ"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"တျူနားနှင့် ချိတ်ဆက်ထားသည့် အပြင် ဧရီယာရှိပါက၊ ဧရီယာကို ရွေးပါ။ သင်၏ ချန်နယ်များမှာ ကြိုးတီဗီ ဝန်ဆောင်ပေးသူထံမှ ဖြစ်လျှင်၊ ကြိုးတီဗီကို ရွေးပါ။ မသေချာလျှင်၊ နှစ်မျိုးစလုံးကို ရစကင် လုပ်သွားမည်ဖြစ်ရာ ပိုကြာနိုင်ပါသည်။"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ဧရီယာ"</item>
- <item msgid="2445879869338877559">"ကြိုးတီဗီ"</item>
- <item msgid="597328838068074806">"မသေချာပါ။"</item>
- <item msgid="3613410733017077040">"စမ်းသပ်မှုအတွက်သာ"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB ချန်နယ် တျူနား စဖွင့်သတ်မှတ်ပါ"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"မိနစ် အနည်းငယ်ကြာနိုင်ပါသည်"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">ချန်နယ် %1$d ခုတွေ့သည်</item>
- <item quantity="one">ချန်နယ် %1$d ခုတွေ့သည်</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ချန်နယ် ရှာဖွေမှုကို ရပ်စဲပါ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">ချန်နယ် %1$d ခုတွေ့သည်</item>
- <item quantity="one">ချန်နယ် %1$d ခုတွေ့သည်</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">ကောင်းသည်။ ချန်နယ်ရှာဖွေချိန်တွင် ချန်နယ် %1$d ခုတွေ့သည်။ မှားယွင်းနေသည်ဟုထင်လျှင်၊ အင်တန်နာတည်နေရာကို ချိန်ညှိကာ ထပ်ရှာပါ။</item>
- <item quantity="one">ကောင်းသည်။ ချန်နယ်ရှာဖွေချိန်တွင် ချန်နယ် %1$d ခုတွေ့သည်။ မှားယွင်းနေသည်ဟုထင်လျှင်၊ အင်တန်နာတည်နေရာကို ချိန်ညှိကာ ထပ်ရှာပါ။</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"လုပ်ပြီး"</item>
- <item msgid="496688122303154468">"ထပ်ပြီး စကင်လုပ်ပါ"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ချန်နယ် တစ်ခုမှ မတွေ့ပါ။"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"စကင် လုပ်မှုက ချန်နယ် တခုကိုမှ မတွေ့ခဲ့ပါ။ USB တျူနားကို ပလပ်ထိုးထားကာ TV အချက်ပေးမှု ရင်းမြစ်ဆီကို ချိတ်ဆက်ထားကြောင်း စစ်ကြည့်ပါ။ \n\n ဝေဟင် ဧရီယာကို သုံးနေလျှင်၊ ၎င်း၏ ထားရှိသည့် နေရာ သို့မဟုတ် ဦးလှည့်ထားမှုကို ညှိကြည့်ပါ။ အကောင်းဆုံး ရလဒ်များ အတွက်၊ မြင့်သည့်နေရာ နှင့် ပြူတင်းပေါက် အနီးမှာ ထားကြည့်လျက် ထပ် စမ်းကြည့်ပါ။"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"ထပ်ပြီး စကင်လုပ်ပါ"</item>
- <item msgid="6784975565864102291">"လုပ်ပြီး"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV ချန်နယ်များကို စကင် လုပ်ပါ"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB ချန်နယ် တျူနား စဖွင့်သတ်မှတ်ပါ"</string>
-</resources>
diff --git a/usbtuner/res/values-nb/strings.xml b/usbtuner/res/values-nb/strings.xml
deleted file mode 100644
index 20856f51..00000000
--- a/usbtuner/res/values-nb/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"TV-inngang på USB-tuneren"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"På"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Av"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Vent til behandlingen er fullført"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Velg en kanalkilde"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ikke noe signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kunne ikke bytte kanal til <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Kunne ikke bytte kanal"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Programvaren for USB-tuneren er nylig blitt oppdatert. Du må skanne kanalene på nytt."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-lyd er ikke tilgjengelig"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Konfigurasjon av kanaler via mottakeren"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Konfigurasjon av kanaler via USB-mottakeren"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Bekreft at USB-mottakeren er plugget i og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, må du kanskje justere posisjonen eller retningen for å motta flest mulig kanaler. For best resultat, plassér antennen høyt og i nærheten av et vindu."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Fortsett"</item>
- <item msgid="7745727658174773453">"Ikke nå"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Vil kjøre kanalkonfigurasjonen på nytt?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Dette fjerner kanaler som er funnet via USB-mottakeren, og skanner på nytt etter nye kanaler.\n\nBekreft at USB-mottakeren er plugget i og koblet til en TV-signalkilde.\n\nHvis du buker en trådløs antenne, må du kanskje justere posisjonen eller retningen for å motta flest mulig kanaler. For best resultat, plassér antennen høyt og i nærheten av et vindu."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Fortsett"</item>
- <item msgid="4432431398374089710">"Avbryt"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Velg tilkoblingstypen"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Velg «Antenne» hvis mottakeren 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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Vet ikke"</item>
- <item msgid="3613410733017077040">"Bare for utvikling"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Konfigurasjon av kanaler via USB-mottakeren"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Dette kan ta flere minutter"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"STOPP KANALSKANNINGEN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Ferdig"</item>
- <item msgid="496688122303154468">"Skann på nytt"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Fant ingen kanaler"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Fant ingen kanaler under skanningen. Bekreft at USB-mottakeren er plugget i og koblet til en TV-signalkilde.\n\nHvis du bruker en trådløs antenne, kan du justere posisjonene eller retningen. For best resultat, plassér 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="6593834378620684951">"Skann på nytt"</item>
- <item msgid="6784975565864102291">"Ferdig"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Skann etter TV-kanaler"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Konfigurasjon av kanaler via USB-mottakeren"</string>
-</resources>
diff --git a/usbtuner/res/values-ne-rNP/strings.xml b/usbtuner/res/values-ne-rNP/strings.xml
deleted file mode 100644
index f1588e4c..00000000
--- a/usbtuner/res/values-ne-rNP/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TV इनपुट"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"अन गर्नुहोस्"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"अफ गर्नुहोस्"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"कृपया प्रक्रिया पूर्ण हुन प्रतीक्षा गर्नुहोस्"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"तपाईँको च्यानल स्रोत छान्‍नुहोस्"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"कुनै सिग्‍नल छैन"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> लाई ट्युन गर्न असफल"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ट्युन गर्न विफल"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB tuner सफ्टवेयर हालै अद्यावधिक गरिएको छ। च्यानलहरू पुन:खोजी गर्नुहोस्।"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 अडियो उपलब्ध छैन"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"च्यानल ट्युनर सेटअप"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB च्यानल ट्युनर सेटअप"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB ट्युनर प्लगइन रहेको र एक TV सिग्नल स्रोतमा जडान गरिएको प्रमाणिकरण गर्नुहोस्\n\nयदि एक हावाबाट एन्टेनाको प्रयोग भइरहेको छ भने, तपाईँलाई धेरै च्यानलहरू प्राप्त गर्न यसको स्थान वा दिशा समायोजन गर्न आवश्यक हुन सक्छ। सबैभन्दा राम्रो परिणामहरूको लागि, यसलाई उच्च स्थानमा र एक झ्यालको नजिक राख्नुहोस्।"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"जारी राख्नुहोस्"</item>
- <item msgid="7745727658174773453">"अहिले होइन"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"च्यानल सेटअप पुनः सञ्चालन गर्ने हो?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"यसले USB ट्युनरबाट फेला परेका च्यानलहरू हटाउनेछ र नयाँ च्यानलहरूको लागि फेरि स्क्यान गर्नेछ। \n\nUSB ट्युनर प्लगइन रहेको र एक TV सिग्नल स्रोतमा जडान गरिएको प्रमाणिकरण गर्नुहोस्।\n\nयदि एक हावाबाट एन्टेनाको प्रयोग भइरहेको छ भने, तपाईँलाई धेरै च्यानलहरू प्राप्त गर्न यसको स्थान वा दिशा समायोजन गर्न आवश्यक हुन सक्छ। सबैभन्दा राम्रो परिणामहरूको लागि, यसलाई उच्च स्थानमा र एक झ्यालको नजिक राख्नुहोस्।"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"जारी राख्नुहोस्"</item>
- <item msgid="4432431398374089710">"रद्द गर्नुहोस्"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"जडान प्रकार चयन गर्नुहोस्"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"यदि ट्युनरमा त्यहाँ बाह्य एन्टेना जडान गरिएको छ भने एन्टेना छनौट गर्नुहोस्। यदि तपाईँको च्यानलहरू केबल सेवा प्रदायकबाट आउँछ भने केबल छनौट गर्नुहोस्। यदि तपाईँ निश्चित हुनुहुन्न भने, दुवै प्रकारहरू स्क्यान गरिने छन्, तर यसले लामो समय लिन सक्छ।"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"एन्टेना"</item>
- <item msgid="2445879869338877559">"केबल"</item>
- <item msgid="597328838068074806">"निश्चित छैन"</item>
- <item msgid="3613410733017077040">"विकास मात्र"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB च्यानल ट्युनर सेटअप"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"यसले धेरै मिनेट लिन सक्छ"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d च्यानलहरू फेला पर्यो</item>
- <item quantity="one">%1$d च्यानल फेला पर्यो</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"च्यानल स्क्यान गर्न रोक्नुहोस्"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d च्यानलहरू फेला पर्यो</item>
- <item quantity="one">%1$d च्यानल फेला पर्यो</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">राम्रो! च्यानल स्क्यान गर्दा %1$d च्यानलहरू फेला पर्यो। यदि त्यो सही जस्तो देखिन्न भने, एन्टेनाको स्थान समायोजन गर्ने प्रयास गर्नुहोस् र फेरि स्क्यान गर्नुहोस्।</item>
- <item quantity="one">राम्रो! च्यानल स्क्यान गर्दा %1$d च्यानल फेला पर्यो। यदि त्यो सही जस्तो देखिन्न भने, एन्टेनाको स्थान समायोजन गर्ने प्रयास गर्नुहोस् र फेरि स्क्यान गर्नुहोस्।</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"सम्पन्न भयो"</item>
- <item msgid="496688122303154468">"फेरि स्क्यान गर्नुहोस्"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"कुनै च्यानलहरू फेला परेनन्।"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"स्क्यानले कुनै पनि च्यानलहरू फेला पारेनन्। USB ट्युनर प्लगइन रहेको र एक TV सिग्नल स्रोतमा जडान गरिएको प्रमाणिकरण गर्नुहोस्। \n\nयदि एक हावाबाट एन्टेनाको प्रयोग भइरहेको छ भने, यसको स्थान वा दिशा समायोजन गर्नुहोस्। सबै भन्दा राम्रो परिणामको लागि, यसलाई उच्च स्थानमा र एक झ्यालको नजिक राख्नुहोस् र फेरि स्क्यान गर्नुहोस्।"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"फेरि स्क्यान गर्नुहोस्"</item>
- <item msgid="6784975565864102291">"सम्पन्न भयो"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV च्यानलहरूका लागि स्क्यान गर्नुहोस्"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB च्यानल ट्युनर सेटअप"</string>
-</resources>
diff --git a/usbtuner/res/values-nl/strings.xml b/usbtuner/res/values-nl/strings.xml
deleted file mode 100644
index 1e7cbe13..00000000
--- a/usbtuner/res/values-nl/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Tv-ingang van USB-tuner"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aan"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Uit"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Wacht tot het proces is voltooid"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecteer je kanaalbron"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Geen signaal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Kan niet afstemmen op <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Kan niet afstemmen"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"De software van de USB-tuner is recent geüpdatet. Scan de zenders opnieuw."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-audio niet beschikbaar"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuratie van kanaaltuner"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuratie van USB-kanaaltuner"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Doorgaan"</item>
- <item msgid="7745727658174773453">"Niet nu"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kanaalconfiguratie opnieuw uitvoeren?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Doorgaan"</item>
- <item msgid="4432431398374089710">"Annuleren"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Het verbindingstype selecteren"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenne"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Niet zeker"</item>
- <item msgid="3613410733017077040">"Alleen ontwikkeling"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Zenderconfiguratie van USB-tuner"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Dit kan enkele minuten duren"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d kanalen gevonden</item>
- <item quantity="one">%1$d kanaal gevonden</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"KANAALSCAN STOPPEN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Gereed"</item>
- <item msgid="496688122303154468">"Opnieuw scannen"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Geen kanalen gevonden"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"De scan heeft geen kanalen gevonden. 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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Opnieuw scannen"</item>
- <item msgid="6784975565864102291">"Gereed"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Scannen naar tv-zenders"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Zenderconfiguratie van USB-tuner"</string>
-</resources>
diff --git a/usbtuner/res/values-pl/strings.xml b/usbtuner/res/values-pl/strings.xml
deleted file mode 100644
index 43f1bdc7..00000000
--- a/usbtuner/res/values-pl/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Wejście TV tunera USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Włącz"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Wyłącz"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Poczekaj na zakończenie przetwarzania"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Wybierz źródło kanału"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Brak sygnału"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Nie udało się nastroić kanału <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Nie udało się dostroić kanału"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Oprogramowanie tunera USB zostało niedawno zaktualizowane. Przeskanuj kanały ponownie."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Dźwięk AC3 jest niedostępny"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Konfiguracja kanałów w tunerze"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Konfiguracja kanałów w tunerze USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Kontynuuj"</item>
- <item msgid="7745727658174773453">"Nie teraz"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Skonfigurować ponownie kanały?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Kontynuuj"</item>
- <item msgid="4432431398374089710">"Anuluj"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Wybierz typ połączenia"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Jeśli do tunera jest podłączona zewnętrzna antena, wybierz opcję Antena. Jeśli kanały są dostarczane przez dostawcę 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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Telewizja kablowa"</item>
- <item msgid="597328838068074806">"Nie mam pewności"</item>
- <item msgid="3613410733017077040">"Tylko dla programistów"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Konfiguracja kanałów w tunerze USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Może to potrwać kilka minut"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ZATRZYMAJ SKANOWANIE W POSZUKIWANIU KANAŁÓW"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Gotowe"</item>
- <item msgid="496688122303154468">"Skanuj ponownie"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nie znaleziono kanałów"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Skanuj ponownie"</item>
- <item msgid="6784975565864102291">"Gotowe"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Wyszukaj kanały TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Konfiguracja kanałów w tunerze USB"</string>
-</resources>
diff --git a/usbtuner/res/values-pt-rPT/strings.xml b/usbtuner/res/values-pt-rPT/strings.xml
deleted file mode 100644
index ec51b909..00000000
--- a/usbtuner/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada de TV do sintonizador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Ativado"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desativado"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Aguarde enquanto o processamento é terminado"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecionar a origem do canal"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sem sinal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Falha ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Falha ao sintonizar"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"O software do sintonizador USB foi atualizado recentemente. Procure novamente os canais."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Áudio AC3 não disponível"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuração do sintonizador de canais"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuração do sintonizador de canais USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Verifique se o sintonizador USB está ativado e ligado a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena de rede sem fios, pode ter de ajustar a posição ou a direção respetivas para receber a maioria dos canais. Para melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuar"</item>
- <item msgid="7745727658174773453">"Agora não"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Pretende executar novamente a configuração de canais?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Esta ação remove os canais encontrados do sintonizador USB e procura novamente canais novos.\n\nVerifique se o sintonizador USB está ativado e ligado a uma fonte de sinal da TV.\n\nSe estiver a utilizar uma antena de rede sem fios, pode ter de ajustar a posição ou a direção respetivas para receber a maioria dos canais. Para melhores resultados, coloque-a num ponto alto e junto a uma janela."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuar"</item>
- <item msgid="4432431398374089710">"Cancelar"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selecionar o tipo de ligação"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cabo"</item>
- <item msgid="597328838068074806">"Não tenho a certeza"</item>
- <item msgid="3613410733017077040">"Apenas para desenvolvimento"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuração do sintonizador de canais USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Esta operação pode demorar vários minutos"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d canais encontrados</item>
- <item quantity="one">%1$d canal encontrado</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"INTERROMPER A PROCURA DE CANAIS"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d canais encontrados</item>
- <item quantity="one">%1$d canal encontrado</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">Boa! Foram encontrados %1$d canais 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="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>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Concluído"</item>
- <item msgid="496688122303154468">"Procurar novamente"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Não foram encontrados canais"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Não forem 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 de rede sem fios, ajuste a posição ou a direção respetivas. Para melhores resultados, coloque-a num ponto alto e junto a uma janela e procure novamente."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Procurar novamente"</item>
- <item msgid="6784975565864102291">"Concluído"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Procurar canais de TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuração do sintonizador de canais USB"</string>
-</resources>
diff --git a/usbtuner/res/values-pt/strings.xml b/usbtuner/res/values-pt/strings.xml
deleted file mode 100644
index 6d51c770..00000000
--- a/usbtuner/res/values-pt/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Entrada de TV por sintonizador USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Ativar"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Desativar"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Aguarde a conclusão do processamento"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selecione a fonte do canal"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sem sinal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Falha ao sintonizar <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Falha ao sintonizar"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"O software do sintonizador USB foi atualizado recentemente. Procure novamente os canais."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"O áudio AC3 não está disponível"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configuração do sintonizador de canais"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configuração do sintonizador de canais USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuar"</item>
- <item msgid="7745727658174773453">"Agora não"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Executar novamente a configuração de canais?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Esta 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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuar"</item>
- <item msgid="4432431398374089710">"Cancelar"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selecione o tipo de conexão"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Cabo"</item>
- <item msgid="597328838068074806">"Não tenho certeza"</item>
- <item msgid="3613410733017077040">"Somente desenvolvimento"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configuração do sintonizador de canais USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Isso pode demorar alguns minutos"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d canais encontrados</item>
- <item quantity="other">%1$d canais encontrados</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"INTERROMPER PROCURA DE CANAIS"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">%1$d canais encontrados</item>
- <item quantity="other">%1$d canais encontrados</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">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>
- <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="979481834388007277">"Concluído"</item>
- <item msgid="496688122303154468">"Procurar novamente"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nenhum canal encontrado"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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 direção dela. Para ter resultados melhores, coloque-a em um lugar alto e perto de uma janela e procure novamente."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Procurar novamente"</item>
- <item msgid="6784975565864102291">"Concluído"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Procurar canais de TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configuração do sintonizador de canais USB"</string>
-</resources>
diff --git a/usbtuner/res/values-ro/strings.xml b/usbtuner/res/values-ro/strings.xml
deleted file mode 100644
index 2773348d..00000000
--- a/usbtuner/res/values-ro/strings.xml
+++ /dev/null
@@ -1,81 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Intrare TV de tip tuner USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Activați"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Dezactivați"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Așteptați ca procesarea să fie finalizată"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Selectați sursa canalului"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Fără semnal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Canalul <xliff:g id="CHANNEL_NAME">%s</xliff:g> nu a putut fi selectat"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Canalul nu a putut fi selectat"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Software-ul tunerului USB a fost actualizat recent. Scanați din nou canalele."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Conținutul audio AC3 nu este disponibil"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Configurarea tunerului de canale"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Configurarea tunerului de canale USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Continuați"</item>
- <item msgid="7745727658174773453">"Nu acum"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Efectuați din nou configurarea canalelor?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Continuați"</item>
- <item msgid="4432431398374089710">"Anulați"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Selectați tipul de conexiune"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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ă procesul poate fi mai îndelungat."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Antenă"</item>
- <item msgid="2445879869338877559">"Cablu"</item>
- <item msgid="597328838068074806">"Nu știu sigur"</item>
- <item msgid="3613410733017077040">"Numai pentru dezvoltare"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Configurarea tunerului de canale USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Poate dura mai multe minute"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"OPRIȚI SCANAREA CANALELOR"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="few">Excelent! La scanarea canalelor s-au găsit %1$d canale. Dacă vi se pare că ceva nu este în regulă, încercați să 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ă, încercați să 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ă, încercați să ajustați poziția antenei și repetați scanarea.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Terminat"</item>
- <item msgid="496688122303154468">"Scanați din nou"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nu s-au găsit canale"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Scanați din nou"</item>
- <item msgid="6784975565864102291">"Terminat"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Căutați canale TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Configurarea tunerului de canale USB"</string>
-</resources>
diff --git a/usbtuner/res/values-ru/strings.xml b/usbtuner/res/values-ru/strings.xml
deleted file mode 100644
index 2f3aab50..00000000
--- a/usbtuner/res/values-ru/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"ТВ-вход типа \"USB-тюнер\""</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Вкл."</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Выкл."</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Дождитесь окончания обработки"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Выберите источник каналов"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Нет сигнала"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Не удалось настроиться на канал \"<xliff:g id="CHANNEL_NAME">%s</xliff:g>\""</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Не удалось настроиться на канал"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Программное обеспечение USB-тюнера было обновлено. Выполните сканирование каналов повторно."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Аудио в формате AC3 недоступно"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Настройка тюнера"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Настройка USB-тюнера"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Убедитесь, что USB-тюнер включен в сеть и подсоединен к источнику телевизионного сигнала.\n\nЕсли используется телеантенна, попробуйте переставить ее повыше и ближе к окну."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Продолжить"</item>
- <item msgid="7745727658174773453">"Не сейчас"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Настроить каналы заново?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Все каналы, найденные с помощью USB-тюнера, будут удалены, и сканирование начнется заново.\n\nУбедитесь, что USB-тюнер включен в сеть и подсоединен к источнику телевизионного сигнала.\n\nЕсли используется телеантенна, попробуйте переставить ее повыше и ближе к окну."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Продолжить"</item>
- <item msgid="4432431398374089710">"Отмена"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Выберите тип соединения"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Если к тюнеру подключена внешняя антенна, выберите вариант \"Антенна\". Если вы ищете кабельные каналы, выберите \"Кабельное ТВ\". Если вы затрудняетесь ответить, мы будем искать оба типа каналов, но это займет чуть больше времени."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антенна"</item>
- <item msgid="2445879869338877559">"Кабельное ТВ"</item>
- <item msgid="597328838068074806">"Не знаю"</item>
- <item msgid="3613410733017077040">"Только для разработки"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Настройка USB-тюнера"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Это может занять несколько минут."</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"НЕ СКАНИРОВАТЬ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Готово"</item>
- <item msgid="496688122303154468">"Сканировать повторно"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Каналы не найдены"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"К сожалению, каналы не найдены. Убедитесь, что USB-тюнер включен в сеть и подсоединен к источнику телевизионного сигнала.\n\nЕсли используется телеантенна, попробуйте переставить ее повыше и ближе к окну. Затем повторите сканирование."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Сканировать повторно"</item>
- <item msgid="6784975565864102291">"Готово"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Сканирование телеканалов"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Настройка USB-тюнера"</string>
-</resources>
diff --git a/usbtuner/res/values-si-rLK/strings.xml b/usbtuner/res/values-si-rLK/strings.xml
deleted file mode 100644
index b8968e6e..00000000
--- a/usbtuner/res/values-si-rLK/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB සුසරක රූපවාහිනී ආදානය"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ක්‍රියාත්මක කරන්න"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ක්‍රියාවිරහිත කරන්න"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"සැකසීම අවසන් කිරීමට කරුණාකර රැඳී සිටින්න"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"ඔබගේ නාලිකා මූලය තෝරන්න"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"සංඥාවක් නැත"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> වෙත සුසර කිරීම අසාර්ථක විය"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"සුසර කිරීම අසාර්ථක විය"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB සුසරක මෘදුකාංගය පසුගියදා යාවත්කාලීන කර ඇත. නැවත නාලිකා පරිලෝකනය කරන්න."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ශ්‍රව්‍ය ලබාගත නොහැකිය"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"නාලිකා සුසරක පිහිටුවීම"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB නාලිකා සුසරක පිහිටුවීම"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"දිගටම කර ගෙන යන්න"</item>
- <item msgid="7745727658174773453">"දැන් නොවේ"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"නාලිකා පිහිටුවීම නැවත ධාවනය කරන්නද?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"මෙය USB සුසරකය වෙතින් සොයා ගත් නාලිකා ඉවත් කරනු ඇති අතර නව නාලිකා සඳහා නැවත ස්කෑන් කරනු ඇත.\n\nUSB සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, ඔබට බොහොමයක් නාලිකා ලබා ගැනීමට පිහිටීම හෝ දිශාව සීරුමාරු කිරීමට අවශ්‍ය විය හැකිය. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබන්න."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"දිගටම කර ගෙන යන්න"</item>
- <item msgid="4432431398374089710">"අවලංගු කරන්න"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"සබැඳුම් ආකාරය තෝරන්න"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"සුසරකයට බාහිර අැන්ටනාවක් සම්බන්ධ කර ඇත්නම්, ඇන්ටනාව තෝරන්න. ඔබේ නාලිකා කේබල් සැපයුම්කරුවෙකු වෙතින් පැමිණෙන්නේ නම් කේබලය තෝරන්න. ඔබට ස්ථිර නැත්නම්, ආකාර දෙකම ස්කෑන් කරනු ඇත, නමුත් මෙයට වැඩි කාලයක් ගත විය හැකිය."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ඇන්ටනාව"</item>
- <item msgid="2445879869338877559">"කේබලය"</item>
- <item msgid="597328838068074806">"ස්ථිර නැත"</item>
- <item msgid="3613410733017077040">"සංවර්ධනයට පමණි"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB නාලිකා සුසරක පිහිටුවීම"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"මෙය මිනිත්තු කිහිපයක් ගත හැකිය"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
- <item quantity="other">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"නාලිකා ස්කෑන් කිරීම නවත්වන්න"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="one">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
- <item quantity="other">නාලිකා %1$dක් සොයා ගන්නා ලදී</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="one">කදිමයි! නාලිකා ස්කෑන් කිරීම අතරතුර නාලිකා %1$dක් සොයා ගන්නා ලදී. මෙය නිවැරදි බව නොපෙනේ නම්, ඇන්ටනාවේ පිහිටීම සීරුමාරු කිරීම උත්සාහ කර නැවත ස්කෑන් කරන්න.</item>
- <item quantity="other">කදිමයි! නාලිකා ස්කෑන් කිරීම අතරතුර නාලිකා %1$dක් සොයා ගන්නා ලදී. මෙය නිවැරදි බව නොපෙනේ නම්, ඇන්ටනාවේ පිහිටීම සීරුමාරු කිරීම උත්සාහ කර නැවත ස්කෑන් කරන්න.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"නිමයි"</item>
- <item msgid="496688122303154468">"නැවත ස්කෑන් කරන්න"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"නාලිකා හමු නොවීය"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ස්කෑන් කිරීමට නාලිකා කිසිවක් හමු නොවීය. USB සුසරකය පේනුගත කර ඇති බව සහ TV සංඥා මූලාශ්‍රයකට සම්බන්ධ කර ඇති බව තහවුරු කර ගන්න.\n\nගුවන-ඔස්සේ ඇන්ටනාවක් භාවිත කරන්නේ නම්, පිහිටීම හෝ දිශාව සීරුමාරු කරන්න. හොඳම ප්‍රතිඵල සඳහා, එය ඉහළින් සහ කවුළුවක් ආසන්නයේ තබා නැවත ස්කෑන් කරන්න."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"නැවත ස්කෑන් කරන්න"</item>
- <item msgid="6784975565864102291">"නිමයි"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV නාලිකා සඳහා ස්කෑන් කරන්න"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB නාලිකා සුසරක පිහිටුවීම"</string>
-</resources>
diff --git a/usbtuner/res/values-sk/strings.xml b/usbtuner/res/values-sk/strings.xml
deleted file mode 100644
index b2673ac9..00000000
--- a/usbtuner/res/values-sk/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"TV vstup pre tuner USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Zapnúť"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Vypnúť"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Počkajte, kým bude spracovanie dokončené"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Vyberte zdroj kanála"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Žiadny signál"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Nepodarilo sa naladiť kanál <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Ladenie zlyhalo"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Softvér tunera USB bol nedávno aktualizovaný. Znova preskenujte kanály."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Zvuk AC3 nie je k dispozícii"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Nastavenie tunera kanálov"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Nastavenie tunera kanálov USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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. Umožní to získať 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="4294610848989236664">"Pokračovať"</item>
- <item msgid="7745727658174773453">"Teraz nie"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Znova spustiť nastavenie kanálov?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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. Umožní to získať 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="8729290093918719208">"Pokračovať"</item>
- <item msgid="4432431398374089710">"Zrušiť"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Výber typu pripojenia"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Anténa"</item>
- <item msgid="2445879869338877559">"Kábel"</item>
- <item msgid="597328838068074806">"Neviem to isto"</item>
- <item msgid="3613410733017077040">"Iba pre vývojárov"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Nastavenie kanálov tunera USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Môže to trvať niekoľko minút"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ZASTAVIŤ HĽADANIE KANÁLOV"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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 spustite hľadanie znova.</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 spustite hľadanie znova.</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 spustite hľadanie znova.</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 spustite hľadanie znova.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"Hotovo"</item>
- <item msgid="496688122303154468">"Hľadať znova"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Nenašli sa žiadne kanály"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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 hľadanie spustite znova."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Hľadať znova"</item>
- <item msgid="6784975565864102291">"Hotovo"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Vyhľadajte televízne kanály"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Nastavenie kanálov tunera USB"</string>
-</resources>
diff --git a/usbtuner/res/values-sl/strings.xml b/usbtuner/res/values-sl/strings.xml
deleted file mode 100644
index 9fc197a3..00000000
--- a/usbtuner/res/values-sl/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"TV-vhod za sprejemnik USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Vklop"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Izklop"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Počakajte, da se dokonča obdelava"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Izberite vir kanalov"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ni signala"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Iskanje kanala <xliff:g id="CHANNEL_NAME">%s</xliff:g> ni uspelo"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Nastavitev kanala ni uspela"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Programska oprema sprejemnika USB je bila nedavno posodobljena. Znova poiščite kanale."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Zvok AC3 ni na voljo"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Nastavitev sprejemnika kanalov"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Nastavitev sprejemnika kanalov USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Naprej"</item>
- <item msgid="7745727658174773453">"Ne zdaj"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Ali želite znova zagnati namestitev kanala?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Naprej"</item>
- <item msgid="4432431398374089710">"Prekliči"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Izbira vrste povezave"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kabelska televizija"</item>
- <item msgid="597328838068074806">"Ne vem"</item>
- <item msgid="3613410733017077040">"Samo za razvoj"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Nastavitev sprejemnika kanalov USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"To lahko traja nekaj minut"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"USTAVI ISKANJE KANALOV"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Končano"</item>
- <item msgid="496688122303154468">"Znova išči"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Ni najdenih kanalov"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Znova išči"</item>
- <item msgid="6784975565864102291">"Končano"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Iskanje TV-kanalov"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Nastavitev sprejemnika kanalov USB"</string>
-</resources>
diff --git a/usbtuner/res/values-sr/strings.xml b/usbtuner/res/values-sr/strings.xml
deleted file mode 100644
index ade9584e..00000000
--- a/usbtuner/res/values-sr/strings.xml
+++ /dev/null
@@ -1,81 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"ТВ улаз USB тјунера"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Укључи"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Искључи"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Сачекајте да се заврши обрада"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Изаберите извор канала"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Нема сигнала"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Укључивање канала <xliff:g id="CHANNEL_NAME">%s</xliff:g> није успело"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Канал није пронађен"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Софтвер USB тјунера је недавно ажуриран. Скенирајте канале поново."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 аудио није доступан"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Подешавање тјунера за канале"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Подешавање USB тјунера за канале"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Проверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда ће бити потребно да подесите њен положај или смер да би регистровала већину канала. Најбоље резултате ћете добити ако је поставите високо у близини прозора."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Настави"</item>
- <item msgid="7745727658174773453">"Не сада"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Желите ли да поново покренете подешавање канала?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"На овај начин ће бити уклоњени канали пронађени помоћу USB тјунера и обавиће се поновно скенирање канала.\n\nПроверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, можда ће бити потребно да подесите њен положај или смер да би регистровала већину канала. Најбоље резултате ћете добити ако је поставите високо у близини прозора."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Настави"</item>
- <item msgid="4432431398374089710">"Откажи"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Изаберите тип везе"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Изаберите „Антена“ ако је спољна антена повезана са тјунером. Изаберите „Кабловска“ ако су вам канали доступни преко добављача услуге кабловске телевизије. Ако нисте сигурни, скенираће се оба типа, али ово може да траје дуже."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антена"</item>
- <item msgid="2445879869338877559">"Кабловска"</item>
- <item msgid="597328838068074806">"Нисам сигуран/на"</item>
- <item msgid="3613410733017077040">"Само за програмирање"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Подешавање USB тјунера за канале"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Ово може да потраје неколико минута"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ЗАУСТАВИ СКЕНИРАЊЕ КАНАЛА"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Готово"</item>
- <item msgid="496688122303154468">"Скенирај поново"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Није пронађен ниједан канал"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Скенирањем није пронађен ниједан канал. Проверите да ли је USB тјунер прикључен и повезан са извором ТВ сигнала.\n\nАко користите антену за сигнал преко мреже, подесите њен положај или смер. Најбоље резултате ћете добити ако је поставите високо у близини прозора и поново обавите скенирање."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Скенирај поново"</item>
- <item msgid="6784975565864102291">"Готово"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Тражење ТВ канала"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Подешавање USB тјунера за канале"</string>
-</resources>
diff --git a/usbtuner/res/values-sv/strings.xml b/usbtuner/res/values-sv/strings.xml
deleted file mode 100644
index 501725eb..00000000
--- a/usbtuner/res/values-sv/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"TV-ingång för USB-tuner"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"På"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Av"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Vänta tills sökningen är klar"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Välj kanalkälla"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ingen signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Det gick inte att ställa in <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Det gick inte att ställa in kanalen"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Mjukvaran för USB-tunern har nyligen uppdaterats. Sök igenom kanalerna igen."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3-ljud är inte tillgängligt"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Inställning av kanalmottagare"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Kanalinställning för USB-mottagare"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Fortsätt"</item>
- <item msgid="7745727658174773453">"Inte nu"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Vill du köra kanalinställningen på nytt?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Fortsätt"</item>
- <item msgid="4432431398374089710">"Avbryt"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Välj anslutningstyp"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenn"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Inte säker"</item>
- <item msgid="3613410733017077040">"Endast för utveckling"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Kanalinställning för USB-mottagare"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Det här kan ta flera minuter"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d kanaler hittades</item>
- <item quantity="one">%1$d kanal hittades</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"STOPPA KANALSÖKNINGEN"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Klar"</item>
- <item msgid="496688122303154468">"Sök igen"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Inga kanaler hittades"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Sök igen"</item>
- <item msgid="6784975565864102291">"Klar"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Sök efter TV-kanaler"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Kanalinställning för USB-mottagare"</string>
-</resources>
diff --git a/usbtuner/res/values-sw/strings.xml b/usbtuner/res/values-sw/strings.xml
deleted file mode 100644
index 4a6e0f24..00000000
--- a/usbtuner/res/values-sw/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Kisimbuzi cha USB cha Kupokea Mawimbi ya TV"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Washa"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Zima"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Tafadhali subiri ili uchakataji umalizike"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Chagua chanzo chako cha stesheni"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Hakuna Mawimbi"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Haikuweza kupata kituo cha <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Imeshindwa kubadilisha kituo cha TV"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Programu ya kisimbuzi cha USB ilisasishwa hivi majuzi. Tafadhali tafuta vituo tena."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Kipengele cha sauti cha AC3 hakipatikani"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kuweka mipangilio ya kitafuta vituo"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Kuweka mipangilio ya kitafuta vituo cha USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Thibitisha kuwa kitafuta vituo cha USB kimechomekwa kwenye chanzo cha nishati na kuunganishwa kwenye chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, huenda ukahitajika kurekebisha mkao wake au kule inakoelekezwa ili upate vituo vingi zaidi. Kwa matokeo bora zaidi, iweke sehemu ya juu iliyo karibu na dirisha."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Endelea"</item>
- <item msgid="7745727658174773453">"Si sasa"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Ungependa kuweka upya mipangilio ya vituo?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Hali hii itaondoa vituo vinavyopatikana kwenye kitafuta vituo cha USB na kutafuta vituo upya tena. \n\nThibitisha kuwa kitafuta vituo cha USB kimechomekwa kwenye chanzo cha nishati na kuunganishwa kwenye chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, rekebisha mkao wake au kule inakoelekezwa ili upate vituo vingi zaidi. Kwa matokeo bora zaidi, weka antena yako sehemu ya juu iliyo karibu na dirisha."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Endelea"</item>
- <item msgid="4432431398374089710">"Ghairi"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Chagua aina ya muunganisho"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antena"</item>
- <item msgid="2445879869338877559">"Kebo"</item>
- <item msgid="597328838068074806">"Sina uhakika"</item>
- <item msgid="3613410733017077040">"Kusanidi pekee"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Kuweka mipangilio ya kitafuta vituo cha USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Hii inaweza kuchukua dakika kadhaa"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">Vituo %1$d vimepatikana</item>
- <item quantity="one">Kituo %1$d kimepatikana</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"SIMAMISHA UTAFUTAJI WA VITUO"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">Sadakta! Vituo %1$d vimepatikana baada ya kutafuta vituo. Kama hujaridhika, jaribu kurekebisha mkao wa antena na 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="979481834388007277">"Imemaliza"</item>
- <item msgid="496688122303154468">"Tafuta tena"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Hakuna Vituo vilivyopatikana"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Hakuna kituo chochote kilichopatikana wakati wa utafutaji. Thibitisha kuwa kitafuta vituo cha USB kimechomekwa kwenye chanzo cha nishati na kuunganishwa kwenye chanzo cha mawimbi ya TV.\n\nKama unatumia antena ya hewani, rekebisha mkao wake au kule inakoelekezwa. Kwa matokeo bora zaidi, iweke sehemu ya juu iliyo karibu na dirisha na utafute tena."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Tafuta tena"</item>
- <item msgid="6784975565864102291">"Imemaliza"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Tafuta vituo vya TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Kuweka mipangilio ya kitafuta vituo cha USB"</string>
-</resources>
diff --git a/usbtuner/res/values-ta-rIN/strings.xml b/usbtuner/res/values-ta-rIN/strings.xml
deleted file mode 100644
index 6db07d72..00000000
--- a/usbtuner/res/values-ta-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB டியூனர் டிவி இன்புட்"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"இயக்கு"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"முடக்கு"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"செயலாக்கம் முடியும் வரை காத்திருக்கவும்"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"சேனல் மூலத்தைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"சிக்னல் இல்லை"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>க்கு டியூன் செய்ய முடியவில்லை"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"மாற்ற முடியவில்லை"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB டியூனர் மென்பொருள் சமீபத்தில் புதுப்பிக்கப்பட்டது. சேனல்களை மீண்டும் ஸ்கேன் செய்யவும்."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ஆடியோ கிடைக்கவில்லை"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"சேனல் டியூனர் அமைவு"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB சேனல் டியூனர் அமைவு"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB டியூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக, அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். சிறந்த பலன்களுக்காக, உயரமான இடத்தில், ஜன்னலுக்கு அருகில் வைக்கவும்."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"தொடர்க"</item>
- <item msgid="7745727658174773453">"இப்போது வேண்டாம்"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"சேனல் அமைவை மீண்டும் இயக்கவா?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"இது USB டியூனரிலிருந்து கண்டறிந்த சேனல்களை அகற்றி, மீண்டும் புதிய சேனல்களை ஸ்கேன் செய்யும்.\n\nUSB டியூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதிகமான சேனல்களைப் பெறுவதற்காக, அதன் இடம் அல்லது திசையைச் சரிசெய்ய வேண்டியிருக்கலாம். சிறந்த பலன்களுக்காக, உயரமான இடத்தில், ஜன்னலுக்கு அருகில் வைக்கவும்."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"தொடர்க"</item>
- <item msgid="4432431398374089710">"ரத்துசெய்"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"இணைப்பு வகையைத் தேர்ந்தெடுக்கவும்"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"டியூனருடன் வெளிப்புற ஆன்டெனா இணைக்கப்பட்டிருந்தால், ஆன்டெனாவைத் தேர்வுசெய்யவும். கேபிள் சேவை வழங்குநரிடமிருந்து சேனல்கள் கிடைக்கின்றன என்றால், கேபிளைத் தேர்வுசெய்யவும். எதையும் தேர்வுசெய்யவில்லை என்றால், இரு வகைகளிலும் ஸ்கேன் செய்யப்படும். ஆனால் இதற்கு அதிக நேரம் எடுக்கலாம்."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"ஆன்டெனா"</item>
- <item msgid="2445879869338877559">"கேபிள்"</item>
- <item msgid="597328838068074806">"நிச்சயமாகத் தெரியவில்லை"</item>
- <item msgid="3613410733017077040">"டெவலப்பர்களுக்கு மட்டும்"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB சேனல் டியூனர் அமைவு"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"இதற்குச் சில நிமிடங்கள் ஆகலாம்"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d சேனல்கள் கண்டறியப்பட்டன</item>
- <item quantity="one">%1$d சேனல் கண்டறியப்பட்டது</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"சேனலை ஸ்கேன் செய்வதை நிறுத்து"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d சேனல்கள் கண்டறியப்பட்டன</item>
- <item quantity="one">%1$d சேனல் கண்டறியப்பட்டது</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">அருமை! சேனலை ஸ்கேன் செய்யும் போது, %1$d சேனல்கள் கண்டறியப்பட்டன. இவை சரியாகத் தெரியவில்லை என்றால், ஆன்டெனா நிலையை மாற்றி, மீண்டும் ஸ்கேன் செய்யவும்.</item>
- <item quantity="one">அருமை! சேனலை ஸ்கேன் செய்யும் போது, %1$d சேனல் கண்டறியப்பட்டது. இது சரியாகத் தெரியவில்லை என்றால், ஆன்டெனா நிலையை மாற்றி, மீண்டும் ஸ்கேன் செய்யவும்.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"முடிந்தது"</item>
- <item msgid="496688122303154468">"மீண்டும் ஸ்கேன் செய்"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"சேனல்கள் இல்லை"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ஸ்கேனில் எந்தச் சேனல்களும் கண்டறியப்படவில்லை. USB டியூனர் செருகப்பட்டுள்ளதையும் டிவி சிக்னல் மூலத்துடன் இணைக்கப்பட்டுள்ளதையும் சரிபார்க்கவும்.\n\nஆன்டெனாவைப் பயன்படுத்தினால், அதன் இடம் அல்லது திசையைச் சரிசெய்யவும். சிறந்த பலன்களுக்காக, உயரமான இடத்தில், ஜன்னலுக்கு அருகில் வைத்து, மீண்டும் ஸ்கேன் செய்யவும்."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"மீண்டும் ஸ்கேன் செய்"</item>
- <item msgid="6784975565864102291">"முடிந்தது"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"டிவி சேனல்களை ஸ்கேன் செய்"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB சேனல் டியூனர் அமைவு"</string>
-</resources>
diff --git a/usbtuner/res/values-te-rIN/strings.xml b/usbtuner/res/values-te-rIN/strings.xml
deleted file mode 100644
index c80ea655..00000000
--- a/usbtuner/res/values-te-rIN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB ట్యూనర్ టీవీ ఇన్‌పుట్"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"ఆన్ చేయండి"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ఆఫ్ చేయండి"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"దయచేసి ప్రాసెస్ చేయడం పూర్తయ్యే వరకు వేచి ఉండండి"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"మీ ఛానెల్ మూలాన్ని ఎంచుకోండి"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"సిగ్నల్ లేదు"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g>కి ట్యూన్ చేయడంలో విఫలమైంది"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ట్యూన్ చేయడం విఫలమైంది"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB ట్యూనర్ సాఫ్ట్‌వేర్ ఇటీవల నవీకరించబడింది. దయచేసి ఛానెల్‌లను మళ్లీ స్కాన్ చేయండి."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ఆడియో అందుబాటులో లేదు"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ఛానెల్ ట్యూనర్ సెటప్"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB ఛానెల్ ట్యూనర్ సెటప్"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"USB ట్యూనర్ ప్లగిన్ చేయబడిందని మరియు టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి ఉండవచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"కొనసాగించు"</item>
- <item msgid="7745727658174773453">"ఇప్పుడు కాదు"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"ఛానెల్ సెటప్‌ను మళ్లీ అమలు చేయాలా?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"ఇది USB ట్యూనర్ నుండి కనుగొన్న ఛానెల్‌లను తీసివేస్తుంది మరియు మళ్లీ కొత్త ఛానెల్‌ల కోసం స్కాన్ చేస్తుంది.\n\nUSB ట్యూనర్ ప్లగిన్ చేయబడిందని మరియు టీవీ సిగ్నల్ సోర్స్‌కు కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, మీరు మరిన్ని ఛానెల్‌లను స్వీకరించడానికి దాని స్థానాన్ని లేదా దిశను మార్చాల్సి ఉండవచ్చు. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచండి."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"కొనసాగించు"</item>
- <item msgid="4432431398374089710">"రద్దు చేయి"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"కనెక్షన్ రకాన్ని ఎంచుకోండి"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"ట్యూనర్‌కు బాహ్య యాంటెన్నా కనెక్ట్ చేసి ఉంటే యాంటెన్నాను ఎంచుకోండి. మీ ఛానెల్‌‍‍లు కేబుల్ సేవా ప్రదాత నుండి అందించబడితే కేబుల్‌ను ఎంచుకోండి. మీకు ఖచ్చితంగా తెలియకుంటే, రెండు రకాలూ స్కాన్ చేయబడతాయి, కానీ దీనికి ఎక్కువ సమయం పట్టవచ్చు."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"యాంటెన్నా"</item>
- <item msgid="2445879869338877559">"కేబుల్"</item>
- <item msgid="597328838068074806">"అంత ఖచ్చితంగా తెలియదు"</item>
- <item msgid="3613410733017077040">"అభివృద్ధి మాత్రమే"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB ఛానెల్ ట్యూనర్ సెటప్"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"దీనికి కొన్ని నిమిషాలు పట్టవచ్చు"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d ఛానెల్‌లు కనుగొనబడ్డాయి</item>
- <item quantity="one">%1$d ఛానెల్ కనుగొనబడింది</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"ఛానెల్ స్కాన్‌ను ఆపివేయి"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">%1$d ఛానెల్‌లు కనుగొనబడ్డాయి</item>
- <item quantity="one">%1$d ఛానెల్ కనుగొనబడింది</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">మంచిది! ఛానెల్ స్కాన్‌లో %1$d ఛానెల్‌లు కనుగొనబడ్డాయి. ఇది సరైనదిగా అనిపించకుంటే, యాంటెన్నా స్థానం సర్దుబాటు చేసి, ఆపై మళ్లీ స్కాన్ చేయడం ప్రయత్నించండి.</item>
- <item quantity="one">మంచిది! ఛానెల్ స్కాన్‌లో %1$d ఛానెల్ కనుగొనబడింది. ఇది సరైనదిగా అనిపించకుంటే, యాంటెన్నా స్థానం సర్దుబాటు చేసి, ఆపై మళ్లీ స్కాన్ చేయడం ప్రయత్నించండి.</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"పూర్తయింది"</item>
- <item msgid="496688122303154468">"మళ్లీ స్కాన్ చేయి"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ఛానెల్‌లు ఏవీ కనుగొనబడలేదు"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"స్కాన్‌లో ఛానెల్‌లు వేటినీ కనుగొనలేదు. USB ట్యూనర్ ప్లగిన్ చేయబడిందని మరియు టీవీ సిగ్నల్ సోర్స్‌కి కనెక్ట్ చేయబడిందని ధృవపరుచుకోండి.\n\nప్రసారాల కోసం యాంటెన్నాను ఉపయోగిస్తుంటే, దాని స్థానాన్ని లేదా దిశను సర్దుబాటు చేయండి. ఉత్తమ ఫలితాల కోసం, దాన్ని ఎత్తులో కిటికీకి దగ్గరగా ఉంచి, ఆపై మళ్లీ స్కాన్ చేయండి."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"మళ్లీ స్కాన్ చేయి"</item>
- <item msgid="6784975565864102291">"పూర్తయింది"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"టీవీ ఛానెల్‌ల కోసం స్కాన్ చేయండి"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB ఛానెల్ ట్యూనర్ సెటప్"</string>
-</resources>
diff --git a/usbtuner/res/values-th/strings.xml b/usbtuner/res/values-th/strings.xml
deleted file mode 100644
index a937c6ec..00000000
--- a/usbtuner/res/values-th/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"อินพุตทีวีสำหรับตัวรับสัญญาณผ่าน USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"เปิด"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"ปิด"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"โปรดรอให้การดำเนินการหยุดลงสักครู่"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"เลือกแหล่งที่มาของช่อง"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"ไม่มีสัญญาณ"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"ไม่สามารถรับสัญญาณ <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ไม่สามารถปรับจูนได้"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"ซอฟต์แวร์ตัวรับสัญญาณผ่าน USB มีการอัปเดตเมื่อเร็วๆ นี้ โปรดสแกนช่องอีกครั้ง"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"ไม่สามารถใช้ระบบเสียง AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"ตั้งค่าตัวรับสัญญาณช่อง"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"ตั้งค่าตัวรับสัญญาณช่องแบบ USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"ให้ตรวจสอบว่าเสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"ดำเนินการต่อ"</item>
- <item msgid="7745727658174773453">"ข้ามไปก่อน"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"หากต้องการเริ่มการตั้งค่าช่องอีกครั้ง"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"การดำเนินการนี้จะนำช่องที่พบจากตัวรับสัญญาณแบบ USB ออกและสแกนหาช่องใหม่อีกครั้ง\n\nให้ตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ คุณอาจต้องปรับตำแหน่งหรือทิศทางเพื่อรับช่องให้ได้มากที่สุด เพื่อผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่าง"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"ดำเนินการต่อ"</item>
- <item msgid="4432431398374089710">"ยกเลิก"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"เลือกประเภทการเชื่อมต่อ"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"เลือกเสาอากาศหากมีการเชื่อมต่อเสาอากาศภายนอกกับตัวรับสัญญาณ เลือกเคเบิลหากช่องของคุณมาจากผู้ให้บริการเคเบิล หากคุณไม่แน่ใจ ระบบจะสแกนทั้ง 2 แบบซึ่งอาจใช้เวลานานขึ้น"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"เสาอากาศ"</item>
- <item msgid="2445879869338877559">"สายสัญญาณ"</item>
- <item msgid="597328838068074806">"ไม่แน่ใจ"</item>
- <item msgid="3613410733017077040">"เฉพาะการพัฒนาเท่านั้น"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"ตั้งค่าตัวรับสัญญาณช่องแบบ USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"อาจใช้เวลาหลายนาที"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">พบ %1$d ช่อง</item>
- <item quantity="one">พบ %1$d ช่อง</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"หยุดการสแกนช่อง"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">พบ %1$d ช่อง</item>
- <item quantity="one">พบ %1$d ช่อง</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">เยี่ยมมาก! พบ %1$d ช่องระหว่างการสแกนช่อง หากคุณคิดว่าไม่ถูกต้อง ให้ลองปรับตำแหน่งเสาอากาศและสแกนอีกครั้ง</item>
- <item quantity="one">เยี่ยมมาก! พบ %1$d ช่องระหว่างการสแกนช่อง หากคุณคิดว่าไม่ถูกต้อง ให้ลองปรับตำแหน่งเสาอากาศและสแกนอีกครั้ง</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"เสร็จ"</item>
- <item msgid="496688122303154468">"สแกนอีกครั้ง"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"ไม่พบช่อง"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"ไม่พบช่องในการสแกน ให้ตรวจสอบว่าได้เสียบปลั๊กตัวรับสัญญาณแบบ USB และเชื่อมต่อกับแหล่งสัญญาณทีวีแล้ว\n\nหากใช้เสาอากาศแบบผ่านอากาศ ให้ปรับตำแหน่งหรือทิศทาง เพื่อให้ได้ผลลัพธ์ที่ดีที่สุด ให้วางไว้บนที่สูงใกล้หน้าต่างและสแกนอีกครั้ง"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"สแกนอีกครั้ง"</item>
- <item msgid="6784975565864102291">"เสร็จ"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"สแกนหาช่องทีวี"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"ตั้งค่าตัวรับสัญญาณช่องแบบ USB"</string>
-</resources>
diff --git a/usbtuner/res/values-tl/strings.xml b/usbtuner/res/values-tl/strings.xml
deleted file mode 100644
index aad2e1cc..00000000
--- a/usbtuner/res/values-tl/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Tuner TV Input"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"I-on"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"I-off"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Mangyaring maghintay na matapos ang pagpoproseso"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Piliin ang pinagmulan ng iyong channel"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Walang Signal"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Hindi nai-tune sa <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Hindi na-tune"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Na-update kamakailan ang USB tuner software. Paki-scan muli ang mga channel."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Hindi available ang AC3 audio"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Pag-setup ng tuner ng channel"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Pag-setup ng USB tuner ng channel"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"I-verify na nakasaksak at nakakonekta ang USB tuner sa pinagmumulan ng signal ng TV.\n\nKung gumagamit ka ng isang over-the-air na antenna, maaaring kailanganin mong ayusin ang pagkakalagay o ang direksyon nito upang masagap ang pinakamaraming channel. Upang makasagap ng mas maraming channel, ilagay ito sa isang mataas na lugar na malapit sa bintana."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Magpatuloy"</item>
- <item msgid="7745727658174773453">"Walang makitang channel"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Gusto mo bang muling patakbuhin ang pag-setup ng channel?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Kapag isinagawa mo ito, maaalis ang mga channel na nakita mula sa USB tuner at muli itong mag-ii-scan ng mga bagong channel.\n\nI-verify na nakasaksak at nakakonekta ang USB tuner sa pinagmumulan ng signal ng TV.\n\nKung gumagamit ka ng isang over-the-air na antenna, maaaring kailanganin mong ayusin ang pagkakalagay o ang direksyon nito upang masagap ang pinakamaraming channel. Upang makasagap ng mas maraming channel, ilagay ito sa isang mataas na lugar na malapit sa bintana."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Magpatuloy"</item>
- <item msgid="4432431398374089710">"Kanselahin"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Piliin ang uri ng koneksyon"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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 nakakatiyak, iii-scan ang parehong nabanggit na uri, ngunit maaaring matagalan ito."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Antenna"</item>
- <item msgid="2445879869338877559">"Cable"</item>
- <item msgid="597328838068074806">"Hindi nakakatiyak"</item>
- <item msgid="3613410733017077040">"Development lang"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Pag-setup ng USB tuner ng channel"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Maaaring abutin ito ng ilang minuto"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"IHINTO ANG PAG-SCAN NG CHANNEL"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Tapos Na"</item>
- <item msgid="496688122303154468">"Muling mag-scan"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Walang nakitang Mga Channel"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Walang nakitang anumang mga channel noong nag-ii-scan. I-verify na nakasaksak at nakakonekta ang USB tuner sa pinagmumulan ng signal ng TV.\n\nKung gumagamit ka ng isang over-the-air na antenna, ayusin ang pagkakalagay o ang direksyon nito. Upang makasagap ng mas maraming channel, ilagay ito sa isang mataas na lugar na malapit sa bintana at muling mag-scan."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Muling mag-scan"</item>
- <item msgid="6784975565864102291">"Tapos Na"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Mag-scan ng mga channel sa TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Pag-setup ng USB tuner ng channel"</string>
-</resources>
diff --git a/usbtuner/res/values-tr/strings.xml b/usbtuner/res/values-tr/strings.xml
deleted file mode 100644
index 167b220e..00000000
--- a/usbtuner/res/values-tr/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB Kanal Ayarlayıcı TV Girişi"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Aç"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Kapat"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Lütfen işlemin tamamlanmasını bekleyin"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Kanal kaynağınızı seçin"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Sinyal Yok"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> adlı kanala ayarlanamadı"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Kanal ayarlanamadı"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB kanal ayarlayıcı yazılımı yakın zamanda güncellendi. Lütfen kanalları yeniden tarayın."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 ses kullanılamıyor"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Kanal ayarlayıcı kurulumu"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB kanal ayarlayıcı kurulumu"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Devam Et"</item>
- <item msgid="7745727658174773453">"Şimdi değil"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kanal kurulumu yeniden çalıştırılsın mı?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Devam Et"</item>
- <item msgid="4432431398374089710">"İptal"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Bağlantı türünü seçin"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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 bu işlem daha uzun sürebilir."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Anten"</item>
- <item msgid="2445879869338877559">"Kablolu"</item>
- <item msgid="597328838068074806">"Emin değilim"</item>
- <item msgid="3613410733017077040">"Yalnızca geliştirme"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB kanal ayarlayıcı kurulumu"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Bu işlem birkaç dakika sürebilir"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">%1$d kanal bulundu</item>
- <item quantity="one">%1$d kanal bulundu</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"KANAL TARAMAYI DURDUR"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <item quantity="other">Harika! 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">Harika! 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="979481834388007277">"Bitti"</item>
- <item msgid="496688122303154468">"Yeniden tara"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Hiçbir kanal bulunamadı"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Yeniden tara"</item>
- <item msgid="6784975565864102291">"Bitti"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"TV kanallarını tarayın"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB kanal ayarlayıcı kurulumu"</string>
-</resources>
diff --git a/usbtuner/res/values-uk/strings.xml b/usbtuner/res/values-uk/strings.xml
deleted file mode 100644
index f84badba..00000000
--- a/usbtuner/res/values-uk/strings.xml
+++ /dev/null
@@ -1,84 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Джерело вхідного телесигналу – USB-тюнер"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Увімкнути"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Вимкнути"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Зачекайте, доки завершиться пошук"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Виберіть джерело каналу"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Немає сигналу"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Не вдалося налаштувати канал <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Не вдалося налаштувати"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Програмне забезпечення USB-тюнера нещодавно оновлено. Проскануйте канали знову."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Аудіо у форматі AC3 не підтримується"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Налаштування тюнера"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Налаштування USB-тюнера"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"Переконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтеся ефірною антеною, змініть її положення, щоб знайти більше каналів. Радимо розмістити антену вище та біля вікна."</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Продовжити"</item>
- <item msgid="7745727658174773453">"Не зараз"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Відновити налаштування каналу?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Канали, знайдені за допомогою USB-тюнера, буде видалено. Пошук почнеться знову.\n\nПереконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтеся ефірною антеною, змініть її положення, щоб знайти більше каналів. Радимо розмістити антену вище та біля вікна."</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Продовжити"</item>
- <item msgid="4432431398374089710">"Скасувати"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Вибір типу з’єднання"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"Виберіть \"Антена\", якщо до тюнера підключено зовнішню антену. Виберіть \"Кабель\", якщо у вас кабельне телебачення. Якщо вибрати \"Не знаю\", тюнер шукатиме обидва типи сигналу, але це займе більше часу."</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"Антена"</item>
- <item msgid="2445879869338877559">"Кабель"</item>
- <item msgid="597328838068074806">"Не знаю"</item>
- <item msgid="3613410733017077040">"Лише для розробки"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Налаштування USB-тюнера"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Це може зайняти декілька хвилин"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"ПРИПИНИТИ ПОШУК КАНАЛІВ"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Готово"</item>
- <item msgid="496688122303154468">"Шукати знову"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Канали не знайдено"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"Канали не знайдено. Переконайтеся, що ви підключили USB-тюнер і під’єднали джерело вхідного телевізійного сигналу.\n\nЯкщо ви користуєтеся ефірною антеною, змініть її положення. Розмістіть антену вище та біля вікна й повторіть спробу."</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Шукати знову"</item>
- <item msgid="6784975565864102291">"Готово"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Пошук телевізійних каналів"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Налаштування USB-тюнера"</string>
-</resources>
diff --git a/usbtuner/res/values-ur-rPK/strings.xml b/usbtuner/res/values-ur-rPK/strings.xml
deleted file mode 100644
index 38b8d601..00000000
--- a/usbtuner/res/values-ur-rPK/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"‏USBٹونرTV ان پٹ"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"آن"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"آف"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"براہ کرم کاروائی ختم ہونے کا انتظار کریں"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"اپنے چینل کا ذریعہ منتخب کریں"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"کوئی سگنل نہیں ہے"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"<xliff:g id="CHANNEL_NAME">%s</xliff:g> پر ٹیون ہونے میں ناکام ہوگیا"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"ٹیون کرنے میں ناکام ہو گیا"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"‏USB ٹونر سافٹ ویئر حال ہی میں اپ ڈیٹ کیا گیا ہے۔ براہ مہربانی چینلز کو دوبارہ اسکین کریں۔"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"‏AC3 آڈیو دستیاب نہیں ہے"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"چینل ٹیونر سیٹ اپ"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"‏USB چینل ٹیونر سیٹ اپ"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"‏USB ٹیونر کے پلگ ان ہونے اور TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کی مقام بندی یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"جاری رکھیں"</item>
- <item msgid="7745727658174773453">"ابھی نہیں"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"چینل سیٹ اپ دوبارہ چلائیں؟"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"‏یہ USB ٹیونر سے ملے چیلنز ہٹا دے گا اور دوبارہ نئے چینلز کیلئے اسکین کرے گا۔\n\nTV ٹیونر کے پلگ ان ہونے اور سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو زیادہ تر چینلز موصول کرنے کیلئے آپ کو اس کی مقام بندی یا سمت ایڈجسٹ کرنے کی ضرورت پیش آ سکتی ہے۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں۔"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"جاری رکھیں"</item>
- <item msgid="4432431398374089710">"منسوخ کریں"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"کنکشن کی قسم منتخب کریں"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"اگر ٹیونر سے کوئی بیرونی انٹینا منسلک ہے تو انٹینا کا انتخاب کریں۔ اگر آپ کے چیلنز کسی کیبل سروس فراہم کنندہ کی طرف سے موصول ہوتے ہیں تو کیبل کا انتخاب کریں۔ اگر آپ پُر یقین نہیں ہیں تو دونوں اقسام کو اسکین کیا جائے گا، مگر اس میں زیادہ وقت لگ سکتا ہے۔"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"انٹینا"</item>
- <item msgid="2445879869338877559">"کیبل"</item>
- <item msgid="597328838068074806">"یقین نہیں ہے"</item>
- <item msgid="3613410733017077040">"صرف ترقی"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"‏USB چینل ٹیونر سیٹ اپ"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"اس میں کئی منٹ لگ سکتے ہیں"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">‏%1$d چینل ملے</item>
- <item quantity="one">‏%1$d چینل ملا</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"چینل اسکین روکیں"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">‏%1$d چینل ملے</item>
- <item quantity="one">‏%1$d چینل ملا</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">‏خوب! چینل اسکین کے دوران ‎%1$d چینل ملے۔ اگر یہ ٹھیک نہیں لگ رہا تو انٹینا کی پوزیشن ایڈجسٹ کرنے کی کوشش کریں اور دوبارہ اسکین کریں۔</item>
- <item quantity="one">‏خوب! چینل اسکین کے دوران ‎%1$d چینل ملا۔ اگر یہ ٹھیک نہیں لگ رہا تو انٹینا کی پوزیشن ایڈجسٹ کرنے کی کوشش کریں اور دوبارہ اسکین کریں۔</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"ہو گیا"</item>
- <item msgid="496688122303154468">"دوبارہ اسکین کریں"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"کوئی چینلز نہیں ملے"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"‏اسکین سے کوئی چیلز نہیں ملے۔ USB ٹیونر کے پلگ ان ہونے اور TV سگنل ماخذ سے منسلک ہونے کی توثیق کریں۔\n\nاگر وائرلیس نیٹ ورک کنکشن انٹینا استعمال کر رہے ہیں تو اس کی مقام بندی یا سمت ایڈجسٹ کریں۔ بہترین نتائج کیلئے اسے اونچی جگہ اور کھڑکی کے پاس رکھیں اور دوبارہ اسکین کریں۔"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"دوبارہ اسکین کریں"</item>
- <item msgid="6784975565864102291">"ہو گیا"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"‏TV چینلز کے لیے سکین کریں"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"‏USB چینل ٹیونر سیٹ اپ"</string>
-</resources>
diff --git a/usbtuner/res/values-uz-rUZ/strings.xml b/usbtuner/res/values-uz-rUZ/strings.xml
deleted file mode 100644
index 06c953fb..00000000
--- a/usbtuner/res/values-uz-rUZ/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB-tyunerli TV-kirish"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Yoqish"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"O‘chirib qo‘yish"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Iltimos, jarayon tugashini kuting"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Kanal manbasini tanlang"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Signal yo’q"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"“<xliff:g id="CHANNEL_NAME">%s</xliff:g>” kanaliga sozlab bo’lmadi"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Sozlab bo‘lmadi"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB-tyunerning dasturiy ta’minoti yaqinda yangilandi. Kanallarni qaytadan qidiring."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"AC3 formatidagi audio qo‘llab-quvvatlanmaydi"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Tyunerni sozlash"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB tyunerni sozlash"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Davom etish"</item>
- <item msgid="7745727658174773453">"Hozir emas"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Kanallar qaytadan sozlansinmi?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Davom etish"</item>
- <item msgid="4432431398374089710">"Bekor qilish"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Aloqa turini tanlang"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Antenna"</item>
- <item msgid="2445879869338877559">"Kabel"</item>
- <item msgid="597328838068074806">"Aniq bilmayman"</item>
- <item msgid="3613410733017077040">"Faqat dasturchilar uchun"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB kanal tyunerini sozlash"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Bu bir necha daqiqa vaqt olishi mumkin"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"KANAL QIDIRUVINI TO‘XTATISH"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Tayyor"</item>
- <item msgid="496688122303154468">"Yana qidirish"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Hech qanday kanal topilmadi"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Yana qidirish"</item>
- <item msgid="6784975565864102291">"Tayyor"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Telekanallarni qidiring"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB kanal tyunerini sozlash"</string>
-</resources>
diff --git a/usbtuner/res/values-vi/strings.xml b/usbtuner/res/values-vi/strings.xml
deleted file mode 100644
index 966b139b..00000000
--- a/usbtuner/res/values-vi/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Đầu vào TV của bộ điều chỉnh USB"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Bật"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Tắt"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Vui lòng đợi để hoàn tất xử lý"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Chọn nguồn kênh của bạn"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Không có tín hiệu"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Không chỉnh được tới <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Dò không thành công"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Phần mềm bộ điều chỉnh USB đã được cập nhật gần đây. Hãy quét lại các kênh."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Không có âm thanh AC3"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Thiết lập bộ dò kênh"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Thiết lập bộ dò kênh USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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 đó để thu đượ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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Tiếp tục"</item>
- <item msgid="7745727658174773453">"Không phải bây giờ"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Chạy lại quá trình thiết lập kênh?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"Quá trình này sẽ xóa các kênh mà 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à đượ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 đó để thu đượ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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Tiếp tục"</item>
- <item msgid="4432431398374089710">"Hủy"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Chọn loại kết nối"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"Ăng-ten"</item>
- <item msgid="2445879869338877559">"Cáp"</item>
- <item msgid="597328838068074806">"Không chắc chắn"</item>
- <item msgid="3613410733017077040">"Chỉ phát triển"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Thiết lập bộ dò kênh USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Quá trình này có thể mất vài phút"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <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="8358794117343664624">"NGỪNG QUÉT KÊNH"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Xong"</item>
- <item msgid="496688122303154468">"Quét lại"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Không tìm thấy kênh nào"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Quét lại"</item>
- <item msgid="6784975565864102291">"Xong"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Quét tìm các kênh TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Thiết lập bộ dò kênh USB"</string>
-</resources>
diff --git a/usbtuner/res/values-zh-rCN/strings.xml b/usbtuner/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 5f8d366f..00000000
--- a/usbtuner/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB 调谐器电视输入设备"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"开启"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"关闭"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"请耐心等待处理完毕"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"选择您的频道来源"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"无信号"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"无法调到<xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"无法调到相应频道"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB 调谐器软件近期已更新。请重新扫描频道。"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"无法播放 AC3 音频"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"频道调谐器设置"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB 频道调谐器设置"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"继续"</item>
- <item msgid="7745727658174773453">"以后再说"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"重新运行频道设置?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"此操作将移除通过 USB 调谐器找到的频道,并重新扫描新频道。\n\n请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,则可能需要调节天线的位置或方向,以便接收尽可能多的频道。要获得最佳效果,请将天线的位置调高并靠近窗户。"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"继续"</item>
- <item msgid="4432431398374089710">"取消"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"选择连接类型"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"如果调谐器连接了外部天线,请选择“天线”。如果您的频道由有线电视服务提供商提供,请选择“有线电视”。如果您不确定,系统则会扫描以上两种类型,不过这可能会花费更长的时间。"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"天线"</item>
- <item msgid="2445879869338877559">"有线电视"</item>
- <item msgid="597328838068074806">"不确定"</item>
- <item msgid="3613410733017077040">"仅限开发用途"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB 频道调谐器设置"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"此过程可能需要几分钟时间"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">找到 %1$d 个频道</item>
- <item quantity="one">找到 %1$d 个频道</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"停止频道扫描"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">找到 %1$d 个频道</item>
- <item quantity="one">找到 %1$d 个频道</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">很好!系统在频道扫描过程中找到 %1$d 个频道。如果您觉得数量有误,请尝试调整天线的位置,然后再扫描一次。</item>
- <item quantity="one">很好!系统在频道扫描过程中找到 %1$d 个频道。如果您觉得数量有误,请尝试调整天线的位置,然后再扫描一次。</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"完成"</item>
- <item msgid="496688122303154468">"重新扫描"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"未找到任何频道"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"扫描后未找到任何频道。请检查 USB 调谐器是否已插好并连接到电视信号源。\n\n如果您使用的是无线电视,请调节天线的位置或方向。要获得最佳效果,请将天线的位置调高并靠近窗户,然后再扫描一次。"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"重新扫描"</item>
- <item msgid="6784975565864102291">"完成"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"扫描电视频道"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB 频道调谐器设置"</string>
-</resources>
diff --git a/usbtuner/res/values-zh-rHK/strings.xml b/usbtuner/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 67ee0a15..00000000
--- a/usbtuner/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB 調諧器電視輸入"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"開啟"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"關閉"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"請等待完成處理程序"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"選擇您的頻道來源"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"無訊號"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"無法調至 <xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"無法調校頻道"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB 調諧器軟件最近已經更新。請重新掃描頻道。"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"無法使用 AC3 音效"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"頻道調諧器設定"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB 頻道調諧器設定"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整它的位置或方向,以接收更多頻道。請將天線放在較高位置並靠近窗戶,以獲取最佳效果。"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"繼續"</item>
- <item msgid="7745727658174773453">"暫時不要"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"重新設定頻道?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"這將會移除 USB 調諧器找到的頻道,並會重新掃瞄新頻道。\n\n請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,可能需要調整天線的位置或方向,以接收更多頻道。請將天線放在較高位置並靠近窗戶,以獲取最佳效果。"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"繼續"</item>
- <item msgid="4432431398374089710">"取消"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"選擇連接類型"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"如果調諧器連接至外置天線,請選擇 [天線]。如果頻道由有線服務供應商提供,請選擇 [有線電視]。如果您不確定,系統會同時掃瞄這兩種類型的頻道,但可能需時較長。"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"天線"</item>
- <item msgid="2445879869338877559">"有線電視"</item>
- <item msgid="597328838068074806">"不確定"</item>
- <item msgid="3613410733017077040">"只限開發用途"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB 頻道調諧器設定"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"可能需時數分鐘"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">已找到 %1$d 個頻道</item>
- <item quantity="one">已找到 %1$d 個頻道</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"停止頻道掃瞄"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">已找到 %1$d 個頻道</item>
- <item quantity="one">已找到 %1$d 個頻道</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">太好了!掃瞄頻道時找到 %1$d 個頻道。如果掃瞄結果看來不正確,請嘗試調整天線位置並重新掃瞄。</item>
- <item quantity="one">太好了!掃瞄頻道時找到 %1$d 個頻道。如果掃瞄結果看來不正確,請嘗試調整天線位置並重新掃瞄。</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"完成"</item>
- <item msgid="496688122303154468">"重新掃瞄"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"找不到頻道"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"掃瞄找不到頻道。請確定 USB 調諧器已接駁並連接至電視訊號來源。\n\n如果您使用無線天線,請調整它的位置或方向。您亦可以將天線放在較高位置並靠近窗戶,然後重新掃瞄,以獲得最佳效果。"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"重新掃瞄"</item>
- <item msgid="6784975565864102291">"完成"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"掃瞄電視頻道"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB 頻道調諧器設定"</string>
-</resources>
diff --git a/usbtuner/res/values-zh-rTW/strings.xml b/usbtuner/res/values-zh-rTW/strings.xml
deleted file mode 100644
index b6c83e5d..00000000
--- a/usbtuner/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"USB 諧調器電視輸入裝置"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"開啟"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"關閉"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"請等待處理程序完成"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"選取您的頻道來源"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"無訊號"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"無法轉到「<xliff:g id="CHANNEL_NAME">%s</xliff:g>」"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"無法轉台"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"USB 諧調器軟體最近已更新。請重新掃描頻道。"</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"無法使用 AC3 音訊"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"頻道調諧器設定"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"USB 頻道調諧器設定"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果您使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
- <string-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"繼續"</item>
- <item msgid="7745727658174773453">"暫時不要"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"要重新執行頻道設定嗎?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"這項動作將移除 USB 調諧器找到的頻道,並再次掃描新的頻道。\n\n請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果您使用無線電視天線,可能需要調整天線的位置和方向,以便接收最多頻道。為達最佳效果,請將天線放在靠近窗戶的較高位置。"</string>
- <string-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"繼續"</item>
- <item msgid="4432431398374089710">"取消"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"選取連接類型"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"如果調諧器連接外部天線,請選擇 [天線]。如果您的頻道來自有線電視服務供應商,請選擇 [有線電視]。如果您不確定,系統會掃描這兩種類型,但是可能需要較長的時間。"</string>
- <string-array name="ut_connection_choices">
- <item msgid="1633072563555330217">"天線"</item>
- <item msgid="2445879869338877559">"有線電視"</item>
- <item msgid="597328838068074806">"不確定"</item>
- <item msgid="3613410733017077040">"僅供開發之用"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"USB 頻道調諧器設定"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"這可能需要幾分鐘的時間"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="other">找到 %1$d 個頻道</item>
- <item quantity="one">找到 %1$d 個頻道</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"停止頻道掃描"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <item quantity="other">找到 %1$d 個頻道</item>
- <item quantity="one">找到 %1$d 個頻道</item>
- </plurals>
- <plurals name="ut_result_found_description" formatted="false" msgid="1946474144459881182">
- <item quantity="other">太好了!頻道掃描作業結束後找到 %1$d 個頻道。如果數量不太正確,請嘗試調整天線的位置,然後再掃描一次。</item>
- <item quantity="one">太好了!頻道掃描作業結束後找到 %1$d 個頻道。如果數量不太正確,請嘗試調整天線的位置,然後再掃描一次。</item>
- </plurals>
- <string-array name="ut_result_found_choices">
- <item msgid="979481834388007277">"完成"</item>
- <item msgid="496688122303154468">"重新掃描"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"找不到任何頻道"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"掃描後並未發現任何頻道。請確認 USB 調諧器已插入並連接到電視訊號來源。\n\n如果您使用無線電視天線,請調整天線的位置和方向。為達最佳效果,請將天線放在靠近窗戶的較高位置,然後再掃描一次。"</string>
- <string-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"重新掃描"</item>
- <item msgid="6784975565864102291">"完成"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"掃描電視頻道"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"USB 頻道調諧器設定"</string>
-</resources>
diff --git a/usbtuner/res/values-zu/strings.xml b/usbtuner/res/values-zu/strings.xml
deleted file mode 100644
index 6373234a..00000000
--- a/usbtuner/res/values-zu/strings.xml
+++ /dev/null
@@ -1,78 +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 xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ut_app_name" msgid="1442714127635348166">"Okokufaka kwe-TV kwe-USB Tuner"</string>
- <string name="ut_setup_on" msgid="4957025496015647961">"Vuliwe"</string>
- <string name="ut_setup_off" msgid="806521579574068484">"Valiwe"</string>
- <string name="ut_setup_cancel" msgid="6173771946434222551">"Sicela ulinde ukuze uqede ukucubungula"</string>
- <string name="ut_select_channel_map" msgid="5007263088526410938">"Khetha umthombo wakho wesiteshi"</string>
- <string name="ut_no_signal" msgid="6484545357071124354">"Ayikho isignali"</string>
- <string name="ut_fail_to_tune" msgid="3995508747351098234">"Yehlulekile ukushunela ku-<xliff:g id="CHANNEL_NAME">%s</xliff:g>"</string>
- <string name="ut_fail_to_tune_to_unknown_channel" msgid="5601031631838024181">"Yehlulekile ukushuna"</string>
- <string name="ut_rescan_needed" msgid="6652963050118174284">"Isofthiwe ye-USB tuner isanda kubuyekezwa. Sicela uskene kabusha iziteshi."</string>
- <string name="ut_ac3_passthrough_unavailable" msgid="1511045190687189559">"Umsindo we-AC3 awutholakali"</string>
- <string name="ut_setup_breadcrumb" msgid="3057650688133018018">"Ukusethwa kweshuna yesiteshi"</string>
- <string name="ut_setup_new_title" msgid="4919412630138697597">"Ukusethwa kweshuna yesiteshi se-USB"</string>
- <string name="ut_setup_new_description" msgid="3950618124169419729">"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-array name="ut_setup_new_choices">
- <item msgid="4294610848989236664">"Qhubeka"</item>
- <item msgid="7745727658174773453">"Hhayi manje"</item>
- </string-array>
- <string name="ut_setup_again_title" msgid="7493163856853246710">"Phinda uqalise ukusethwa kwesiteshi?"</string>
- <string name="ut_setup_again_description" msgid="6974243332718382952">"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-array name="ut_setup_again_choices">
- <item msgid="8729290093918719208">"Qhubeka"</item>
- <item msgid="4432431398374089710">"Khansela"</item>
- </string-array>
- <string name="ut_connection_title" msgid="1689960211113015793">"Khetha uhlobo lokuxhumeka"</string>
- <string name="ut_connection_description" msgid="3218265227667113165">"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="1633072563555330217">"I-Antenna"</item>
- <item msgid="2445879869338877559">"Ikhebuli"</item>
- <item msgid="597328838068074806">"Angiqinisekile"</item>
- <item msgid="3613410733017077040">"Ukuthuthukiswa kuphela"</item>
- </string-array>
- <string name="ut_channel_scan" msgid="5275436876483779315">"Ukusetha kweshuna yesiteshi se-USB"</string>
- <string name="ut_channel_scan_time" msgid="5108578893396614867">"Lokhu kungathatha amaminithi athile"</string>
- <plurals name="ut_channel_scan_message" formatted="false" msgid="8883404542863956040">
- <item quantity="one">%1$d iziteshi ezitholakele</item>
- <item quantity="other">%1$d iziteshi ezitholakele</item>
- </plurals>
- <string name="ut_stop_channel_scan" msgid="8358794117343664624">"MISA UKUSKENA KWESITESHI"</string>
- <plurals name="ut_result_found_title" formatted="false" msgid="4621251784881527371">
- <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="1946474144459881182">
- <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="979481834388007277">"Kwenziwe"</item>
- <item msgid="496688122303154468">"Skena futhi"</item>
- </string-array>
- <string name="ut_result_not_found_title" msgid="3367485970267699896">"Azikho iziteshi ezitholiwe"</string>
- <string name="ut_result_not_found_description" msgid="2230088613315287072">"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-array name="ut_result_not_found_choices">
- <item msgid="6593834378620684951">"Skena futhi"</item>
- <item msgid="6784975565864102291">"Kwenziwe"</item>
- </string-array>
- <string name="ut_setup_recommendation_card_focused_title" msgid="1003442802579648042">"Skenela iziteshi ze-TV"</string>
- <string name="ut_setup_recommendation_card_title" msgid="4192974818384769494">"Ukusetha kweshuna yesiteshi se-USB"</string>
-</resources>
diff --git a/usbtuner/res/values/themes.xml b/usbtuner/res/values/themes.xml
deleted file mode 100644
index a3c24661..00000000
--- a/usbtuner/res/values/themes.xml
+++ /dev/null
@@ -1,32 +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>
- <style name="Theme.UsbTunerSetup.Leanback.GuidedStep" parent="Theme.Leanback.GuidedStep">
- <item name="guidanceContainerStyle">@style/ut_guidance_container</item>
- <item name="guidanceTitleStyle">@style/ut_guidance_title</item>
- <item name="guidanceBreadcrumbStyle">@style/ut_guidance_breadcrumb</item>
- <item name="guidanceDescriptionStyle">@style/ut_guidance_desc</item>
- <item name="guidedActionsContainerStyle">@style/ut_guidedactions_container</item>
- <item name="guidedActionsSelectorStyle">@style/ut_guidedactions_null_selector</item>
- <item name="guidedActionsListStyle">@style/ut_guidedactions_list</item>
- <item name="guidedActionItemContainerStyle">@style/ut_guidedactions_item_container</item>
- <item name="guidedActionItemTitleStyle">@style/ut_guidedactions_item_title</item>
- <item name="guidedActionItemCheckmarkStyle">@style/ut_guidedactions_item_checkmark</item>
- <item name="guidedActionItemChevronStyle">@style/ut_guidedactions_item_chevron</item>
- </style>
-</resources>
diff --git a/usbtuner/src/com/android/usbtuner/InputStreamSource.java b/usbtuner/src/com/android/usbtuner/InputStreamSource.java
deleted file mode 100644
index 12587d9a..00000000
--- a/usbtuner/src/com/android/usbtuner/InputStreamSource.java
+++ /dev/null
@@ -1,73 +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.usbtuner;
-
-import com.android.usbtuner.ChannelScanFileParser.ScanChannel;
-import com.android.usbtuner.data.TunerChannel;
-
-/**
- * Interface definition for stream source. Source based on physical tuner or files should implement
- * this interface.
- */
-public interface InputStreamSource extends AutoCloseable {
- /**
- * @return a type of the source. Either {@code TYPE_TUNER} or {@code TYPE_FILE}.
- */
- int getType();
-
- /**
- * Get the source ready to provide stream for channel scanning process.
- *
- * @param channel {@link ScanChannel} to be scanned
- * @return {@code true} if the source is ready, otherwise {@code false}
- */
- boolean setScanChannel(ScanChannel channel);
-
- /**
- * Tune to a channel to start viewing.
- *
- * @param channel {@link TunerChannel} to view
- * @return {@code true} if tuning was successful, otherwise {@code false}
- */
- boolean tuneToChannel(TunerChannel channel);
-
- /**
- * Start streaming the data.
- */
- void startStream();
-
- /**
- * Stop streaming the data.
- */
- void stopStream();
-
- /**
- * Returns the limit of a input source in bytes. This return value means the number of bytes
- * reading from a tuner device.
- *
- * @return the limit of a input source
- */
- long getLimit();
-
- /**
- * Returns the position of a input source in bytes. This return value means the number of bytes
- * taken by a reader (for example, {@link MediaExtractor}).
- *
- * @return the position of a input source
- */
- long getPosition();
-}
diff --git a/usbtuner/src/com/android/usbtuner/InternalTunerHal.java b/usbtuner/src/com/android/usbtuner/InternalTunerHal.java
deleted file mode 100644
index 50832aae..00000000
--- a/usbtuner/src/com/android/usbtuner/InternalTunerHal.java
+++ /dev/null
@@ -1,57 +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.usbtuner;
-
-import android.content.Context;
-
-/**
- * A class to handle one internal tuner device.
- */
-public class InternalTunerHal extends TunerHal {
-
- private boolean isDeviceOpen;
-
- protected InternalTunerHal(Context context) {
- super(context);
- isDeviceOpen = false;
- }
-
- @Override
- protected boolean openFirstAvailable() {
- isDeviceOpen = true;
- return true;
- }
-
- @Override
- public void close() {
- if (isStreaming()) {
- stopTune();
- }
- nativeFinalize(getDeviceId());
- isDeviceOpen = false;
- }
-
- @Override
- protected boolean isDeviceOpen() {
- return (isDeviceOpen);
- }
-
- @Override
- protected long getDeviceId() {
- return 0L;
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/UsbTunerDataSource.java b/usbtuner/src/com/android/usbtuner/UsbTunerDataSource.java
deleted file mode 100644
index 0d139311..00000000
--- a/usbtuner/src/com/android/usbtuner/UsbTunerDataSource.java
+++ /dev/null
@@ -1,310 +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.usbtuner;
-
-import android.media.MediaDataSource;
-import android.util.Log;
-
-import com.android.usbtuner.ChannelScanFileParser.ScanChannel;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.tvinput.EventDetector;
-import com.android.usbtuner.tvinput.EventDetector.EventListener;
-import com.android.usbtuner.tvinput.UsbTunerDebug;
-
-import java.io.IOException;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A {@link MediaDataSource} implementation which provides the mpeg2ts stream from the tuner device
- * to {@link MediaExtractor}.
- */
-public class UsbTunerDataSource extends MediaDataSource implements InputStreamSource {
- private static final String TAG = "UsbTunerDataSource";
-
- private static final int MIN_READ_UNIT = 1500;
- private static final int READ_BUFFER_SIZE = MIN_READ_UNIT * 10; // ~15KB
- private static final int CIRCULAR_BUFFER_SIZE = MIN_READ_UNIT * 20000; // ~ 30MB
-
- private static final int READ_TIMEOUT_MS = 5000; // 5 secs.
- private static final int BUFFER_UNDERRUN_SLEEP_MS = 10;
-
- private static final int CACHE_KEY_VERSION = 1;
-
- // UTCK stands for USB Tuner Cache Key.
- private static final String CACHE_KEY_PREFIX = "UTCK";
-
- private final Object mCircularBufferMonitor = new Object();
- private final byte[] mCircularBuffer = new byte[CIRCULAR_BUFFER_SIZE];
- private long mBytesFetched;
- private final AtomicLong mLastReadPosition = new AtomicLong();
- private boolean mEndOfStreamSent;
- private boolean mStreaming;
-
- private final TunerHal mTunerHal;
- private Thread mStreamingThread;
- private boolean mDeviceConfigured;
- private EventDetector mEventDetector;
-
- public UsbTunerDataSource(TunerHal tunerHal, EventListener eventListener) {
- mTunerHal = tunerHal;
- mEventDetector = new EventDetector(mTunerHal, eventListener);
- }
-
- /**
- * Starts the streaming of a configured program. Throws a runtime exception if no channel and
- * program have successfully been configured yet.
- */
- @Override
- public void startStream() {
- if (!mDeviceConfigured) {
- throw new RuntimeException("Channel and program not configured!");
- }
-
- synchronized (mCircularBufferMonitor) {
- if (mStreaming) {
- Log.w(TAG, "Streaming should be stopped before start streaming");
- return;
- }
- mStreaming = true;
- mBytesFetched = 0;
- mLastReadPosition.set(0L);
- mEndOfStreamSent = false;
- }
-
- mStreamingThread = new StreamingThread();
- mStreamingThread.start();
- Log.i(TAG, "Streaming started");
- }
-
- /**
- * Sets the channel required to start streaming from this device. Afterwards, prepares the tuner
- * device for streaming. Package retrieval can be made at any time after invoking this method
- * and before stopping the stream.
- *
- * @param channel a {@link TunerChannel} instance tune to
- * @return {@code true} if the entire operation was successful; {@code false} otherwise
- */
- @Override
- public boolean tuneToChannel(TunerChannel channel) {
- if (mTunerHal.tune(channel.getFrequency(), channel.getModulation())) {
- if (channel.hasVideo()) {
- mTunerHal.addPidFilter(channel.getVideoPid(),
- TunerHal.FILTER_TYPE_VIDEO);
- }
- if (channel.hasAudio()) {
- mTunerHal.addPidFilter(channel.getAudioPid(),
- TunerHal.FILTER_TYPE_AUDIO);
- }
- mTunerHal.addPidFilter(channel.getPcrPid(),
- TunerHal.FILTER_TYPE_PCR);
- if (mEventDetector != null) {
- mEventDetector.startDetecting(channel.getFrequency(), channel.getModulation());
- }
- mDeviceConfigured = true;
- return true;
- }
- return false;
- }
-
- /**
- * Blocks the current thread until the streaming thread stops. In rare cases when the tuner
- * device is overloaded this can take a while, but usually it returns pretty quickly.
- */
- @Override
- public void stopStream() {
- synchronized (mCircularBufferMonitor) {
- mStreaming = false;
- mCircularBufferMonitor.notify();
- }
-
- try {
- if (mStreamingThread != null) {
- mStreamingThread.join();
- }
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- } finally {
- mTunerHal.stopTune();
- }
- }
-
- @Override
- public long getLimit() {
- synchronized (mCircularBufferMonitor) {
- return mBytesFetched;
- }
- }
-
- @Override
- public long getPosition() {
- return mLastReadPosition.get();
- }
-
- private class StreamingThread extends Thread {
- @Override
- public void run() {
- // Buffers for streaming data from the tuner and the internal buffer.
- byte[] dataBuffer = new byte[READ_BUFFER_SIZE];
-
- while (true) {
- synchronized (mCircularBufferMonitor) {
- if (!mStreaming) {
- break;
- }
- }
-
- int bytesWritten = mTunerHal.readTsStream(dataBuffer, dataBuffer.length);
- if (bytesWritten <= 0) {
- try {
- // When buffer is underrun, we sleep for short time to prevent
- // unnecessary CPU draining.
- sleep(BUFFER_UNDERRUN_SLEEP_MS);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- }
- continue;
- }
-
- if (mEventDetector != null) {
- mEventDetector.feedTSStream(dataBuffer, 0, bytesWritten);
- }
- synchronized (mCircularBufferMonitor) {
- int posInBuffer = (int) (mBytesFetched % CIRCULAR_BUFFER_SIZE);
- int bytesToCopyInFirstPass = bytesWritten;
- if (posInBuffer + bytesToCopyInFirstPass > mCircularBuffer.length) {
- bytesToCopyInFirstPass = mCircularBuffer.length - posInBuffer;
- }
- System.arraycopy(dataBuffer, 0, mCircularBuffer, posInBuffer,
- bytesToCopyInFirstPass);
- if (bytesToCopyInFirstPass < bytesWritten) {
- System.arraycopy(dataBuffer, bytesToCopyInFirstPass, mCircularBuffer, 0,
- bytesWritten - bytesToCopyInFirstPass);
- }
- mBytesFetched += bytesWritten;
- mCircularBufferMonitor.notify();
- }
- }
-
- Log.i(TAG, "Streaming stopped");
- }
- }
-
- @Override
- public int readAt(long pos, byte[] buffer, int offset, int amount) throws IOException {
- synchronized (mCircularBufferMonitor) {
- if (mEndOfStreamSent) {
- // Nothing was received during READ_TIMEOUT_MS before.
- return -1;
- }
- if (mBytesFetched - CIRCULAR_BUFFER_SIZE > pos) {
- // Not available at circular buffer.
- Log.w(TAG, "Not available at circular buffer");
- return -1;
- }
- long initialBytesFetched = mBytesFetched;
- while (mBytesFetched < pos + amount && mStreaming) {
- try {
- mCircularBufferMonitor.wait(READ_TIMEOUT_MS);
- } catch (InterruptedException e) {
- // Wait again.
- Thread.currentThread().interrupt();
- }
- if (initialBytesFetched == mBytesFetched) {
- Log.w(TAG, "No data update for " + READ_TIMEOUT_MS + "ms. returning -1.");
-
- // Returning -1 will make demux report EOS so that the input service can retry
- // the playback.
- mEndOfStreamSent = true;
- return -1;
- }
- }
- if (!mStreaming) {
- Log.w(TAG, "Stream is already stopped.");
- return -1;
- }
- if (mBytesFetched - CIRCULAR_BUFFER_SIZE > pos) {
- Log.e(TAG, "Demux is requesting the data which is already overwritten.");
- return -1;
- }
- int posInBuffer = (int) (pos % CIRCULAR_BUFFER_SIZE);
- int bytesToCopyInFirstPass = amount;
- if (posInBuffer + bytesToCopyInFirstPass > mCircularBuffer.length) {
- bytesToCopyInFirstPass = mCircularBuffer.length - posInBuffer;
- }
- System.arraycopy(mCircularBuffer, posInBuffer, buffer, offset, bytesToCopyInFirstPass);
- if (bytesToCopyInFirstPass < amount) {
- System.arraycopy(mCircularBuffer, 0, buffer, offset + bytesToCopyInFirstPass,
- amount - bytesToCopyInFirstPass);
- }
- mLastReadPosition.set(pos + amount);
- mCircularBufferMonitor.notify();
-
- if (UsbTunerDebug.ENABLED) {
- UsbTunerDebug.setBytesInQueue((int) (mBytesFetched - mLastReadPosition.get()));
- }
-
- return amount;
- }
- }
-
- @Override
- public long getSize() throws IOException {
- return -1;
- }
-
- @Override
- public void close() {
- // Called from system MediaExtractor. All the resource should be closed
- // in stopStream() already.
- }
-
- @Override
- public int getType() {
- return Channel.TYPE_TUNER;
- }
-
- @Override
- public boolean setScanChannel(ScanChannel channel) {
- return false;
- }
-
- public static String generateCacheKey(TunerChannel channel, long timestampMs) {
- return String.format(Locale.ENGLISH, "%s-%x-%x-%x-%x", CACHE_KEY_PREFIX, CACHE_KEY_VERSION,
- channel.getFrequency(), channel.getProgramNumber(), timestampMs);
- }
-
- /**
- * Parses the timestamp from a cache key generated by {@link #generateCacheKey}.
- *
- * @param cacheKey a cache key generated by {@link #generateCacheKey}
- * @return the timestamp parsed from the given cache key. {@code -1} if unable to parse.
- */
- public static long parseTimestampFromCacheKey(String cacheKey) {
- String[] tokens = cacheKey.split("-");
- if (tokens.length < 2 || !tokens[0].equals(CACHE_KEY_PREFIX)) {
- return -1;
- }
- int version = Integer.parseInt(tokens[1], 16);
- if (version == 1) {
- return Long.parseLong(tokens[4], 16);
- } else {
- return -1;
- }
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/UsbTunerPreferences.java b/usbtuner/src/com/android/usbtuner/UsbTunerPreferences.java
deleted file mode 100644
index 0394648d..00000000
--- a/usbtuner/src/com/android/usbtuner/UsbTunerPreferences.java
+++ /dev/null
@@ -1,195 +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.usbtuner;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.database.Cursor;
-import android.os.AsyncTask;
-import android.os.Bundle;
-
-import com.android.tv.common.SoftPreconditions;
-import com.android.usbtuner.UsbTunerPreferenceProvider.Preferences;
-import com.android.usbtuner.util.TisConfiguration;
-
-/**
- * A helper class for the USB tuner preferences.
- */
-// TODO: Change this class to run on the worker thread.
-public class UsbTunerPreferences {
- private static final String TAG = "UsbTunerPreferences";
-
- 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_LAUNCH_SETUP = "launch_setup";
-
- private static final String SHARED_PREFS_NAME = "com.android.usbtuner.preferences";
-
- private static final Bundle PREFERENCE_VALUES = new Bundle();
-
- private static boolean useContentProvider(Context context) {
- // If TIS is a part of LC, it should use ContentProvider to resolve multiple process access.
- return TisConfiguration.isPackagedWithLiveChannels(context);
- }
-
- public static int getChannelDataVersion(Context context) {
- if (useContentProvider(context)) {
- return getPreferenceInt(context, PREFS_KEY_CHANNEL_DATA_VERSION);
- } else {
- return getSharedPreferences(context)
- .getInt(UsbTunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, 0);
- }
- }
-
- public static void setChannelDataVersion(Context context, int version) {
- if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_CHANNEL_DATA_VERSION, version);
- } else {
- getSharedPreferences(context).edit()
- .putInt(UsbTunerPreferences.PREFS_KEY_CHANNEL_DATA_VERSION, version)
- .apply();
- }
- }
-
- public static int getScannedChannelCount(Context context) {
- if (useContentProvider(context)) {
- return getPreferenceInt(context, PREFS_KEY_SCANNED_CHANNEL_COUNT);
- } else {
- return getSharedPreferences(context)
- .getInt(UsbTunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, 0);
- }
- }
-
- public static void setScannedChannelCount(Context context, int channelCount) {
- if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount);
- } else {
- getSharedPreferences(context).edit()
- .putInt(UsbTunerPreferences.PREFS_KEY_SCANNED_CHANNEL_COUNT, channelCount)
- .apply();
- }
- }
-
- public static boolean isScanDone(Context context) {
- if (useContentProvider(context)) {
- return getPreferenceBoolean(context, PREFS_KEY_SCAN_DONE);
- } else {
- return getSharedPreferences(context)
- .getBoolean(UsbTunerPreferences.PREFS_KEY_SCAN_DONE, false);
- }
- }
-
- public static void setScanDone(Context context) {
- if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_SCAN_DONE, true);
- } else {
- getSharedPreferences(context).edit()
- .putBoolean(UsbTunerPreferences.PREFS_KEY_SCAN_DONE, true)
- .apply();
- }
- }
-
- public static boolean shouldShowSetupActivity(Context context) {
- if (useContentProvider(context)) {
- return getPreferenceBoolean(context, PREFS_KEY_LAUNCH_SETUP);
- } else {
- return getSharedPreferences(context)
- .getBoolean(UsbTunerPreferences.PREFS_KEY_LAUNCH_SETUP, false);
- }
- }
-
- public static void setShouldShowSetupActivity(Context context, boolean need) {
- if (useContentProvider(context)) {
- setPreference(context, PREFS_KEY_LAUNCH_SETUP, need);
- } else {
- getSharedPreferences(context).edit()
- .putBoolean(UsbTunerPreferences.PREFS_KEY_LAUNCH_SETUP, need)
- .apply();
- }
- }
-
- private static SharedPreferences getSharedPreferences(Context context) {
- return context.getSharedPreferences(SHARED_PREFS_NAME, Context.MODE_PRIVATE);
- }
-
- // Content provider helpers
- private static String getPreference(Context context, String key) {
- ContentResolver resolver = context.getContentResolver();
- String[] projection = new String[] { Preferences.COLUMN_VALUE };
- String selection = Preferences.COLUMN_KEY + " like ?";
- String[] selectionArgs = new String[] { key };
- try (Cursor cursor = resolver.query(UsbTunerPreferenceProvider.buildPreferenceUri(key),
- projection, selection, selectionArgs, null)) {
- if (cursor != null && cursor.moveToFirst()) {
- return cursor.getString(0);
- }
- } catch (Exception e) {
- SoftPreconditions.warn(TAG, "getPreference", "Error querying preference values", e);
- }
- return null;
- }
-
- private static int getPreferenceInt(Context context, String key) {
- if (PREFERENCE_VALUES.containsKey(key)) {
- return PREFERENCE_VALUES.getInt(key);
- }
- try {
- return Integer.parseInt(getPreference(context, key));
- } catch (NumberFormatException e) {
- return 0;
- }
- }
-
- private static boolean getPreferenceBoolean(Context context, String key) {
- if (PREFERENCE_VALUES.containsKey(key)) {
- return PREFERENCE_VALUES.getBoolean(key);
- }
- return Boolean.valueOf(getPreference(context, key));
- }
-
- private static void setPreference(final Context context, final String key, final String value) {
- new AsyncTask<Void, Void, Void>() {
- @Override
- protected Void doInBackground(Void... params) {
- ContentResolver resolver = context.getContentResolver();
- ContentValues values = new ContentValues();
- values.put(Preferences.COLUMN_KEY, key);
- values.put(Preferences.COLUMN_VALUE, value);
- try {
- resolver.insert(Preferences.CONTENT_URI, values);
- } catch (Exception e) {
- SoftPreconditions.warn(TAG, "setPreference", "Error writing preference values",
- e);
- }
- return null;
- }
- }.execute();
- }
-
- private static void setPreference(Context context, String key, int value) {
- PREFERENCE_VALUES.putInt(key, value);
- setPreference(context, key, Integer.toString(value));
- }
-
- private static void setPreference(Context context, String key, boolean value) {
- PREFERENCE_VALUES.putBoolean(key, value);
- setPreference(context, key, Boolean.toString(value));
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/UsbTunerTsScannerSource.java b/usbtuner/src/com/android/usbtuner/UsbTunerTsScannerSource.java
deleted file mode 100644
index fd7f8838..00000000
--- a/usbtuner/src/com/android/usbtuner/UsbTunerTsScannerSource.java
+++ /dev/null
@@ -1,156 +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.usbtuner;
-
-import android.content.Context;
-import android.util.Log;
-
-import com.android.tv.common.AutoCloseableUtils;
-import com.android.usbtuner.ChannelScanFileParser.ScanChannel;
-import com.android.usbtuner.data.Channel;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.tvinput.EventDetector;
-import com.android.usbtuner.tvinput.EventDetector.EventListener;
-
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A class that processes mpeg2ts stream coming from a tuner.
- */
-public class UsbTunerTsScannerSource implements InputStreamSource {
- // TODO: Refactor with {@link UsbTunerDataSource}.
-
- private static final String TAG = "UsbTunerTsScannerSource";
-
- private static final int MIN_READ_UNIT = 1500;
- private static final int READ_BUFFER_SIZE = MIN_READ_UNIT * 10; // ~15KB
-
- private boolean mStreaming;
-
- private final TunerHal mTunerHal;
- private Thread mStreamingThread;
- private boolean mDeviceConfigured;
- private final EventDetector mEventDetector;
- private final AtomicLong mBytesFetched = new AtomicLong();
-
- public UsbTunerTsScannerSource(Context context, EventListener eventListener) {
- mTunerHal = TunerHal.createInstance(context);
- if (mTunerHal == null) {
- throw new RuntimeException("Failed to open a DVB device");
- }
- mEventDetector = new EventDetector(mTunerHal, eventListener);
- }
-
- /**
- * Starts the streaming of a configured program. Throws a runtime exception if no channel and
- * program have successfully been configured yet.
- */
- @Override
- public void startStream() {
- if (!mDeviceConfigured) {
- throw new RuntimeException("Channel and program not configured!");
- }
-
- mBytesFetched.set(0L);
- mStreaming = true;
- mStreamingThread = new StreamingThread();
- mStreamingThread.start();
- Log.i(TAG, "Streaming started");
- }
-
- @Override
- public boolean setScanChannel(ScanChannel channel) {
- if (mTunerHal.tune(channel.frequency, channel.modulation)) {
- mEventDetector.startDetecting(channel.frequency, channel.modulation);
- mDeviceConfigured = true;
- return true;
- }
- return false;
- }
-
- @Override
- public boolean tuneToChannel(TunerChannel channel) {
- return false;
- }
-
- public List<TunerChannel> getIncompleteChannels() {
- return mEventDetector.getIncompleteChannels();
- }
-
- /**
- * Blocks the current thread until the streaming thread stops. In rare cases when the tuner
- * device is overloaded this can take a while, but usually it returns pretty quickly.
- */
- @Override
- public void stopStream() {
- mStreaming = false;
-
- try {
- if (mStreamingThread != null) {
- mStreamingThread.join();
- }
- } catch (InterruptedException e) {
- Log.e(TAG, "Interrupted while joining the streaming thread.", e);
- }
- }
-
- @Override
- public long getLimit() {
- return mBytesFetched.get();
- }
-
- @Override
- public long getPosition() {
- return 0L;
- }
-
- @Override
- public void close() {
- AutoCloseableUtils.closeQuietly(mTunerHal);
- }
-
- private class StreamingThread extends Thread {
-
- @Override
- public void run() {
- // Buffers for streaming data from the tuner and the internal buffer.
- byte[] dataBuffer = new byte[READ_BUFFER_SIZE];
-
- while (true) {
- if (!mStreaming) {
- break;
- }
- int bytesWritten;
- bytesWritten = mTunerHal.readTsStream(dataBuffer, dataBuffer.length);
- if (bytesWritten <= 0) {
- continue;
- }
- mBytesFetched.addAndGet(bytesWritten);
-
- mEventDetector.feedTSStream(dataBuffer, 0, bytesWritten);
- }
-
- Log.i(TAG, "Streaming stopped");
- }
- }
-
- @Override
- public int getType() {
- return Channel.TYPE_TUNER;
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSourceExtractor.java b/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSourceExtractor.java
deleted file mode 100644
index 7a7248be..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/MpegTsSampleSourceExtractor.java
+++ /dev/null
@@ -1,293 +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.usbtuner.exoplayer;
-
-import android.media.MediaDataSource;
-
-import com.google.android.exoplayer.MediaFormat;
-import com.google.android.exoplayer.MediaFormatHolder;
-import com.google.android.exoplayer.MediaFormatUtil;
-import com.google.android.exoplayer.SampleHolder;
-import com.google.android.exoplayer.SampleSource;
-import com.google.android.exoplayer.util.MimeTypes;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-
-/**
- * Extracts samples from {@link MediaDataSource} for MPEG-TS streams.
- */
-public final class MpegTsSampleSourceExtractor implements SampleExtractor {
- public static final String MIMETYPE_TEXT_CEA_708 = "text/cea-708";
-
- private static final int CC_BUFFER_SIZE_IN_BYTES = 9600 / 8;
-
- private final SampleExtractor mSampleExtractor;
- private MediaFormat[] mTrackFormats;
- private boolean[] mGotEos;
- private int mVideoTrackIndex;
- private int mCea708TextTrackIndex;
- private boolean mCea708TextTrackSelected;
- private ByteBuffer mCea708CcBuffer;
-
- private long mCea708PresentationTimeUs;
- private CcParser mCcParser;
-
- private void init() {
- mVideoTrackIndex = -1;
- mCea708TextTrackIndex = -1;
- mCea708CcBuffer = ByteBuffer.allocate(CC_BUFFER_SIZE_IN_BYTES);
- mCea708PresentationTimeUs = -1;
- mCea708TextTrackSelected = false;
- }
-
- /**
- * Creates MpegTsSampleSourceExtractor for {@link MediaDataSource}.
- *
- * @param source the {@link MediaDataSource} to extract from
- * @param cacheManager the manager for reading & writing samples backed by physical storage
- * @param cacheListener the {@link com.android.usbtuner.tvinput.PlaybackCacheListener}
- * to notify cache storage status change
- */
- public MpegTsSampleSourceExtractor(MediaDataSource source,
- CacheManager cacheManager, PlaybackCacheListener cacheListener) {
- if (cacheManager == null || cacheManager.isDisabled()) {
- mSampleExtractor =
- new PlaySampleExtractor(source, cacheManager, cacheListener, false);
-
- } else {
- mSampleExtractor =
- new PlaySampleExtractor(source, cacheManager, cacheListener, true);
- }
- init();
- }
-
- /**
- * Creates MpegTsSampleSourceExtractor for a recorded program.
- *
- * @param cacheManager the samples provider which is stored in physical storage
- * @param cacheListener the {@link com.android.usbtuner.tvinput.PlaybackCacheListener}
- * to notify cache storage status change
- */
- public MpegTsSampleSourceExtractor(CacheManager cacheManager,
- PlaybackCacheListener cacheListener) {
- mSampleExtractor = new ReplaySampleSourceExtractor(cacheManager, cacheListener);
- init();
- }
-
- @Override
- public boolean prepare() throws IOException {
- if(!mSampleExtractor.prepare()) {
- return false;
- }
- MediaFormat trackFormats[] = mSampleExtractor.getTrackFormats();
- int trackCount = trackFormats.length;
- mGotEos = new boolean[trackCount];
-
- for (int i = 0; i < trackCount; ++i) {
- String mime = trackFormats[i].mimeType;
- if (MimeTypes.isVideo(mime) && mVideoTrackIndex == -1) {
- mVideoTrackIndex = i;
- if (android.media.MediaFormat.MIMETYPE_VIDEO_MPEG2.equals(mime)) {
- mCcParser = new Mpeg2CcParser();
- } else if (android.media.MediaFormat.MIMETYPE_VIDEO_AVC.equals(mime)) {
- mCcParser = new H264CcParser();
- }
- }
- }
-
- if (mVideoTrackIndex != -1) {
- mCea708TextTrackIndex = trackCount;
- }
- mTrackFormats = new MediaFormat[mCea708TextTrackIndex < 0 ? trackCount : trackCount + 1];
- System.arraycopy(trackFormats, 0, mTrackFormats, 0, trackCount);
- if (mCea708TextTrackIndex >= 0) {
- mTrackFormats[trackCount] = MediaFormatUtil.createTextMediaFormat(MIMETYPE_TEXT_CEA_708,
- mTrackFormats[0].durationUs);
- }
- return true;
- }
-
- @Override
- public MediaFormat[] getTrackFormats() {
- return mTrackFormats;
- }
-
- @Override
- public void selectTrack(int index) {
- if (index == mCea708TextTrackIndex) {
- mCea708TextTrackSelected = true;
- return;
- }
- mSampleExtractor.selectTrack(index);
- }
-
- @Override
- public void deselectTrack(int index) {
- if (index == mCea708TextTrackIndex) {
- mCea708TextTrackSelected = false;
- return;
- }
- mSampleExtractor.deselectTrack(index);
- }
-
- @Override
- public long getBufferedPositionUs() {
- return mSampleExtractor.getBufferedPositionUs();
- }
-
- @Override
- public void seekTo(long positionUs) {
- mSampleExtractor.seekTo(positionUs);
- }
-
- @Override
- public void getTrackMediaFormat(int track, MediaFormatHolder outMediaFormatHolder) {
- if (track != mCea708TextTrackIndex) {
- mSampleExtractor.getTrackMediaFormat(track, outMediaFormatHolder);
- }
- }
-
- @Override
- public int readSample(int track, SampleHolder sampleHolder) {
- if (track == mCea708TextTrackIndex) {
- if (mCea708TextTrackSelected && mCea708CcBuffer.position() > 0) {
- mCea708CcBuffer.flip();
- sampleHolder.timeUs = mCea708PresentationTimeUs;
- sampleHolder.data.put(mCea708CcBuffer);
- mCea708CcBuffer.clear();
- return SampleSource.SAMPLE_READ;
- } else {
- return mVideoTrackIndex < 0 || mGotEos[mVideoTrackIndex]
- ? SampleSource.END_OF_STREAM : SampleSource.NOTHING_READ;
- }
- }
-
- // Should read CC track first.
- if (mCea708TextTrackSelected && mCea708CcBuffer.position() > 0) {
- return mGotEos[track] ? SampleSource.END_OF_STREAM : SampleSource.NOTHING_READ;
- }
-
- int result = mSampleExtractor.readSample(track, sampleHolder);
- switch (result) {
- case SampleSource.END_OF_STREAM: {
- mGotEos[track] = true;
- break;
- }
- case SampleSource.SAMPLE_READ: {
- if (mCea708TextTrackSelected && track == mVideoTrackIndex
- && sampleHolder.data != null) {
- mCcParser.mayParseClosedCaption(sampleHolder.data, sampleHolder.timeUs);
- }
- break;
- }
- }
- return result;
- }
-
- @Override
- public void release() {
- mSampleExtractor.release();
- mVideoTrackIndex = -1;
- mCea708TextTrackIndex = -1;
- mCea708TextTrackSelected = false;
- }
-
- @Override
- public boolean continueBuffering(long positionUs) {
- return mSampleExtractor.continueBuffering(positionUs);
- }
-
- private abstract class CcParser {
- abstract void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs);
-
- protected void parseClosedCaption(ByteBuffer buffer, int offset, long presentationTimeUs) {
- // For the details of user_data_type_structure, see ATSC A/53 Part 4 - Table 6.9.
- int pos = offset;
- if (pos + 2 >= buffer.position()) {
- return;
- }
- boolean processCcDataFlag = (buffer.get(pos) & 64) != 0;
- int ccCount = buffer.get(pos) & 0x1f;
- pos += 2;
- if (!processCcDataFlag || pos + 3 * ccCount >= buffer.position() || ccCount == 0) {
- return;
- }
- for (int i = 0; i < 3 * ccCount; i++) {
- mCea708CcBuffer.put(buffer.get(pos + i));
- }
- mCea708PresentationTimeUs = presentationTimeUs;
- }
- }
-
- private class Mpeg2CcParser extends CcParser {
- @Override
- public void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs) {
- int pos = 0;
- while (pos + 9 < buffer.position()) {
- // Find the start prefix code of private user data.
- if (buffer.get(pos) == 0
- && buffer.get(pos + 1) == 0
- && buffer.get(pos + 2) == 1
- && (buffer.get(pos + 3) & 0xff) == 0xb2) {
- // ATSC closed caption data embedded in MPEG2VIDEO stream has 'GA94' user
- // identifier and user data type code 3.
- if (buffer.get(pos + 4) == 'G'
- && buffer.get(pos + 5) == 'A'
- && buffer.get(pos + 6) == '9'
- && buffer.get(pos + 7) == '4'
- && buffer.get(pos + 8) == 3) {
- parseClosedCaption(buffer, pos + 9, presentationTimeUs);
- }
- pos += 9;
- } else {
- ++pos;
- }
- }
- }
- }
-
- private class H264CcParser extends CcParser {
- @Override
- public void mayParseClosedCaption(ByteBuffer buffer, long presentationTimeUs) {
- int pos = 0;
- while (pos + 7 < buffer.position()) {
- // Find the start prefix code of a NAL Unit.
- if (buffer.get(pos) == 0
- && buffer.get(pos + 1) == 0
- && buffer.get(pos + 2) == 1) {
- int nalType = buffer.get(pos + 3) & 0x1f;
- int payloadType = buffer.get(pos + 4) & 0xff;
-
- // ATSC closed caption data embedded in H264 private user data has NAL type 6,
- // payload type 4, and 'GA94' user identifier for ATSC.
- if (nalType == 6 && payloadType == 4 && buffer.get(pos + 9) == 'G'
- && buffer.get(pos + 10) == 'A'
- && buffer.get(pos + 11) == '9'
- && buffer.get(pos + 12) == '4') {
- parseClosedCaption(buffer, pos + 14, presentationTimeUs);
- }
- pos += 7;
- } else {
- ++pos;
- }
- }
- }
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/PlaySampleExtractor.java b/usbtuner/src/com/android/usbtuner/exoplayer/PlaySampleExtractor.java
deleted file mode 100644
index e249e3cb..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/PlaySampleExtractor.java
+++ /dev/null
@@ -1,228 +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.usbtuner.exoplayer;
-
-import android.media.MediaDataSource;
-import android.media.MediaExtractor;
-import android.os.ConditionVariable;
-import android.os.SystemClock;
-import android.util.Log;
-
-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.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.RecordingSampleBuffer;
-import com.android.usbtuner.exoplayer.cache.SimpleSampleBuffer;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * A class that plays a live stream from a given media extractor using an extractor thread.
- */
-public class PlaySampleExtractor implements SampleExtractor {
- private static final String TAG = "PlaySampleExtractor";
-
- // 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 AtomicLong ID_COUNTER = new AtomicLong(0);
-
- private final MediaDataSource mDataSource;
- private final MediaExtractor mMediaExtractor;
- private final ExtractorThread mExtractorThread;
- private final CacheManager.SampleBuffer mSampleBuffer;
- private final long mId;
- private MediaFormat[] mTrackFormats;
-
- private boolean mReleased = false;
-
- public PlaySampleExtractor(MediaDataSource source, CacheManager cacheManager,
- PlaybackCacheListener cacheListener, boolean useCache) {
- mId = ID_COUNTER.incrementAndGet();
- mDataSource = source;
- mMediaExtractor = new MediaExtractor();
- mExtractorThread = new ExtractorThread();
- if (useCache) {
- mSampleBuffer = new RecordingSampleBuffer(cacheManager, cacheListener, true,
- RecordingSampleBuffer.CACHE_REASON_LIVE_PLAYBACK);
- } else {
- mSampleBuffer = new SimpleSampleBuffer(cacheListener);
- }
- }
-
- private class ExtractorThread extends Thread {
- private volatile boolean mQuitRequested = false;
-
- public ExtractorThread() {
- super("ExtractorThread");
- }
-
- @Override
- public void run() {
- SampleHolder sample = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
- sample.ensureSpaceForWrite(SAMPLE_BUFFER_SIZE);
- ConditionVariable conditionVariable = new ConditionVariable();
- while (!mQuitRequested) {
- fetchSample(sample, conditionVariable);
- }
- cleanUp();
- }
-
- private void fetchSample(SampleHolder sample, ConditionVariable conditionVariable) {
- int index = mMediaExtractor.getSampleTrackIndex();
- if (index < 0) {
- Log.i(TAG, "EoS");
- mQuitRequested = true;
- mSampleBuffer.setEos();
- return;
- }
- sample.data.clear();
- sample.size = mMediaExtractor.readSampleData(sample.data, 0);
- if (sample.size < 0 || sample.size > SAMPLE_BUFFER_SIZE) {
- // Should not happen
- Log.e(TAG, "Invalid sample size: " + sample.size);
- mMediaExtractor.advance();
- return;
- }
- sample.data.position(sample.size);
- sample.timeUs = mMediaExtractor.getSampleTime();
- sample.flags = mMediaExtractor.getSampleFlags();
-
- mMediaExtractor.advance();
- try {
- queueSample(index, sample, conditionVariable);
- } catch (IOException e) {
- mQuitRequested = true;
- mSampleBuffer.setEos();
- }
- }
-
- public void quit() {
- mQuitRequested = true;
- }
- }
-
- public void queueSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
- throws IOException {
- long writeStartTimeNs = SystemClock.elapsedRealtimeNanos();
- mSampleBuffer.writeSample(index, sample, conditionVariable);
-
- // Check if the storage has enough bandwidth for trickplay. Otherwise we disable it
- // and notify the slowness through the playback cache listener.
- if (mSampleBuffer.isWriteSpeedSlow(sample.size,
- SystemClock.elapsedRealtimeNanos() - writeStartTimeNs)) {
- mSampleBuffer.handleWriteSpeedSlow();
- }
- }
-
- @Override
- public boolean prepare() throws IOException {
- synchronized (this) {
- mMediaExtractor.setDataSource(mDataSource);
-
- int trackCount = mMediaExtractor.getTrackCount();
- mTrackFormats = new MediaFormat[trackCount];
- for (int i = 0; i < trackCount; i++) {
- mTrackFormats[i] =
- MediaFormatUtil.createMediaFormat(mMediaExtractor.getTrackFormat(i));
- mMediaExtractor.selectTrack(i);
- }
- List<String> ids = new ArrayList<>();
- for (int i = 0; i < trackCount; i++) {
- ids.add(String.format(Locale.ENGLISH, "%s_%x", Long.toHexString(mId), i));
-
- }
- mSampleBuffer.init(ids, null);
-
- }
- mExtractorThread.start();
- return true;
- }
-
- @Override
- public synchronized MediaFormat[] getTrackFormats() {
- return mTrackFormats;
- }
-
- @Override
- public void getTrackMediaFormat(int track, MediaFormatHolder outMediaFormatHolder) {
- outMediaFormatHolder.format = mTrackFormats[track];
- outMediaFormatHolder.drmInitData = null;
- }
-
- @Override
- public void selectTrack(int index) {
- mSampleBuffer.selectTrack(index);
- }
-
- @Override
- public void deselectTrack(int index) {
- mSampleBuffer.deselectTrack(index);
- }
-
- @Override
- public long getBufferedPositionUs() {
- return mSampleBuffer.getBufferedPositionUs();
- }
-
- @Override
- public boolean continueBuffering(long positionUs) {
- return mSampleBuffer.continueBuffering(positionUs);
- }
-
- @Override
- public void seekTo(long positionUs) {
- mSampleBuffer.seekTo(positionUs);
- }
-
- @Override
- public int readSample(int track, SampleHolder sampleHolder) {
- return mSampleBuffer.readSample(track, sampleHolder);
- }
-
- @Override
- public void release() {
- synchronized (this) {
- mReleased = true;
- }
- if (mExtractorThread.isAlive()) {
- mExtractorThread.quit();
-
- // We don't join here to prevent hang --- MediaExtractor is released at the thread.
- } else {
- cleanUp();
- }
- }
-
- public void cleanUpImpl() {
- mSampleBuffer.release();
- }
-
- public synchronized void cleanUp() {
- if (!mReleased) {
- return;
- }
- cleanUpImpl();
- mMediaExtractor.release();
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/Recorder.java b/usbtuner/src/com/android/usbtuner/exoplayer/Recorder.java
deleted file mode 100644
index d7145f26..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/Recorder.java
+++ /dev/null
@@ -1,216 +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.usbtuner.exoplayer;
-
-import android.media.MediaDataSource;
-import android.media.MediaExtractor;
-import android.os.ConditionVariable;
-import android.os.SystemClock;
-import android.util.Log;
-
-import com.google.android.exoplayer.SampleHolder;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.RecordingSampleBuffer;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-import java.util.concurrent.atomic.AtomicLong;
-
-/**
- * Records live streams on the disk for DVR.
- */
-public class Recorder {
- private static final String TAG = "Recorder";
-
- // 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 AtomicLong ID_COUNTER = new AtomicLong(0);
-
- private final MediaDataSource mDataSource;
- private final MediaExtractor mMediaExtractor;
- private final ExtractorThread mExtractorThread;
- private int mTrackCount;
- private List<android.media.MediaFormat> mMediaFormats;
-
- private final CacheManager.SampleBuffer mSampleBuffer;
-
- private boolean mReleased = false;
- private boolean mResultNotified = false;
- private final long mId;
-
- private final RecordListener mRecordListener;
-
- /**
- * Listeners for events which happens during the recording.
- */
- public interface RecordListener {
-
- /**
- * Notifies recording completion.
- *
- * @param success {@code true} when the recording succeeded, {@code false} otherwise
- */
- void notifyRecordingFinished(boolean success);
- }
-
- /**
- * Create a recorder for a {@link android.media.MediaDataSource}.
- *
- * @param source {@link android.media.MediaDataSource} to record from
- * @param cacheManager the manager for recording samples to physical storage
- * @param cacheListener the {@link com.android.usbtuner.tvinput.PlaybackCacheListener}
- * to notify cache storage status change
- * @param recordListener RecordListener to notify events during the recording
- */
- public Recorder(MediaDataSource source, CacheManager cacheManager,
- PlaybackCacheListener cacheListener, RecordListener recordListener) {
- mDataSource = source;
- mMediaExtractor = new MediaExtractor();
- mExtractorThread = new ExtractorThread();
- mRecordListener = recordListener;
-
- mSampleBuffer = new RecordingSampleBuffer(cacheManager, cacheListener, false,
- RecordingSampleBuffer.CACHE_REASON_RECORDING);
- mId = ID_COUNTER.incrementAndGet();
- }
-
- private class ExtractorThread extends Thread {
- private volatile boolean mQuitRequested = false;
-
- public ExtractorThread() {
- super("ExtractorThread");
- }
-
- @Override
- public void run() {
- SampleHolder sample = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_NORMAL);
- sample.ensureSpaceForWrite(SAMPLE_BUFFER_SIZE);
- ConditionVariable conditionVariable = new ConditionVariable();
- while (!mQuitRequested) {
- fetchSample(sample, conditionVariable);
- }
- cleanUp();
- }
-
- private void fetchSample(SampleHolder sample, ConditionVariable conditionVariable) {
- int index = mMediaExtractor.getSampleTrackIndex();
- if (index < 0) {
- Log.i(TAG, "EoS");
- mQuitRequested = true;
- mSampleBuffer.setEos();
- return;
- }
- sample.data.clear();
- sample.size = mMediaExtractor.readSampleData(sample.data, 0);
- if (sample.size < 0 || sample.size > SAMPLE_BUFFER_SIZE) {
- // Should not happen
- Log.e(TAG, "Invalid sample size: " + sample.size);
- mMediaExtractor.advance();
- return;
- }
- sample.data.position(sample.size);
- sample.timeUs = mMediaExtractor.getSampleTime();
- sample.flags = mMediaExtractor.getSampleFlags();
-
- mMediaExtractor.advance();
- try {
- queueSample(index, sample, conditionVariable);
- } catch (IOException e) {
- mQuitRequested = true;
- mSampleBuffer.setEos();
- }
- }
-
- public void quit() {
- mQuitRequested = true;
- }
- }
-
- private void queueSample(int index, SampleHolder sample, ConditionVariable conditionVariable)
- throws IOException {
- long writeStartTimeNs = SystemClock.elapsedRealtimeNanos();
- mSampleBuffer.writeSample(index, sample, conditionVariable);
-
- // Check if the storage has enough bandwidth for recording. Otherwise we disable it
- // and notify the slowness.
- if (mSampleBuffer.isWriteSpeedSlow(sample.size,
- SystemClock.elapsedRealtimeNanos() - writeStartTimeNs)) {
- Log.w(TAG, "Disk is too slow for trickplay. Disable trickplay.");
- throw new IOException("Disk is too slow");
- }
- }
-
- /**
- * Prepares a recording.
- *
- * @return {@code true} when preparation finished successfully, {@code false} otherwise
- * @throws IOException
- */
- public boolean prepare() throws IOException {
- synchronized (this) {
- mMediaExtractor.setDataSource(mDataSource);
-
- mTrackCount = mMediaExtractor.getTrackCount();
- List<String> ids = new ArrayList<>();
- mMediaFormats = new ArrayList<>();
- for (int i = 0; i < mTrackCount; i++) {
- ids.add(String.format(Locale.ENGLISH, "%s_%x", Long.toHexString(mId), i));
- android.media.MediaFormat format = mMediaExtractor.getTrackFormat(i);
- mMediaExtractor.selectTrack(i);
- mMediaFormats.add(format);
- }
- mSampleBuffer.init(ids, mMediaFormats);
- }
- mExtractorThread.start();
- return true;
- }
-
- /**
- * Releases all the resources which were used in the recording.
- */
- public void release() {
- synchronized (this) {
- mReleased = true;
- }
- if (mExtractorThread.isAlive()) {
- mExtractorThread.quit();
- // We don't join here to prevent hang --- MediaExtractor is released at the thread.
- } else {
- cleanUp();
- }
- }
-
- private synchronized void cleanUp() {
- if (!mReleased) {
- if (!mResultNotified) {
- mRecordListener.notifyRecordingFinished(false);
- mResultNotified = true;
- }
- return;
- }
- mSampleBuffer.release();
- if (!mResultNotified) {
- mRecordListener.notifyRecordingFinished(true);
- mResultNotified = true;
- }
- mMediaExtractor.release();
- }
-
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3Decoder.java b/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3Decoder.java
deleted file mode 100644
index 4795378d..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3Decoder.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.usbtuner.exoplayer.ac3;
-
-import java.nio.ByteBuffer;
-
-/**
- * Decoder for {@link Ac3TrackRenderer}.
- */
-public abstract class Ac3Decoder {
- /**
- * Interface definition for AC3 decoder.
- */
- public interface DecodeListener {
- void decodeDone(ByteBuffer resultBuffer, long presentationTimeUs);
- }
-
- /**
- * Creates {@link AC3Decoder} instance that handles AC3 stream decoder.
- */
- public static Ac3Decoder createAc3Decoder(boolean isSoftware) {
- // TODO: Support framework/software-based AC3 decoder if available.
- return new Ac3PassthroughDecoder();
- }
-
- public abstract void startDecoder(DecodeListener listener);
-
- public abstract void decode(ByteBuffer inputBuffer, long presentationTimeUs);
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3PassthroughDecoder.java b/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3PassthroughDecoder.java
deleted file mode 100644
index 58497e35..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/ac3/Ac3PassthroughDecoder.java
+++ /dev/null
@@ -1,40 +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.usbtuner.exoplayer.ac3;
-
-import java.nio.ByteBuffer;
-
-/**
- * Decodes AC3 audio samples using AC3 Passthrough.
- */
-public final class Ac3PassthroughDecoder extends Ac3Decoder {
- private DecodeListener mListener;
-
- // Should not be created outside the package
- Ac3PassthroughDecoder() {
- }
-
- @Override
- public void startDecoder(DecodeListener listener) {
- mListener = listener;
- }
-
- @Override
- public void decode(ByteBuffer inputBuffer, long presentationTimeUs) {
- mListener.decodeDone(inputBuffer, presentationTimeUs);
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/RecordingSampleBuffer.java b/usbtuner/src/com/android/usbtuner/exoplayer/cache/RecordingSampleBuffer.java
deleted file mode 100644
index 324fba82..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/RecordingSampleBuffer.java
+++ /dev/null
@@ -1,419 +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.usbtuner.exoplayer.cache;
-
-import android.media.MediaCodec;
-import android.media.MediaFormat;
-import android.os.ConditionVariable;
-import android.support.annotation.IntDef;
-import android.util.Log;
-import android.util.Pair;
-
-import com.google.android.exoplayer.C;
-import com.google.android.exoplayer.SampleHolder;
-import com.google.android.exoplayer.SampleSource;
-import com.google.android.exoplayer.util.MimeTypes;
-import com.android.usbtuner.tvinput.PlaybackCacheListener;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-import junit.framework.Assert;
-
-/**
- * Handles I/O between {@link com.android.usbtuner.exoplayer.SampleExtractor} and
- * {@link CacheManager}.Reads & writes samples from/to {@link SampleCache} which is backed
- * by physical storage.
- */
-public class RecordingSampleBuffer implements CacheManager.SampleBuffer,
- CacheManager.EvictListener {
- private static final String TAG = "RecordingSampleBuffer";
- private static final boolean DEBUG = false;
-
- @IntDef({CACHE_REASON_LIVE_PLAYBACK, CACHE_REASON_RECORDED_PLAYBACK, CACHE_REASON_RECORDING})
- @Retention(RetentionPolicy.SOURCE)
- public @interface CacheReason {}
-
- /**
- * A cache reason for live-stream playback.
- */
- public static final int CACHE_REASON_LIVE_PLAYBACK = 0;
-
- /**
- * A cache reason for playback of a recorded program.
- */
- public static final int CACHE_REASON_RECORDED_PLAYBACK = 1;
-
- /**
- * A cache reason for recording a program.
- */
- public static final int CACHE_REASON_RECORDING = 2;
-
- private static final long CACHE_WRITE_TIMEOUT_MS = 10 * 1000; // 10 seconds
- private static final long CHUNK_DURATION_US = TimeUnit.MILLISECONDS.toMicros(500);
- private static final long LIVE_THRESHOLD_US = TimeUnit.SECONDS.toMicros(1);
-
- private final CacheManager mCacheManager;
- private final PlaybackCacheListener mCacheListener;
- private final int mCacheReason;
-
- private int mTrackCount;
- private List<String> mIds;
- private List<MediaFormat> mMediaFormats;
- private volatile long mCacheDurationUs = 0;
- private long[] mCacheEndPositionUs;
- // SampleCache to append the latest live sample.
- private SampleCache[] mSampleCaches;
- private CachedSampleQueue[] mPlayingSampleQueues;
- private final SamplePool mSamplePool = new SamplePool();
- private long mLastBufferedPositionUs = C.UNKNOWN_TIME_US;
- private long mCurrentPlaybackPositionUs = 0;
- private boolean mEos = false;
-
- private class CachedSampleQueue extends SampleQueue {
- private SampleCache mCache = null;
-
- public CachedSampleQueue(SamplePool samplePool) {
- super(samplePool);
- }
-
- public void setSource(SampleCache newCache) {
- for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) {
- cache.clear();
- cache.close();
- }
- mCache = newCache;
- for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) {
- cache.resetRead();
- }
- }
-
- public boolean maybeReadSample() {
- if (isDurationGreaterThan(CHUNK_DURATION_US)) {
- return false;
- }
- SampleHolder sample = mCache.maybeReadSample();
- if (sample == null) {
- if (!mCache.canReadMore() && mCache.getNext() != null) {
- mCache.clear();
- mCache.close();
- mCache = mCache.getNext();
- mCache.resetRead();
- return maybeReadSample();
- } else {
- if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK
- && !mCache.canReadMore() && mCache.getNext() == null) {
- // At the end of the recorded playback.
- setEos();
- }
- return false;
- }
- } else {
- queueSample(sample);
- return true;
- }
- }
-
- public int dequeueSample(SampleHolder sample) {
- maybeReadSample();
- return super.dequeueSample(sample);
- }
-
- @Override
- public void clear() {
- super.clear();
- for (SampleCache cache = mCache; cache != null; cache = cache.getNext()) {
- cache.clear();
- cache.close();
- }
- mCache = null;
- }
-
- public long getSourceStartPositionUs() {
- return mCache == null ? -1 : mCache.getStartPositionUs();
- }
- }
-
- /**
- * Creates {@link com.android.usbtuner.exoplayer.cache.CacheManager.SampleBuffer} with
- * cached I/O backed by physical storage (e.g. trickplay,recording,recorded-playback).
- *
- * @param cacheManager
- * @param cacheListener
- * @param enableTrickplay {@code true} when trickplay should be enabled
- * @param cacheReason the reason for caching samples {@link RecordingSampleBuffer.CacheReason}
- */
- public RecordingSampleBuffer(CacheManager cacheManager, PlaybackCacheListener cacheListener,
- boolean enableTrickplay, @CacheReason int cacheReason) {
- mCacheManager = cacheManager;
- mCacheListener = cacheListener;
- if (cacheListener != null) {
- cacheListener.onCacheStateChanged(enableTrickplay);
- }
- mCacheReason = cacheReason;
- }
-
- private String getTrackId(int index) {
- return mIds.get(index);
- }
-
- @Override
- public synchronized void init(List<String> ids, List<MediaFormat> mediaFormats)
- throws IOException {
- mTrackCount = ids.size();
- if (mTrackCount <= 0) {
- throw new IOException("No tracks to initialize");
- }
- mIds = ids;
- if (mCacheReason == CACHE_REASON_RECORDING && mediaFormats == null) {
- throw new IOException("MediaFormat is not provided.");
- }
- mMediaFormats = mediaFormats;
- mSampleCaches = new SampleCache[mTrackCount];
- mPlayingSampleQueues = new CachedSampleQueue[mTrackCount];
- mCacheEndPositionUs = new long[mTrackCount];
- for (int i = 0; i < mTrackCount; i++) {
- if (mCacheReason != CACHE_REASON_RECORDED_PLAYBACK) {
- mSampleCaches[i] = mCacheManager.createNewWriteFile(getTrackId(i), 0, mSamplePool);
- mPlayingSampleQueues[i] = null;
- mCacheEndPositionUs[i] = CHUNK_DURATION_US;
- } else {
- mCacheManager.loadTrackFormStorage(mIds.get(i), mSamplePool);
- }
- }
- }
-
- private boolean isLiveLocked(long positionUs) {
- Long livePositionUs = null;
- for (SampleCache cache : mSampleCaches) {
- if (livePositionUs == null || livePositionUs < cache.getEndPositionUs()) {
- livePositionUs = cache.getEndPositionUs();
- }
- }
- return (livePositionUs == null
- || Math.abs(livePositionUs - positionUs) < LIVE_THRESHOLD_US);
- }
-
- private void seekIndividualTrackLocked(int index, long positionUs, boolean isLive) {
- CachedSampleQueue queue = mPlayingSampleQueues[index];
- if (queue == null) {
- return;
- }
- queue.clear();
- if (isLive) {
- queue.setSource(mSampleCaches[index]);
- } else {
- queue.setSource(mCacheManager.getReadFile(getTrackId(index), positionUs));
- }
- queue.maybeReadSample();
- }
-
- @Override
- public synchronized void selectTrack(int index) {
- if (mPlayingSampleQueues[index] == null) {
- String trackId = getTrackId(index);
- mPlayingSampleQueues[index] = new CachedSampleQueue(mSamplePool);
- mCacheManager.registerEvictListener(trackId, this);
- seekIndividualTrackLocked(index, mCurrentPlaybackPositionUs,
- mCacheReason != CACHE_REASON_RECORDED_PLAYBACK && isLiveLocked(
- mCurrentPlaybackPositionUs));
- mPlayingSampleQueues[index].maybeReadSample();
- }
- }
-
- @Override
- public synchronized void deselectTrack(int index) {
- if (mPlayingSampleQueues[index] != null) {
- mPlayingSampleQueues[index].clear();
- mPlayingSampleQueues[index] = null;
- mCacheManager.unregisterEvictListener(getTrackId(index));
- }
- }
-
- @Override
- public void writeSample(int index, SampleHolder sample,
- ConditionVariable conditionVariable) throws IOException {
- synchronized (this) {
- SampleCache cache = mSampleCaches[index];
- if ((sample.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
- if (sample.timeUs > mCacheDurationUs) {
- mCacheDurationUs = sample.timeUs;
- }
- if (sample.timeUs >= mCacheEndPositionUs[index]) {
- try {
- SampleCache nextCache = mCacheManager.createNewWriteFile(
- getTrackId(index), mCacheEndPositionUs[index], mSamplePool);
- cache.finishWrite(nextCache);
- mSampleCaches[index] = cache = nextCache;
- mCacheEndPositionUs[index] =
- ((sample.timeUs / CHUNK_DURATION_US) + 1) * CHUNK_DURATION_US;
- } catch (IOException e) {
- cache.finishWrite(null);
- throw e;
- }
- }
- }
- cache.writeSample(sample, conditionVariable);
- }
-
- if (!conditionVariable.block(CACHE_WRITE_TIMEOUT_MS)) {
- Log.e(TAG, "Error: Serious delay on writing cache");
- conditionVariable.block();
- }
- }
-
- @Override
- public boolean isWriteSpeedSlow(int sampleSize, long writeDurationNs) {
- if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK) {
- return false;
- }
- mCacheManager.addWriteStat(sampleSize, writeDurationNs);
- return mCacheManager.isWriteSlow();
- }
-
- @Override
- public void handleWriteSpeedSlow() {
- Log.w(TAG, "Disk is too slow for trickplay. Disable trickplay.");
- mCacheManager.disable();
- mCacheListener.onDiskTooSlow();
- }
-
- @Override
- public synchronized void setEos() {
- mEos = true;
- }
-
- private synchronized boolean reachedEos() {
- return mEos;
- }
-
- @Override
- public synchronized int readSample(int track, SampleHolder sampleHolder) {
- CachedSampleQueue queue = mPlayingSampleQueues[track];
- Assert.assertNotNull(queue);
- queue.maybeReadSample();
- int result = queue.dequeueSample(sampleHolder);
- if (result != SampleSource.SAMPLE_READ && reachedEos()) {
- return SampleSource.END_OF_STREAM;
- }
- return result;
- }
-
- @Override
- public synchronized void seekTo(long positionUs) {
- boolean isLive = mCacheReason != CACHE_REASON_RECORDED_PLAYBACK && isLiveLocked(positionUs);
-
- // Seek video track first
- for (int i = 0; i < mPlayingSampleQueues.length; ++i) {
- CachedSampleQueue queue = mPlayingSampleQueues[i];
- if (queue == null) {
- continue;
- }
- seekIndividualTrackLocked(i, positionUs, isLive);
- if (DEBUG) {
- Log.d(TAG, "start time = " + queue.getSourceStartPositionUs());
- }
- }
- mLastBufferedPositionUs = positionUs;
- }
-
- @Override
- public synchronized long getBufferedPositionUs() {
- Long result = null;
- for (CachedSampleQueue queue : mPlayingSampleQueues) {
- if (queue == null) {
- continue;
- }
- Long bufferedPositionUs = queue.getEndPositionUs();
- if (bufferedPositionUs == null) {
- continue;
- }
- if (result == null || result > bufferedPositionUs) {
- result = bufferedPositionUs;
- }
- }
- if (result == null) {
- return mLastBufferedPositionUs;
- } else {
- return (mLastBufferedPositionUs = result);
- }
- }
-
- @Override
- public synchronized boolean continueBuffering(long positionUs) {
- boolean hasSamples = true;
- mCurrentPlaybackPositionUs = positionUs;
- for (CachedSampleQueue queue : mPlayingSampleQueues) {
- if (queue == null) {
- continue;
- }
- queue.maybeReadSample();
- if (queue.isEmpty()) {
- hasSamples = false;
- }
- }
- return hasSamples;
- }
-
- @Override
- public synchronized void release() {
- if (mSampleCaches == null) {
- return;
- }
- if (mCacheReason == CACHE_REASON_RECORDED_PLAYBACK) {
- mCacheManager.close();
- }
- for (int i = 0; i < mTrackCount; ++i) {
- if (mCacheReason != CACHE_REASON_RECORDED_PLAYBACK) {
- mSampleCaches[i].finishWrite(null);
- }
- mCacheManager.unregisterEvictListener(getTrackId(i));
- }
- if (mCacheReason == CACHE_REASON_RECORDING && mTrackCount > 0) {
- // Saves meta information for recording.
- Pair<String, android.media.MediaFormat> audio = null, video = null;
- for (int i = 0; i < mTrackCount; ++i) {
- MediaFormat mediaFormat = mMediaFormats.get(i);
- String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
- mediaFormat.setLong(android.media.MediaFormat.KEY_DURATION, mCacheDurationUs);
- if (MimeTypes.isAudio(mime)) {
- audio = new Pair<>(getTrackId(i), mediaFormat);
- }
- else if (MimeTypes.isVideo(mime)) {
- video = new Pair<>(getTrackId(i), mediaFormat);
- }
- }
- mCacheManager.writeMetaFiles(audio, video);
- }
-
- for (int i = 0; i < mTrackCount; ++i) {
- mCacheManager.clearTrack(getTrackId(i));
- }
- }
-
- // CacheEvictListener
- @Override
- public void onCacheEvicted(String id, long createdTimeMs) {
- if (mCacheListener != null) {
- mCacheListener.onCacheStartTimeChanged(
- createdTimeMs + TimeUnit.MICROSECONDS.toMillis(CHUNK_DURATION_US));
- }
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleCache.java b/usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleCache.java
deleted file mode 100644
index 52b7daa9..00000000
--- a/usbtuner/src/com/android/usbtuner/exoplayer/cache/SampleCache.java
+++ /dev/null
@@ -1,401 +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.usbtuner.exoplayer.cache;
-
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-
-import com.google.android.exoplayer.SampleHolder;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-/**
- * {@link SampleCache} stores samples into file and make them available for read.
- * This class is thread-safe.
- */
-public class SampleCache {
- private static final String TAG = "SampleCache";
- private static final boolean DEBUG = false;
-
- private final long mCreatedTimeMs;
- private final long mStartPositionUs;
- private long mEndPositionUs = 0;
- private SampleCache mNextCache = null;
- private final CacheState mCacheState = new CacheState();
- private final Handler mIoHandler;
-
- public static class SampleCacheFactory {
- public SampleCache createSampleCache(SamplePool samplePool, File file,
- long startPositionUs, CacheManager.CacheListener cacheListener,
- Looper looper) throws IOException {
- return new SampleCache(samplePool, file, startPositionUs, System.currentTimeMillis(),
- cacheListener, looper);
- }
-
- public SampleCache createSampleCacheFromFile(SamplePool samplePool, File cacheDir,
- String filename, long startPositionUs, CacheManager.CacheListener cacheListener,
- Looper looper, SampleCache prev) throws IOException {
- File file = new File(cacheDir, filename);
- SampleCache cache =
- new SampleCache(samplePool, file, startPositionUs, cacheListener, looper);
- if (prev != null) {
- prev.setNext(cache);
- }
- return cache;
- }
- }
-
- private static class CacheState {
- private static final int NUM_SAMPLES = 3;
-
- private volatile boolean mCanReadMore = true;
- private final ConcurrentLinkedQueue<SampleHolder> mSamples = new ConcurrentLinkedQueue<>();
- private volatile long mSize = 0;
-
- public SampleHolder pollSample() {
- return mSamples.poll();
- }
-
- public void offerSample(SampleHolder sample) {
- mSamples.offer(sample);
- }
-
- public void setCanReadMore(boolean canReadMore) {
- mCanReadMore = canReadMore;
- }
-
- public boolean canReadMore() {
- return mCanReadMore || !mSamples.isEmpty();
- }
-
- public boolean hasEnoughSamples() {
- return mSamples.size() > NUM_SAMPLES;
- }
-
- public void setSize(long size) {
- mSize = size;
- }
-
- public long getSize() {
- return mSize;
- }
- }
-
- private class IoHandlerCallback implements Handler.Callback {
- public static final int MSG_WRITE = 1;
- public static final int MSG_READ = 2;
- public static final int MSG_CLOSE = 3;
- public static final int MSG_DELETE = 4;
- public static final int MSG_FINISH_WRITE = 5;
- public static final int MSG_RESET_READ = 6;
- public static final int MSG_CLEAR = 7;
- public static final int MSG_OPEN = 8;
-
- private static final int DELAY_MS = 10;
- private static final int SAMPLE_HEADER_LENGTH = 16;
-
- private final File mFile;
- private final CacheManager.CacheListener mCacheListener;
- private final SamplePool mSamplePool;
- private final CacheState mCacheState;
- private RandomAccessFile mRaf = null;
- private long mWriteOffset = 0;
- private long mReadOffset = 0;
- private boolean mWriteFinished = false;
- private boolean mDeleteAtEof = false;
- private boolean mDeleted = false;
-
- public IoHandlerCallback(File file, CacheManager.CacheListener cacheListener,
- SamplePool samplePool, CacheState cacheState, boolean fromFile) throws IOException {
- mFile = file;
- mCacheListener = cacheListener;
- mSamplePool = samplePool;
- mCacheState = cacheState;
- if (fromFile) {
- loadFromFile();
- }
- }
-
- private void loadFromFile() throws IOException {
- // "r" is enough
- try (RandomAccessFile raf = new RandomAccessFile(mFile, "r")) {
- mWriteFinished = true;
- mWriteOffset = raf.length();
- mCacheState.setSize(mWriteOffset);
- mCacheListener.onWrite(SampleCache.this);
- }
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- if (mDeleted) {
- if (DEBUG) {
- Log.d(TAG, "Ignore access to a deleted cache.");
- }
- return true;
- }
- try {
- switch (msg.what) {
- case MSG_WRITE:
- handleWrite(msg);
- return true;
- case MSG_READ:
- handleRead(msg);
- return true;
- case MSG_CLOSE:
- handleClose();
- return true;
- case MSG_DELETE:
- handleDelete();
- return true;
- case MSG_FINISH_WRITE:
- handleFinishWrite();
- return true;
- case MSG_RESET_READ:
- handleResetRead();
- return true;
- case MSG_CLEAR:
- handleClear(msg);
- return true;
- case MSG_OPEN:
- handleOpen();
- return true;
- default:
- return false;
- }
- } catch (IOException e) {
- Log.e(TAG, "Error while handling file operation", e);
- return true;
- }
- }
-
- private void handleWrite(Message msg) throws IOException {
- SampleHolder sample = (SampleHolder) ((Object[])msg.obj)[0];
- ConditionVariable conditionVariable = (ConditionVariable) ((Object[])msg.obj)[1];
- try {
- mRaf.seek(mWriteOffset);
- mRaf.writeInt(sample.size);
- mRaf.writeInt(sample.flags);
- mRaf.writeLong(sample.timeUs);
- sample.data.position(0).limit(sample.size);
- mRaf.getChannel().position(mWriteOffset + SAMPLE_HEADER_LENGTH).write(sample.data);
- mWriteOffset += sample.size + SAMPLE_HEADER_LENGTH;
- mCacheState.setSize(mWriteOffset);
- } finally {
- conditionVariable.open();
- }
- }
-
- private void handleRead(Message msg) throws IOException {
- msg.getTarget().removeMessages(MSG_READ);
- if (mCacheState.hasEnoughSamples()) {
- // If cache has enough samples, try again few moments later hoping that mCacheState
- // needs a sample by then.
- msg.getTarget().sendEmptyMessageDelayed(MSG_READ, DELAY_MS);
- } else if (mReadOffset >= mWriteOffset) {
- if (mWriteFinished) {
- if (mRaf != null) {
- mRaf.close();
- mRaf = null;
- }
- mCacheState.setCanReadMore(false);
- maybeDelete();
- } else {
- // Read reached write but write is not finished yet --- wait a few moments to
- // see if another sample is written.
- msg.getTarget().sendEmptyMessageDelayed(MSG_READ, DELAY_MS);
- }
- } else {
- if (mRaf == null) {
- try {
- mRaf = new RandomAccessFile(mFile, "r");
- } catch (FileNotFoundException e) {
- // Cache can be deleted by installd service.
- Log.e(TAG, "Failed opening a random access file.", e);
- mDeleted = true;
- mCacheListener.onDelete(SampleCache.this);
- return;
- }
- }
- mRaf.seek(mReadOffset);
- int size = mRaf.readInt();
- SampleHolder sample = mSamplePool.acquireSample(size);
- sample.size = size;
- sample.flags = mRaf.readInt();
- sample.timeUs = mRaf.readLong();
- sample.clearData();
- sample.data.put(mRaf.getChannel().map(FileChannel.MapMode.READ_ONLY,
- mReadOffset + SAMPLE_HEADER_LENGTH, sample.size));
- mReadOffset += sample.size + SAMPLE_HEADER_LENGTH;
- mCacheState.offerSample(sample);
- msg.getTarget().sendEmptyMessage(MSG_READ);
- }
- }
-
- private void handleClose() throws IOException {
- if (mWriteFinished) {
- if (mRaf != null) {
- mRaf.close();
- mRaf = null;
- }
- mReadOffset = mWriteOffset;
- mCacheState.setCanReadMore(false);
- maybeDelete();
- }
- }
-
- private void handleDelete() throws IOException {
- mDeleteAtEof = true;
- maybeDelete();
- }
-
- private void maybeDelete() throws IOException {
- if (!mDeleteAtEof || mCacheState.canReadMore()) {
- return;
- }
- if (mRaf != null) {
- mRaf.close();
- mRaf = null;
- }
- mFile.delete();
- mDeleted = true;
- mCacheListener.onDelete(SampleCache.this);
- }
-
- private void handleFinishWrite() throws IOException {
- mCacheListener.onWrite(SampleCache.this);
- mWriteFinished = true;
- mRaf.close();
- mRaf = null;
- }
-
- private void handleResetRead() {
- mReadOffset = 0;
- }
-
- private void handleClear(Message msg) {
- msg.getTarget().removeMessages(MSG_READ);
- SampleHolder sample;
- while ((sample = mCacheState.pollSample()) != null) {
- mSamplePool.releaseSample(sample);
- }
- }
-
- private void handleOpen() {
- try {
- mRaf = new RandomAccessFile(mFile, "rw");
- } catch (FileNotFoundException e) {
- Log.e(TAG, "Failed opening a random access file.", e);
- }
- }
- }
-
- protected SampleCache(SamplePool samplePool, File file, long startPositionUs,
- long createdTimeMs, CacheManager.CacheListener cacheListener, Looper looper)
- throws IOException {
- mEndPositionUs = mStartPositionUs = startPositionUs;
- mCreatedTimeMs = createdTimeMs;
- mIoHandler = new Handler(looper,
- new IoHandlerCallback(file, cacheListener, samplePool, mCacheState, false));
- mIoHandler.sendEmptyMessage(IoHandlerCallback.MSG_OPEN);
- }
-
- // Constructor of SampleCache which is backed by the given existing file.
- protected SampleCache(SamplePool samplePool, File file, long startPositionUs,
- CacheManager.CacheListener cacheListener, Looper looper) throws IOException {
- mCreatedTimeMs = mEndPositionUs = mStartPositionUs = startPositionUs;
- IoHandlerCallback handlerCallback =
- new IoHandlerCallback(file, cacheListener, samplePool, mCacheState, true);
- mIoHandler = new Handler(looper, handlerCallback);
- }
-
- public void resetRead() {
- mCacheState.setCanReadMore(true);
- mIoHandler.sendMessageAtFrontOfQueue(
- mIoHandler.obtainMessage(IoHandlerCallback.MSG_RESET_READ));
- }
-
- private void setNext(SampleCache next) {
- mNextCache = next;
- }
-
- public void finishWrite(SampleCache next) {
- setNext(next);
- mIoHandler.sendEmptyMessage(IoHandlerCallback.MSG_FINISH_WRITE);
- }
-
- public long getStartPositionUs() {
- return mStartPositionUs;
- }
-
- public SampleCache getNext() {
- return mNextCache;
- }
-
- public void writeSample(SampleHolder sample, ConditionVariable conditionVariable) {
- if (mNextCache != null) {
- throw new IllegalStateException(
- "Called writeSample() even though write is already finished");
- }
- mEndPositionUs = sample.timeUs;
- conditionVariable.close();
- mIoHandler.obtainMessage(IoHandlerCallback.MSG_WRITE,
- new Object[] { sample, conditionVariable }).sendToTarget();
- }
-
- public long getEndPositionUs() {
- return mEndPositionUs;
- }
-
- public long getCreatedTimeMs() {
- return mCreatedTimeMs;
- }
-
- public boolean canReadMore() {
- return mCacheState.canReadMore();
- }
-
- public SampleHolder maybeReadSample() {
- SampleHolder sample = mCacheState.pollSample();
- mIoHandler.sendEmptyMessage(IoHandlerCallback.MSG_READ);
- return sample;
- }
-
- public void close() {
- mIoHandler.sendEmptyMessage(IoHandlerCallback.MSG_CLOSE);
- }
-
- public void delete() {
- mIoHandler.sendEmptyMessage(IoHandlerCallback.MSG_DELETE);
- }
-
- public void clear() {
- mIoHandler.sendMessageAtFrontOfQueue(mIoHandler.obtainMessage(IoHandlerCallback.MSG_CLEAR));
- }
-
- public long getSize() {
- return mCacheState.getSize();
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/BaseTunerTvInputService.java b/usbtuner/src/com/android/usbtuner/tvinput/BaseTunerTvInputService.java
deleted file mode 100644
index a24b6146..00000000
--- a/usbtuner/src/com/android/usbtuner/tvinput/BaseTunerTvInputService.java
+++ /dev/null
@@ -1,101 +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.usbtuner.tvinput;
-
-import android.media.tv.TvInputService;
-import android.util.Log;
-import com.google.android.exoplayer.audio.AudioCapabilities;
-import com.google.android.exoplayer.audio.AudioCapabilitiesReceiver;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-
-import java.util.Collections;
-import java.util.Set;
-import java.util.WeakHashMap;
-
-/**
- * {@link BaseTunerTvInputService} serves TV channels coming from a tuner device.
- */
-public abstract class BaseTunerTvInputService extends TvInputService
- implements AudioCapabilitiesReceiver.Listener {
- private static final String TAG = "BaseTunerTvInputService";
- private static final boolean DEBUG = false;
-
- // WeakContainer for {@link TvInputSessionImpl}
- private final Set<TunerSession> mTunerSessions = Collections.newSetFromMap(
- new WeakHashMap<TunerSession, Boolean>());
- private ChannelDataManager mChannelDataManager;
- private AudioCapabilitiesReceiver mAudioCapabilitiesReceiver;
- private AudioCapabilities mAudioCapabilities;
- private CacheManager mCacheManager;
-
- @Override
- public void onCreate() {
- super.onCreate();
- if (DEBUG) Log.d(TAG, "onCreate");
- mChannelDataManager = new ChannelDataManager(getApplicationContext());
- mAudioCapabilitiesReceiver = new AudioCapabilitiesReceiver(getApplicationContext(), this);
- mAudioCapabilitiesReceiver.register();
- mCacheManager = createCacheManager();
- if (mCacheManager == null) {
- Log.i(TAG, "Trickplay is disabled");
- } else {
- Log.i(TAG, "Trickplay is enabled");
- }
- }
-
- /**
- * Creates {@CacheManager}. It returns null, if storage in not enough.
- */
- protected abstract CacheManager createCacheManager();
-
- @Override
- public void onDestroy() {
- if (DEBUG) Log.d(TAG, "onDestroy");
- super.onDestroy();
- mChannelDataManager.release();
- mAudioCapabilitiesReceiver.unregister();
- if (mCacheManager != null) {
- mCacheManager.close();
- }
- }
-
- @Override
- public RecordingSession onCreateRecordingSession(String inputId) {
- return new TunerRecordingSession(this, inputId, mChannelDataManager);
- }
-
- @Override
- public Session onCreateSession(String inputId) {
- if (DEBUG) Log.d(TAG, "onCreateSession");
- final TunerSession session = new TunerSession(
- this, mChannelDataManager, mCacheManager);
- mTunerSessions.add(session);
- session.setAudioCapabilities(mAudioCapabilities);
- session.setOverlayViewEnabled(true);
- return session;
- }
-
- @Override
- public void onAudioCapabilitiesChanged(AudioCapabilities audioCapabilities) {
- mAudioCapabilities = audioCapabilities;
- for (TunerSession session : mTunerSessions) {
- if (!session.isReleased()) {
- session.setAudioCapabilities(audioCapabilities);
- }
- }
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/InternalTunerTvInputService.java b/usbtuner/src/com/android/usbtuner/tvinput/InternalTunerTvInputService.java
deleted file mode 100644
index b4e97833..00000000
--- a/usbtuner/src/com/android/usbtuner/tvinput/InternalTunerTvInputService.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.usbtuner.tvinput;
-
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.media.tv.TvInputHardwareInfo;
-import android.media.tv.TvInputInfo;
-import android.os.Environment;
-import android.util.Log;
-
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.TrickplayStorageManager;
-import com.android.usbtuner.util.SystemPropertiesProxy;
-import com.android.usbtuner.util.TisConfiguration;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * {@link InternalTunerTvInputService} serves TV channels coming from a internal tuner device.
- */
-public class InternalTunerTvInputService extends BaseTunerTvInputService {
- private static final String TAG = "InternalTunerTvInputService";
- private static final boolean DEBUG = false;
-
-
- private static final String MAX_CACHE_SIZE_KEY = "usbtuner.cachesize_mbytes";
- private static final int MAX_CACHE_SIZE_DEF = 2 * 1024; // 2GB
- private static final int MIN_CACHE_SIZE_DEF = 256; // 256MB
-
- private ResolveInfo mResolveInfo;
- private String mTvInputId;
-
- @Override
- public void onCreate() {
- super.onCreate();
- mResolveInfo = getPackageManager().resolveService(
- new Intent(SERVICE_INTERFACE).setClass(this, getClass()),
- PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
- }
-
- @Override
- protected CacheManager createCacheManager() {
- int maxCacheSizeMb = SystemPropertiesProxy.getInt(MAX_CACHE_SIZE_KEY, MAX_CACHE_SIZE_DEF);
- if (maxCacheSizeMb >= MIN_CACHE_SIZE_DEF) {
- boolean useExternalStorage = Environment.MEDIA_MOUNTED.equals(
- Environment.getExternalStorageState()) &&
- Environment.isExternalStorageRemovable();
- if (DEBUG) Log.d(TAG, "useExternalStorage for trickplay: " + useExternalStorage);
- boolean allowToUseInternalStorage = true;
- if (useExternalStorage || allowToUseInternalStorage) {
- File baseDir = useExternalStorage ? getExternalCacheDir() : getCacheDir();
- return new CacheManager(
- new TrickplayStorageManager(getApplicationContext(), baseDir,
- 1024L * 1024 * maxCacheSizeMb));
- }
- }
- return null;
- }
-
- @Override
- public TvInputInfo onHardwareAdded(TvInputHardwareInfo hardwareInfo) {
- if (DEBUG) Log.d(TAG, "onHardwareAdded: " + hardwareInfo.toString());
- if (mTvInputId != null) {
- return null;
- }
- TvInputInfo info = null;
- if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_TUNER &&
- TisConfiguration.getTunerHwDeviceId(this) == hardwareInfo.getDeviceId()) {
- try {
- info = TvInputInfo.createTvInputInfo(this, mResolveInfo, hardwareInfo,
- "Google Tuner", null);
- mTvInputId = info.getId();
- } catch (XmlPullParserException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- return info;
- }
-
- @Override
- public String onHardwareRemoved(TvInputHardwareInfo hardwareInfo) {
- if (DEBUG) Log.d(TAG, "onHardwareRemoved: " + hardwareInfo.toString());
- return null;
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSessionWorker.java b/usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSessionWorker.java
deleted file mode 100644
index 3d121a85..00000000
--- a/usbtuner/src/com/android/usbtuner/tvinput/TunerRecordingSessionWorker.java
+++ /dev/null
@@ -1,549 +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.usbtuner.tvinput;
-
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-import android.database.Cursor;
-import android.media.MediaDataSource;
-import android.media.tv.TvContract;
-import android.media.tv.TvInputManager;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.support.annotation.IntDef;
-import android.support.annotation.Nullable;
-import android.util.Log;
-import android.widget.Toast;
-
-import com.google.android.exoplayer.util.Assertions;
-import com.android.tv.common.recording.RecordedProgram;
-import com.android.tv.common.recording.RecordingCapability;
-import com.android.usbtuner.DvbDeviceAccessor;
-import com.android.usbtuner.TunerHal;
-import com.android.usbtuner.UsbTunerDataSource;
-import com.android.usbtuner.data.PsipData;
-import com.android.usbtuner.data.TunerChannel;
-import com.android.usbtuner.exoplayer.Recorder;
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.DvrStorageManager;
-
-import java.io.File;
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.List;
-import java.util.Locale;
-import java.util.Random;
-
-/**
- * Implements a DVR feature.
- */
-public class TunerRecordingSessionWorker implements PlaybackCacheListener,
- EventDetector.EventListener, Recorder.RecordListener,
- Handler.Callback {
- private static String TAG = "TunerRecordingSessionWorker";
- private static final boolean DEBUG = false;
-
- private static final String SORT_BY_TIME = TvContract.Programs.COLUMN_START_TIME_UTC_MILLIS
- + ", " + TvContract.Programs.COLUMN_CHANNEL_ID + ", "
- + TvContract.Programs.COLUMN_END_TIME_UTC_MILLIS;
- private static final int MSG_CONNECT = 1;
- private static final int MSG_DISCONNECT = 2;
- private static final int MSG_START_RECORDING = 3;
- private static final int MSG_STOP_RECORDING = 4;
- private static final int MSG_RECORDING_RESULT = 5;
- private static final int MSG_DELETE_RECORDING = 6;
- private static final int MSG_RELEASE = 7;
- private RecordingCapability mCapabilities;
-
- public RecordingCapability getCapabilities() {
- return mCapabilities;
- }
-
- @IntDef({STATE_IDLE, STATE_CONNECTED, STATE_RECORDING})
- @Retention(RetentionPolicy.SOURCE)
- public @interface DvrSessionState {}
- private static final int STATE_IDLE = 1;
- private static final int STATE_CONNECTED = 2;
- private static final int STATE_RECORDING = 3;
-
- private static final long CHANNEL_ID_NONE = -1;
-
- private final Context mContext;
- private final ChannelDataManager mChannelDataManager;
- private final Handler mHandler;
- private final Random mRandom = new Random();
-
- private TunerHal mTunerHal;
- private UsbTunerDataSource mTunerSource;
- private TunerChannel mChannel;
- private File mStorageDir;
- private long mRecordStartTime;
- private long mRecordEndTime;
- private CacheManager mCacheManager;
- private Recorder mRecorder;
- private final TunerRecordingSession mSession;
- @DvrSessionState private int mSessionState = STATE_IDLE;
- private final String mInputId;
-
- public TunerRecordingSessionWorker(Context context, String inputId,
- ChannelDataManager dataManager, TunerRecordingSession session) {
- mRandom.setSeed(System.nanoTime());
- mContext = context;
- HandlerThread handlerThread = new HandlerThread(TAG);
- handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper(), this);
- mChannelDataManager = dataManager;
- mChannelDataManager.checkDataVersion(context);
- mCapabilities = new DvbDeviceAccessor(context).getRecordingCapability(inputId);
- mInputId = inputId;
- if (DEBUG) Log.d(TAG, mCapabilities.toString());
- mSession = session;
- }
-
- // PlaybackCacheListener
- @Override
- public void onCacheStartTimeChanged(long startTimeMs) {
- }
-
- @Override
- public void onCacheStateChanged(boolean available) {
- }
-
- @Override
- public void onDiskTooSlow() {
- }
-
- // EventDetector.EventListener
- @Override
- public void onChannelDetected(TunerChannel channel, boolean channelArrivedAtFirstTime) {
- if (mChannel == null || mChannel.compareTo(channel) != 0) {
- return;
- }
- mChannelDataManager.notifyChannelDetected(channel, channelArrivedAtFirstTime);
- }
-
- @Override
- public void onEventDetected(TunerChannel channel, List<PsipData.EitItem> items) {
- if (mChannel == null || mChannel.compareTo(channel) != 0) {
- return;
- }
- mChannelDataManager.notifyEventDetected(channel, items);
- }
-
- public void connect(Uri channelUri) {
- mHandler.removeCallbacksAndMessages(null);
- mHandler.obtainMessage(MSG_CONNECT, channelUri).sendToTarget();
- }
-
- public void disconnect() {
- mHandler.sendEmptyMessage(MSG_DISCONNECT);
- }
-
- public void startRecording() {
- mHandler.sendEmptyMessage(MSG_START_RECORDING);
- }
-
- public void stopRecording() {
- mHandler.sendEmptyMessage(MSG_STOP_RECORDING);
- }
-
- public void notifyRecordingFinished(boolean success) {
- mHandler.obtainMessage(MSG_RECORDING_RESULT, success).sendToTarget();
- }
-
- public void deleteRecording(Uri mediaUri) {
- mHandler.obtainMessage(MSG_DELETE_RECORDING, mediaUri).sendToTarget();
- }
-
- public void release() {
- mHandler.removeCallbacksAndMessages(null);
- mHandler.sendEmptyMessage(MSG_RELEASE);
- }
-
- @Override
- public boolean handleMessage(Message msg) {
- // TODO: Add RecordStopped status
- switch (msg.what) {
- case MSG_CONNECT: {
- Uri channelUri = (Uri) msg.obj;
- if (onConnect(channelUri)) {
- mSession.onTuned(channelUri);
- } else {
- Log.w(TAG, "Recording session connect failed");
- mSession.onConnectFailed();
- }
- return true;
- }
- case MSG_START_RECORDING: {
- if(onStartRecording()) {
- Toast.makeText(mContext, "USB TV tuner: Recording started",
- Toast.LENGTH_SHORT).show();
- }
- else {
- mSession.onRecordUnexpectedlyStopped(TvInputManager.RECORDING_ERROR_UNKNOWN);
- }
- return true;
- }
- case MSG_DISCONNECT: {
- return true;
- }
- case MSG_STOP_RECORDING: {
- onStopRecording();
- new Handler(Looper.getMainLooper()).post(new Runnable() {
- @Override
- public void run() {
- Toast.makeText(mContext, "USB TV tuner: Recording stopped",
- Toast.LENGTH_SHORT).show();
- }
- });
- return true;
- }
- case MSG_RECORDING_RESULT: {
- onRecordingResult((Boolean) msg.obj);
- return true;
- }
- case MSG_DELETE_RECORDING: {
- Uri toDelete = (Uri) msg.obj;
- onDeleteRecording(toDelete);
- return true;
- }
- case MSG_RELEASE: {
- onRelease();
- return true;
- }
- }
- return false;
- }
-
- @Nullable
- private TunerChannel getChannel(Uri channelUri) {
- if (channelUri == null) {
- return null;
- }
- long channelId;
- try {
- channelId = ContentUris.parseId(channelUri);
- } catch (UnsupportedOperationException | NumberFormatException e) {
- channelId = CHANNEL_ID_NONE;
- }
- return (channelId == CHANNEL_ID_NONE) ? null : mChannelDataManager.getChannel(channelId);
- }
-
- private String getStorageKey() {
- long prefix = System.currentTimeMillis();
- int suffix = mRandom.nextInt();
- return String.format(Locale.ENGLISH, "%016x_%016x", prefix, suffix);
- }
-
- private File getMediaDir(String storageKey) {
- return new File(mContext.getCacheDir().getAbsolutePath() + "/recording/" + storageKey);
- }
-
- private File getMediaDir(Uri mediaUri) {
- String mediaPath = mediaUri.getPath();
- if (mediaPath == null || mediaPath.length() == 0) {
- return null;
- }
- return new File(mContext.getCacheDir().getAbsolutePath() + "/recording" +
- mediaUri.getPath());
- }
-
- private void reset() {
- if (mRecorder != null) {
- mRecorder.release();
- mRecorder = null;
- }
- if (mCacheManager != null) {
- mCacheManager.close();
- mCacheManager = null;
- }
- if (mTunerSource != null) {
- mTunerSource.stopStream();
- mTunerSource = null;
- }
- if (mTunerHal != null) {
- try {
- mTunerHal.close();
- } catch (Exception ex) {
- Log.e(TAG, "Error on closing tuner HAL.", ex);
- }
- mTunerHal = null;
- }
- mSessionState = STATE_IDLE;
- }
-
- private void resetRecorder() {
- Assertions.checkArgument(mSessionState != STATE_IDLE);
- if (mRecorder != null) {
- mRecorder.release();
- mRecorder = null;
- }
- if (mCacheManager != null) {
- mCacheManager.close();
- mCacheManager = null;
- }
- if (mTunerSource != null) {
- mTunerSource.stopStream();
- mTunerSource = null;
- }
- mSessionState = STATE_CONNECTED;
- }
-
- private boolean onConnect(Uri channelUri) {
- if (mSessionState == STATE_RECORDING) {
- return false;
- }
- mChannel = getChannel(channelUri);
- if (mChannel == null) {
- Log.w(TAG, "Failed to start recording. Couldn't find the channel for " + mChannel);
- return false;
- }
- if (mSessionState == STATE_CONNECTED) {
- return true;
- }
- mTunerHal = TunerHal.createInstance(mContext);
- if (mTunerHal == null) {
- Log.w(TAG, "Failed to start recording. Couldn't open a DVB device");
- reset();
- return false;
- }
- mSessionState = STATE_CONNECTED;
- return true;
- }
-
- private boolean onStartRecording() {
- if (mSessionState != STATE_CONNECTED) {
- return false;
- }
- mStorageDir = getMediaDir(getStorageKey());
- mTunerSource = new UsbTunerDataSource(mTunerHal, this);
- if (!mTunerSource.tuneToChannel(mChannel)) {
- Log.w(TAG, "Failed to start recording. Couldn't tune to the channel for " +
- mChannel.toString());
- resetRecorder();
- return false;
- }
- mCacheManager = new CacheManager(new DvrStorageManager(mStorageDir, true));
- mTunerSource.startStream();
- mRecordStartTime = System.currentTimeMillis();
- mRecorder = new Recorder((MediaDataSource) mTunerSource,
- mCacheManager, this, this);
- try {
- mRecorder.prepare();
- } catch (IOException e) {
- Log.w(TAG, "Failed to start recording. Couldn't prepare a extractor");
- resetRecorder();
- return false;
- }
- mSessionState = STATE_RECORDING;
- return true;
- }
-
- private void onStopRecording() {
- if (mSessionState != STATE_RECORDING) {
- return;
- }
- // Do not change session status.
- if (mRecorder != null) {
- mRecorder.release();
- mRecordEndTime = System.currentTimeMillis();
- mRecorder = null;
- }
- }
-
- private static class Program {
- private long mChannelId;
- private String mTitle;
- private String mEpisodeTitle;
- private int mSeasonNumber;
- private int mEpisodeNumber;
- private String mDescription;
- private String mPosterArtUri;
- private String mThumbnailUri;
- private String mCanonicalGenres;
- private String mContentRatings;
- private long mStartTimeUtcMillis;
- private long mEndTimeUtcMillis;
- private long mVideoWidth;
- private long mVideoHeight;
-
- private static final String[] PROJECTION = {
- TvContract.Programs.COLUMN_CHANNEL_ID,
- TvContract.Programs.COLUMN_TITLE,
- TvContract.Programs.COLUMN_EPISODE_TITLE,
- TvContract.Programs.COLUMN_SEASON_NUMBER,
- TvContract.Programs.COLUMN_EPISODE_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
- };
-
- public Program(Cursor cursor) {
- int index = 0;
- mChannelId = cursor.getLong(index++);
- mTitle = cursor.getString(index++);
- mEpisodeTitle = cursor.getString(index++);
- mSeasonNumber = cursor.getInt(index++);
- mEpisodeNumber = cursor.getInt(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.getLong(index++);
- mVideoHeight = cursor.getLong(index++);
- }
-
- public Program(long channelId) {
- mChannelId = channelId;
- mTitle = "Unknown";
- mEpisodeTitle = "";
- mSeasonNumber = 0;
- mEpisodeNumber = 0;
- mDescription = "Unknown";
- mPosterArtUri = null;
- mThumbnailUri = null;
- mCanonicalGenres = null;
- mContentRatings = null;
- mStartTimeUtcMillis = 0;
- mEndTimeUtcMillis = 0;
- mVideoWidth = 0;
- mVideoHeight = 0;
- }
-
- 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();
- values.put(PROJECTION[0], mChannelId);
- values.put(PROJECTION[1], mTitle);
- values.put(PROJECTION[2], mEpisodeTitle);
- values.put(PROJECTION[3], mSeasonNumber);
- values.put(PROJECTION[4], mEpisodeNumber);
- values.put(PROJECTION[5], mDescription);
- values.put(PROJECTION[6], mPosterArtUri);
- values.put(PROJECTION[7], mThumbnailUri);
- values.put(PROJECTION[8], mCanonicalGenres);
- values.put(PROJECTION[9], mContentRatings);
- values.put(PROJECTION[10], mStartTimeUtcMillis);
- values.put(PROJECTION[11], mEndTimeUtcMillis);
- values.put(PROJECTION[12], mVideoWidth);
- values.put(PROJECTION[13], mVideoHeight);
- return values;
- }
- }
-
- private Program getRecordedProgram() {
- ContentResolver resolver = mContext.getContentResolver();
- long avg = mRecordStartTime / 2 + mRecordEndTime / 2;
- Uri programUri = TvContract.buildProgramsUriForChannel(mChannel.getChannelId(), avg, avg);
- 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);
- }
- return result;
- } else {
- if (c == null) {
- Log.e(TAG, "Unknown query error for " + this);
- } else {
- if (DEBUG) {
- Log.d(TAG, "Canceled query for " + this);
- }
- }
- return null;
- }
- }
- }
-
- private Uri insertRecordedProgram(Program program, long channelId, String storageUri,
- long totalBytes, long startTime, long endTime) {
- RecordedProgram recordedProgram = RecordedProgram.builder()
- .setInputId(mInputId)
- .setChannelId(channelId)
- .setDataUri(storageUri)
- .setDurationMillis(endTime - startTime)
- .setDataBytes(totalBytes)
- .build();
- Uri uri = mContext.getContentResolver().insert(TvContract.RecordedPrograms.CONTENT_URI,
- RecordedProgram.toValues(recordedProgram));
- return uri;
- }
-
- private boolean onRecordingResult(boolean success) {
- if (mSessionState == STATE_RECORDING && success) {
- Uri uri = insertRecordedProgram(getRecordedProgram(), mChannel.getChannelId(),
- mStorageDir.toURI().toString(), 1024 * 1024,
- mRecordStartTime, mRecordEndTime);
- if (uri != null) {
- mSession.onRecordFinished(uri);
- }
- resetRecorder();
- return true;
- }
-
- if (mSessionState == STATE_RECORDING) {
- mSession.onRecordUnexpectedlyStopped(TvInputManager.RECORDING_ERROR_UNKNOWN);
- Log.w(TAG, "Recording failed: " + mChannel == null ? "" : mChannel.toString());
- resetRecorder();
- } else {
- Log.e(TAG, "Recording session status abnormal");
- reset();
- }
- return false;
- }
-
- private void onDeleteRecording(Uri mediaUri) {
- // TODO: notify the deletion result to LiveChannels
- File mediaDir = getMediaDir(mediaUri);
- if (mediaDir == null) {
- return;
- }
- for(File file: mediaDir.listFiles()) {
- file.delete();
- }
- mediaDir.delete();
- }
-
- private void onRelease() {
- // Current recording will be canceled.
- reset();
- mHandler.getLooper().quitSafely();
- // TODO: Remove failed recording files.
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/tvinput/UsbTunerTvInputService.java b/usbtuner/src/com/android/usbtuner/tvinput/UsbTunerTvInputService.java
deleted file mode 100644
index e91d8769..00000000
--- a/usbtuner/src/com/android/usbtuner/tvinput/UsbTunerTvInputService.java
+++ /dev/null
@@ -1,65 +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.usbtuner.tvinput;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.media.tv.TvContract;
-import android.os.Environment;
-import android.util.Log;
-
-import com.android.usbtuner.exoplayer.cache.CacheManager;
-import com.android.usbtuner.exoplayer.cache.TrickplayStorageManager;
-import com.android.usbtuner.util.SystemPropertiesProxy;
-
-import java.io.File;
-
-/**
- * {@link UsbTunerTvInputService} serves TV channels coming from a usb tuner device.
- */
-public class UsbTunerTvInputService extends BaseTunerTvInputService {
- private static final String TAG = "UsbTunerTvInputService";
- private static final boolean DEBUG = false;
-
-
- private static final String MAX_CACHE_SIZE_KEY = "usbtuner.cachesize_mbytes";
- private static final int MAX_CACHE_SIZE_DEF = 2 * 1024; // 2GB
- private static final int MIN_CACHE_SIZE_DEF = 256; // 256MB
-
- @Override
- protected CacheManager createCacheManager() {
- int maxCacheSizeMb = SystemPropertiesProxy.getInt(MAX_CACHE_SIZE_KEY, MAX_CACHE_SIZE_DEF);
- if (maxCacheSizeMb >= MIN_CACHE_SIZE_DEF) {
- boolean useExternalStorage = Environment.MEDIA_MOUNTED.equals(
- Environment.getExternalStorageState()) &&
- Environment.isExternalStorageRemovable();
- if (DEBUG) Log.d(TAG, "useExternalStorage for trickplay: " + useExternalStorage);
- boolean allowToUseInternalStorage = true;
- if (useExternalStorage || allowToUseInternalStorage) {
- File baseDir = useExternalStorage ? getExternalCacheDir() : getCacheDir();
- return new CacheManager(
- new TrickplayStorageManager(getApplicationContext(), baseDir,
- 1024L * 1024 * maxCacheSizeMb));
- }
- }
- return null;
- }
-
- public static String getInputId(Context context) {
- return TvContract.buildInputId(new ComponentName(context, UsbTunerTvInputService.class));
- }
-}
diff --git a/usbtuner/src/com/android/usbtuner/util/IsoUtils.java b/usbtuner/src/com/android/usbtuner/util/IsoUtils.java
deleted file mode 100644
index d9ffbe37..00000000
--- a/usbtuner/src/com/android/usbtuner/util/IsoUtils.java
+++ /dev/null
@@ -1,44 +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.usbtuner.util;
-
-import java.util.HashSet;
-import java.util.Locale;
-
-/**
- * Utility class for ISO codes.
- */
-public final class IsoUtils {
- private static final HashSet<String> ISO3_LANGUAGES = new HashSet<>();
-
- static {
- String[] languages = Locale.getISOLanguages();
- for (String lang : languages) {
- Locale locale = new Locale(lang);
- ISO3_LANGUAGES.add(locale.getISO3Language());
- }
- }
-
- private IsoUtils() { }
-
- /**
- * Returns {@code true} if a {@link String} is a valid ISO-639-2/T language code.
- */
- public static boolean isValidIso3Language(String langCode) {
- return ISO3_LANGUAGES.contains(langCode);
- }
-}
diff --git a/version.mk b/version.mk
index 49048f2a..f63f5834 100644
--- a/version.mk
+++ b/version.mk
@@ -48,13 +48,13 @@
base_version_major := 1
# Change this for each branch
-base_version_minor := 10
+base_version_minor := 11
# 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 := 596
+code_version_build := 011
#####################################################
#####################################################
# Collect automatic version code parameters