aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLive Channels Team <no-reply@google.com>2018-02-16 10:34:47 -0800
committerNick Chalko <nchalko@google.com>2018-02-16 11:50:03 -0800
commit0cc0713c1bf8027642987b750b80217569d2932a (patch)
treeafafc2e82a5626b383e495635c843c51ceb985c5
parentee959c2539b768dd3fbcbdf70acb03e536a9d76d (diff)
downloadTV-0cc0713c1bf8027642987b750b80217569d2932a.tar.gz
Changes imported from Live Channels
- 186014614 Sync more make files with master by nchalko <nchalko@google.com> - 186013553 FIX: safely parse URI from intents. by nchalko <nchalko@google.com> - 186010488 Add missing license header by nchalko <nchalko@google.com> - 186009400 Sync all make files with master by nchalko <nchalko@google.com> - 185891159 Extract a Channel interface by nchalko <nchalko@google.com> - 185885678 Make recording history available by shubang <shubang@google.com> - 185725900 Extract an interface for TunableTvView by nchalko <nchalko@google.com> - 185724604 CLEANUP: Move ImageLoader to a separate package by nchalko <nchalko@google.com> - 185722979 CLEANUP: Fix amiguous method reference by renaming static... by nchalko <nchalko@google.com> - 185721563 CLEANUP: create a seperate top level target for resources by nchalko <nchalko@google.com> - 185720102 CLEANUP: fix comparison using reference equality instead ... by nchalko <nchalko@google.com> - 185717674 CLEANUP: Move MemoryManageable to a separate package by nchalko <nchalko@google.com> - 185609615 FIX: Improve Program Guide description for talkback by nchalko <nchalko@google.com> - 185607602 PARTIAL: Speak the channel number for each item in the pr... by nchalko <nchalko@google.com> - 185552957 CLEANUP: Move TestUtils to tests/common by nchalko <nchalko@google.com> - 185549529 PARTIAL: Add program description to the content discripti... by nchalko <nchalko@google.com> - 185521822 Use robolectric 3.6.1 in android.mk by nchalko <nchalko@google.com> - 185521733 Add recording info to ProgramItemView content description by nchalko <nchalko@google.com> - 185459218 Add time to ProgramItemView content description by nchalko <nchalko@google.com> - 185449505 Add clock to the Utils.getDurationString by nchalko <nchalko@google.com> - 185435931 Inject the clock in ProgramItemView for testing by nchalko <nchalko@google.com> - 185435648 Fix link-type warnings by nchalko <nchalko@google.com> - 185435488 Migrate to AAPT2 by nchalko <nchalko@google.com> - 185434148 Add uptimeMillis to the Clock interface by nchalko <nchalko@google.com> PiperOrigin-RevId: 186014614 Change-Id: I583af9ac3e56161736504024b62d1fd62e31c15a Test: tested in google3
-rw-r--r--AndroidManifest.xml310
-rw-r--r--ResourceManifest.xml22
-rw-r--r--common/src/com/android/tv/common/CommonConstants.java38
-rw-r--r--common/src/com/android/tv/common/TvContentRatingCache.java1
-rw-r--r--common/src/com/android/tv/common/actions/InputSetupActionUtils.java127
-rw-r--r--common/src/com/android/tv/common/memory/MemoryManageable.java (renamed from common/src/com/android/tv/common/MemoryManageable.java)2
-rw-r--r--common/src/com/android/tv/common/util/CommonUtils.java13
-rw-r--r--common/src/com/android/tv/common/util/ContentUriUtils.java29
-rw-r--r--res/layout/activity_dvr_history.xml37
-rw-r--r--res/values/strings.xml2
-rw-r--r--src/com/android/tv/AudioManagerHelper.java5
-rw-r--r--src/com/android/tv/ChannelTuner.java2
-rw-r--r--src/com/android/tv/InputSessionManager.java2
-rw-r--r--src/com/android/tv/MainActivity.java50
-rw-r--r--src/com/android/tv/MainActivityWrapper.java2
-rw-r--r--src/com/android/tv/MediaSessionWrapper.java4
-rw-r--r--src/com/android/tv/SelectInputActivity.java5
-rw-r--r--src/com/android/tv/SetupPassthroughActivity.java14
-rw-r--r--src/com/android/tv/TimeShiftManager.java6
-rw-r--r--src/com/android/tv/TvFeatures.java3
-rw-r--r--src/com/android/tv/analytics/SendChannelStatusRunnable.java2
-rw-r--r--src/com/android/tv/analytics/StubTracker.java2
-rw-r--r--src/com/android/tv/analytics/Tracker.java2
-rw-r--r--src/com/android/tv/app/LiveTvApplication.java5
-rw-r--r--src/com/android/tv/data/ChannelDataManager.java5
-rw-r--r--src/com/android/tv/data/ChannelImpl.java (renamed from src/com/android/tv/data/Channel.java)178
-rw-r--r--src/com/android/tv/data/ChannelLogoFetcher.java5
-rw-r--r--src/com/android/tv/data/ChannelNumber.java9
-rw-r--r--src/com/android/tv/data/PreviewProgramContent.java2
-rw-r--r--src/com/android/tv/data/Program.java5
-rw-r--r--src/com/android/tv/data/ProgramDataManager.java14
-rw-r--r--src/com/android/tv/data/StreamInfo.java1
-rw-r--r--src/com/android/tv/data/WatchedHistoryManager.java1
-rw-r--r--src/com/android/tv/data/api/Channel.java130
-rw-r--r--src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java2
-rw-r--r--src/com/android/tv/data/epg/EpgFetcherImpl.java11
-rw-r--r--src/com/android/tv/data/epg/EpgReader.java4
-rw-r--r--src/com/android/tv/data/epg/StubEpgReader.java2
-rw-r--r--src/com/android/tv/dialog/DvrHistoryDialogFragment.java2
-rw-r--r--src/com/android/tv/dialog/RecentlyWatchedDialogFragment.java2
-rw-r--r--src/com/android/tv/dvr/BaseDvrDataManager.java5
-rw-r--r--src/com/android/tv/dvr/DvrDataManager.java3
-rw-r--r--src/com/android/tv/dvr/DvrDataManagerImpl.java2
-rw-r--r--src/com/android/tv/dvr/DvrManager.java2
-rw-r--r--src/com/android/tv/dvr/DvrScheduleManager.java6
-rw-r--r--src/com/android/tv/dvr/data/ScheduledRecording.java7
-rw-r--r--src/com/android/tv/dvr/recorder/ConflictChecker.java2
-rw-r--r--src/com/android/tv/dvr/recorder/InputTaskScheduler.java2
-rw-r--r--src/com/android/tv/dvr/recorder/RecordingTask.java2
-rw-r--r--src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java5
-rw-r--r--src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java2
-rw-r--r--src/com/android/tv/dvr/ui/DvrConflictFragment.java2
-rw-r--r--src/com/android/tv/dvr/ui/DvrFutureProgramInfoFragment.java2
-rw-r--r--src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java6
-rw-r--r--src/com/android/tv/dvr/ui/DvrUiHelper.java13
-rw-r--r--src/com/android/tv/dvr/ui/browse/DetailsContent.java2
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java13
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrHistoryCardHolder.java25
-rw-r--r--src/com/android/tv/dvr/ui/browse/DvrHistoryCardPresenter.java64
-rw-r--r--src/com/android/tv/dvr/ui/browse/RecordingCardView.java2
-rw-r--r--src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java3
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrHistoryActivity.java39
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java73
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java137
-rw-r--r--src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java4
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRow.java6
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java36
-rw-r--r--src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java58
-rw-r--r--src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java4
-rw-r--r--src/com/android/tv/guide/ProgramItemView.java224
-rw-r--r--src/com/android/tv/guide/ProgramListAdapter.java2
-rw-r--r--src/com/android/tv/guide/ProgramManager.java22
-rw-r--r--src/com/android/tv/guide/ProgramRow.java2
-rw-r--r--src/com/android/tv/guide/ProgramTableAdapter.java16
-rw-r--r--src/com/android/tv/menu/AppLinkCardView.java10
-rw-r--r--src/com/android/tv/menu/ChannelCardView.java4
-rw-r--r--src/com/android/tv/menu/ChannelsPosterPrefetcher.java5
-rw-r--r--src/com/android/tv/menu/ChannelsRowAdapter.java7
-rw-r--r--src/com/android/tv/menu/ChannelsRowItem.java2
-rw-r--r--src/com/android/tv/menu/MenuUpdater.java2
-rw-r--r--src/com/android/tv/menu/PlayControlsRowView.java2
-rw-r--r--src/com/android/tv/recommendation/ChannelPreviewUpdater.java2
-rw-r--r--src/com/android/tv/recommendation/ChannelRecord.java2
-rw-r--r--src/com/android/tv/recommendation/NotificationService.java17
-rw-r--r--src/com/android/tv/recommendation/RecommendationDataManager.java2
-rw-r--r--src/com/android/tv/recommendation/Recommender.java2
-rw-r--r--src/com/android/tv/search/DataManagerSearch.java2
-rw-r--r--src/com/android/tv/search/ProgramGuideSearchFragment.java7
-rw-r--r--src/com/android/tv/setup/SystemSetupActivity.java4
-rw-r--r--src/com/android/tv/ui/ChannelBannerView.java14
-rw-r--r--src/com/android/tv/ui/InputBannerView.java2
-rw-r--r--src/com/android/tv/ui/KeypadChannelSwitchView.java2
-rw-r--r--src/com/android/tv/ui/SelectInputView.java2
-rw-r--r--src/com/android/tv/ui/TunableTvView.java32
-rw-r--r--src/com/android/tv/ui/TunableTvViewPlayingApi.java56
-rw-r--r--src/com/android/tv/ui/TvTransitionManager.java2
-rw-r--r--src/com/android/tv/ui/sidepanel/ChannelCheckItem.java2
-rw-r--r--src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java7
-rw-r--r--src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java2
-rw-r--r--src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java2
-rw-r--r--src/com/android/tv/util/AsyncDbTask.java7
-rw-r--r--src/com/android/tv/util/SetupUtils.java2
-rw-r--r--src/com/android/tv/util/TvInputManagerHelper.java6
-rw-r--r--src/com/android/tv/util/Utils.java53
-rw-r--r--src/com/android/tv/util/images/BitmapUtils.java (renamed from src/com/android/tv/util/BitmapUtils.java)2
-rw-r--r--src/com/android/tv/util/images/ImageCache.java (renamed from src/com/android/tv/util/ImageCache.java)6
-rw-r--r--src/com/android/tv/util/images/ImageLoader.java (renamed from src/com/android/tv/util/ImageLoader.java)4
-rw-r--r--tests/common/src/com/android/tv/testing/EpgTestData.java5
-rw-r--r--tests/common/src/com/android/tv/testing/FakeEpgReader.java5
-rw-r--r--tests/common/src/com/android/tv/testing/TestSingletonApp.java17
-rw-r--r--tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java21
-rw-r--r--tests/common/src/com/android/tv/testing/testdata/TestData.java31
-rw-r--r--tests/common/src/com/android/tv/testing/utils/TestUtils.java (renamed from tests/unit/src/com/android/tv/util/TestUtils.java)4
-rw-r--r--tests/unit/src/com/android/tv/BaseMainActivityTestCase.java2
-rw-r--r--tests/unit/src/com/android/tv/MainActivityTest.java2
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java1
-rw-r--r--tests/unit/src/com/android/tv/data/ChannelImplTest.java (renamed from tests/unit/src/com/android/tv/data/ChannelTest.java)46
-rw-r--r--tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java2
-rw-r--r--tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java4
-rw-r--r--tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java2
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java5
-rw-r--r--tests/unit/src/com/android/tv/recommendation/RecommenderTest.java2
-rw-r--r--tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java1
-rw-r--r--tests/unit/src/com/android/tv/util/images/ImageCacheTest.java (renamed from tests/unit/src/com/android/tv/util/ImageCacheTest.java)6
-rw-r--r--tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java (renamed from tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java)4
-rw-r--r--tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java4
-rw-r--r--tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml2
128 files changed, 1705 insertions, 589 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 970c3046..3456f16b 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -13,15 +13,18 @@
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
- -->
-
+-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.tv" xmlns:tools="http://schemas.android.com/tools">
+ package="com.android.tv" >
+
+ <uses-sdk
+ android:minSdkVersion="23"
+ android:targetSdkVersion="26" />
- <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_HDMI_CEC_ACTIVE_SOURCE" />
- <uses-permission android:name="android.permission.GLOBAL_SEARCH" tools:ignore="ProtectedPermissions"/>
+ <uses-permission android:name="android.permission.GLOBAL_SEARCH" />
<uses-permission android:name="android.permission.HDMI_CEC" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_PARENTAL_CONTROLS" />
@@ -33,56 +36,94 @@
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_ALL_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.ACCESS_WATCHED_PROGRAMS" />
-
<!-- Permissions/feature for USB tuner -->
<uses-permission android:name="android.permission.DVB_DEVICE" />
- <uses-feature android:name="android.hardware.usb.host" android:required="false" />
+
+ <uses-feature
+ android:name="android.hardware.usb.host"
+ android:required="false" />
<!-- Limit only for Android TV -->
- <uses-feature android:name="android.software.leanback" android:required="true" />
- <uses-feature android:name="android.software.live_tv" android:required="true" />
- <uses-feature android:name="android.hardware.touchscreen" android:required="false"/>
+ <uses-feature
+ android:name="android.software.leanback"
+ android:required="true" />
+ <uses-feature
+ android:name="android.software.live_tv"
+ android:required="true" />
+ <uses-feature
+ android:name="android.hardware.touchscreen"
+ android:required="false" />
<!-- Receives input events from the TV app. -->
- <permission android:name="com.android.tv.permission.RECEIVE_INPUT_EVENT"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_receiveInputEvent"
+ <permission
+ android:name="com.android.tv.permission.RECEIVE_INPUT_EVENT"
android:description="@string/permdesc_receiveInputEvent"
- tools:ignore="SignatureOrSystemPermissions"/>
+ android:label="@string/permlab_receiveInputEvent"
+ android:protectionLevel="signatureOrSystem" />
<!-- Customizes Live TV with customization packages. -->
- <permission android:name="com.android.tv.permission.CUSTOMIZE_TV_APP"
- android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_customizeTvApp"
+ <permission
+ android:name="com.android.tv.permission.CUSTOMIZE_TV_APP"
android:description="@string/permdesc_customizeTvApp"
- tools:ignore="SignatureOrSystemPermissions"/>
-
- <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23"/>
+ android:label="@string/permlab_customizeTvApp"
+ android:protectionLevel="signatureOrSystem" />
- <application android:label="@string/app_name"
+ <application
android:name="com.android.tv.app.LiveTvApplication"
android:allowBackup="true"
- android:icon="@drawable/ic_live_channels"
android:banner="@drawable/banner"
+ android:icon="@drawable/ic_live_channels"
+ android:label="@string/app_name"
android:supportsRtl="true"
- android:theme="@style/Theme.TV">
- <activity android:name="com.android.tv.TvActivity">
+ android:theme="@style/Theme.TV" >
+ <activity
+ android:name="com.android.tv.tuner.setup.LiveTvTunerSetupActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:label="@string/bt_app_name"
+ android:launchMode="singleInstance"
+ android:process="com.android.tv.tuner"
+ android:theme="@style/Theme.Setup.GuidedStep" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ </intent-filter>
+ </activity>
+
+ <!-- providers are listed here to keep them separate from the internal versions -->
+ <provider
+ android:name="com.android.tv.search.LocalSearchProvider"
+ android:authorities="com.android.tv.search"
+ android:enabled="true"
+ android:exported="true" >
+ <meta-data
+ android:name="SupportedSwitchActionType"
+ android:value="CHANNEL|TVINPUT" />
+ </provider>
+ <provider
+ android:name="com.android.tv.common.CommonPreferenceProvider"
+ android:authorities="com.android.tv.common.preferences"
+ android:exported="false"
+ android:process="com.android.tv.common" />
+
+ <activity android:name="com.android.tv.TvActivity" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
+
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter>
</activity>
-
- <activity android:name="com.android.tv.MainActivity"
+ <activity
+ android:name="com.android.tv.MainActivity"
android:configChanges="keyboard|keyboardHidden|screenSize|smallestScreenSize|screenLayout|orientation"
- android:screenOrientation="landscape"
android:launchMode="singleTask"
android:resizeableActivity="true"
+ android:screenOrientation="landscape"
android:supportsPictureInPicture="true"
- android:theme="@style/Theme.TV.MainActivity">
+ android:theme="@style/Theme.TV.MainActivity" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+
<category android:name="android.intent.category.DEFAULT" />
+
<data android:mimeType="vnd.android.cursor.item/channel" />
<data android:mimeType="vnd.android.cursor.dir/channel" />
<data android:mimeType="vnd.android.cursor.item/program" />
@@ -90,170 +131,146 @@
</intent-filter>
<intent-filter>
<action android:name="android.media.tv.action.SETUP_INPUTS" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
- <meta-data android:name="supports_leanback" android:value="true" />
- <meta-data android:name="android.app.searchable"
+
+ <meta-data
+ android:name="supports_leanback"
+ android:value="true" />
+ <meta-data
+ android:name="android.app.searchable"
android:resource="@xml/searchable" />
</activity>
-
- <activity android:name="com.android.tv.LauncherActivity"
+ <activity
+ android:name="com.android.tv.LauncherActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
-
- <activity android:name="com.android.tv.SetupPassthroughActivity"
+ <activity
+ android:name="com.android.tv.SetupPassthroughActivity"
android:configChanges="keyboard|keyboardHidden"
- android:theme="@android:style/Theme.Translucent.NoTitleBar">
+ android:exported="true"
+ android:theme="@android:style/Theme.Translucent.NoTitleBar" >
<intent-filter>
<action android:name="com.android.tv.action.LAUNCH_INPUT_SETUP" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
-
- <activity android:name="com.android.tv.SelectInputActivity"
+ <activity
+ android:name="com.android.tv.SelectInputActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
android:theme="@style/Theme.SelectInputActivity" />
-
- <activity android:name="com.android.tv.onboarding.OnboardingActivity"
+ <activity
+ android:name="com.android.tv.onboarding.OnboardingActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTop"
android:theme="@style/Theme.Setup.GuidedStep" />
-
- <activity android:name="com.android.tv.dvr.ui.browse.DvrBrowseActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.browse.DvrBrowseActivity"
android:configChanges="keyboard|keyboardHidden"
android:launchMode="singleTask"
- android:theme="@style/Theme.Leanback.Browse">
+ android:theme="@style/Theme.Leanback.Browse" >
<intent-filter>
<action android:name="android.media.tv.action.VIEW_RECORDING_SCHEDULES" />
+
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+
<category android:name="android.intent.category.DEFAULT" />
+
<data android:mimeType="vnd.android.cursor.dir/recorded_program" />
</intent-filter>
</activity>
-
- <activity android:name="com.android.tv.dvr.ui.playback.DvrPlaybackActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.playback.DvrPlaybackActivity"
android:configChanges="keyboard|keyboardHidden|screenSize|smallestScreenSize|screenLayout|orientation"
android:launchMode="singleTask"
- android:theme="@style/Theme.Leanback">
+ android:theme="@style/Theme.Leanback" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
+
<category android:name="android.intent.category.DEFAULT" />
+
<data android:mimeType="vnd.android.cursor.item/recorded_program" />
</intent-filter>
</activity>
-
- <activity android:name="com.android.tv.dvr.ui.browse.DvrDetailsActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.browse.DvrDetailsActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Browse.Details" />
-
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesSettingsActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.DvrSeriesSettingsActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Series.Settings.GuidedStep" />
-
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesDeletionActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.DvrSeriesDeletionActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.TV.Dvr.Series.Deletion.GuidedStep" />
-
- <activity android:name="com.android.tv.dvr.ui.DvrSeriesScheduledDialogActivity"
- android:theme="@style/Theme.TV.dialog.HalfSizedDialog"/>
-
- <activity android:name="com.android.tv.dvr.ui.list.DvrSchedulesActivity"
+ <activity
+ android:name="com.android.tv.dvr.ui.DvrSeriesScheduledDialogActivity"
+ android:theme="@style/Theme.TV.dialog.HalfSizedDialog" />
+ <activity
+ android:name="com.android.tv.dvr.ui.list.DvrSchedulesActivity"
android:configChanges="keyboard|keyboardHidden"
android:theme="@style/Theme.Leanback.Details" />
+ <activity
+ android:name="com.android.tv.dvr.ui.list.DvrHistoryActivity"
+ android:configChanges="keyboard|keyboardHidden"
+ android:exported="false"
+ android:theme="@style/Theme.Leanback.Details" />
- <provider android:name="com.android.tv.search.LocalSearchProvider"
- android:authorities="com.android.tv.search"
- android:exported="true"
- android:enabled="true" tools:ignore="ExportedContentProvider"
- >
- <meta-data android:name="SupportedSwitchActionType" android:value="CHANNEL|TVINPUT" />
- </provider>
-
- <service android:name="com.android.tv.recommendation.NotificationService"
- android:exported="false" />
- <service android:name="com.android.tv.recommendation.ChannelPreviewUpdater$ChannelPreviewUpdateService"
- android:permission="android.permission.BIND_JOB_SERVICE" />
+ <service
+ android:name="com.android.tv.recommendation.NotificationService"
+ android:exported="false" />
+ <service
+ android:name="com.android.tv.recommendation.ChannelPreviewUpdater$ChannelPreviewUpdateService"
+ android:permission="android.permission.BIND_JOB_SERVICE" />
- <receiver android:name="com.android.tv.receiver.BootCompletedReceiver">
+ <receiver android:name="com.android.tv.receiver.BootCompletedReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
- <receiver android:name="com.android.tv.receiver.PackageIntentsReceiver">
+ <receiver android:name="com.android.tv.receiver.PackageIntentsReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<!-- PACKAGE_CHANGED for package enabled/disabled notification -->
<action android:name="android.intent.action.PACKAGE_CHANGED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
- <data android:scheme="package"/>
+
+ <data android:scheme="package" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
- </receiver>
- <receiver android:name="com.android.tv.livetv.receiver.GlobalKeyReceiver">
- <intent-filter>
- <action android:name="android.intent.action.GLOBAL_BUTTON" />
- </intent-filter>
-
- <!-- Not directly related to GlobalKeyReceiver but needed to be able to provide our
- content rating definitions to the system service. -->
- <intent-filter>
- <action android:name="android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
- </intent-filter>
- <meta-data android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
- android:resource="@xml/tv_content_rating_systems" />
- </receiver>
-
- <!-- USB tuner components definition -->
- <activity android:name="com.android.tv.tuner.setup.LiveTvTunerSetupActivity"
+ </receiver> <!-- System initial setup component definition -->
+ <activity
+ android:name="com.android.tv.setup.SystemSetupActivity"
android:configChanges="keyboard|keyboardHidden"
+ android:exported="true"
android:label="@string/bt_app_name"
android:launchMode="singleInstance"
- android:process="com.android.tv.tuner"
android:theme="@style/Theme.Setup.GuidedStep" >
<intent-filter>
- <action android:name="android.intent.action.MAIN" />
- </intent-filter>
- </activity>
-
- <service android:name="com.android.tv.tuner.livetuner.LiveTvTunerTvInputService"
- android:enabled="false"
- 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" />
- </intent-filter>
- <meta-data android:name="android.media.tv.input"
- android:resource="@xml/ut_tvinputservice" />
- </service>
-
- <provider android:name="com.android.tv.common.CommonPreferenceProvider"
- android:authorities="com.android.tv.common.preferences"
- android:process="com.android.tv.common"
- android:exported="false" />
- <!-- System initial setup component definition -->
- <activity android:name="com.android.tv.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="com.android.tv.tuner.TunerInputController$IntentReceiver"
- android:exported="false">
+ <!--
+ TunerInputController should be the same process with MainActivity to check status
+ of MainActivity
+ -->
+ <receiver
+ android:name="com.android.tv.tuner.TunerInputController$IntentReceiver"
+ android:exported="false" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
@@ -262,19 +279,56 @@
<action android:name="com.android.tv.action.NETWORK_TUNER_ATTACHED" />
<action android:name="com.android.tv.action.NETWORK_TUNER_DETACHED" />
</intent-filter>
- </receiver>
+ </receiver> <!-- DVR -->
+ <service
+ android:name="com.android.tv.dvr.recorder.DvrRecordingService"
+ android:label="@string/dvr_service_name" />
- <!-- DVR -->
- <service android:name="com.android.tv.dvr.recorder.DvrRecordingService" android:label="@string/dvr_service_name" />
<receiver android:name="com.android.tv.dvr.recorder.DvrStartRecordingReceiver" />
- <service android:name="com.android.tv.tuner.tvinput.TunerStorageCleanUpService"
+ <service
+ android:name="com.android.tv.tuner.tvinput.TunerStorageCleanUpService"
+ android:exported="false"
android:permission="android.permission.BIND_JOB_SERVICE"
- android:process="com.android.tv.tuner"
- android:exported="false" />
-
- <service android:name="com.android.tv.data.epg.EpgFetchService"
+ android:process="com.android.tv.tuner" />
+ <service
+ android:name="com.android.tv.data.epg.EpgFetchService"
android:permission="android.permission.BIND_JOB_SERVICE" />
+ <receiver
+ android:name="com.android.tv.livetv.receiver.GlobalKeyReceiver"
+ android:exported="true" >
+ <intent-filter>
+ <action android:name="android.intent.action.GLOBAL_BUTTON" />
+ </intent-filter>
+
+ <!--
+ Not directly related to GlobalKeyReceiver but needed to be able to provide our
+ content rating definitions to the system service.
+ -->
+ <intent-filter>
+ <action android:name="android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS" />
+ </intent-filter>
+
+ <meta-data
+ android:name="android.media.tv.metadata.CONTENT_RATING_SYSTEMS"
+ android:resource="@xml/tv_content_rating_systems" />
+ </receiver>
+
+ <service
+ android:name="com.android.tv.tuner.livetuner.LiveTvTunerTvInputService"
+ android:enabled="false"
+ android:label="@string/bt_app_name"
+ android:permission="android.permission.BIND_TV_INPUT"
+ android:process="com.android.tv.tuner" >
+ <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>
+
+</manifest> \ No newline at end of file
diff --git a/ResourceManifest.xml b/ResourceManifest.xml
new file mode 100644
index 00000000..a859327f
--- /dev/null
+++ b/ResourceManifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tv" xmlns:tools="http://schemas.android.com/tools">
+ <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23"/>
+ <application />
+</manifest>
diff --git a/common/src/com/android/tv/common/CommonConstants.java b/common/src/com/android/tv/common/CommonConstants.java
index 44799f6b..ac379d18 100644
--- a/common/src/com/android/tv/common/CommonConstants.java
+++ b/common/src/com/android/tv/common/CommonConstants.java
@@ -16,51 +16,13 @@
package com.android.tv.common;
-import android.media.tv.TvInputInfo;
-
/** Constants for common use in apps and tests. */
public final class CommonConstants {
public static final String BASE_PACKAGE =
"com.android.tv";
-
/** A constant for the key of the extra data for the app linking intent. */
public static final String EXTRA_APP_LINK_CHANNEL_URI = "app_link_channel_uri";
- /**
- * An intent action to launch setup activity of a TV input. The intent should include TV input
- * ID in the value of {@link #EXTRA_INPUT_ID}. Optionally, given the value of {@link
- * #EXTRA_ACTIVITY_AFTER_COMPLETION}, the activity will be launched after the setup activity
- * successfully finishes.
- */
- public static final String INTENT_ACTION_INPUT_SETUP =
- "com.android.tv.action.LAUNCH_INPUT_SETUP";
-
- /**
- * A constant of the key to indicate a TV input ID for the intent action {@link
- * #INTENT_ACTION_INPUT_SETUP}.
- *
- * <p>Value type: String
- */
- public static final String EXTRA_INPUT_ID = TvInputInfo.EXTRA_INPUT_ID;
-
- /**
- * A constant of the key for intent to launch actual TV input setup activity used with {@link
- * #INTENT_ACTION_INPUT_SETUP}.
- *
- * <p>Value type: Intent (Parcelable)
- */
- public static final String EXTRA_SETUP_INTENT =
- CommonConstants.BASE_PACKAGE + ".extra.SETUP_INTENT";
-
- /**
- * A constant of the key to indicate an Activity launch intent for the intent action {@link
- * #INTENT_ACTION_INPUT_SETUP}.
- *
- * <p>Value type: Intent (Parcelable)
- */
- public static final String EXTRA_ACTIVITY_AFTER_COMPLETION =
- CommonConstants.BASE_PACKAGE + ".intent.extra.ACTIVITY_AFTER_COMPLETION";
-
private CommonConstants() {}
}
diff --git a/common/src/com/android/tv/common/TvContentRatingCache.java b/common/src/com/android/tv/common/TvContentRatingCache.java
index 5f91ee3e..cfdb8e4d 100644
--- a/common/src/com/android/tv/common/TvContentRatingCache.java
+++ b/common/src/com/android/tv/common/TvContentRatingCache.java
@@ -22,6 +22,7 @@ import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import com.android.tv.common.memory.MemoryManageable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
diff --git a/common/src/com/android/tv/common/actions/InputSetupActionUtils.java b/common/src/com/android/tv/common/actions/InputSetupActionUtils.java
new file mode 100644
index 00000000..7ba799ed
--- /dev/null
+++ b/common/src/com/android/tv/common/actions/InputSetupActionUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.common.actions;
+
+import android.content.Intent;
+import android.media.tv.TvInputInfo;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+/** Constants and static utilities for the Input Setup Action. */
+public class InputSetupActionUtils {
+
+ /**
+ * An intent action to launch setup activity of a TV input.
+ *
+ * <p>The intent should include TV input ID in the value of {@link #EXTRA_INPUT_ID}. Optionally,
+ * given the value of {@link #EXTRA_ACTIVITY_AFTER_COMPLETION}, the activity will be launched
+ * after the setup activity successfully finishes.
+ */
+ public static final String INTENT_ACTION_INPUT_SETUP =
+ "com.android.tv.action.LAUNCH_INPUT_SETUP";
+ /**
+ * A constant of the key to indicate a TV input ID for the intent action {@link
+ * #INTENT_ACTION_INPUT_SETUP}.
+ *
+ * <p>Value type: String
+ */
+ public static final String EXTRA_INPUT_ID = TvInputInfo.EXTRA_INPUT_ID;
+ /**
+ * A constant of the key for intent to launch actual TV input setup activity used with {@link
+ * #INTENT_ACTION_INPUT_SETUP}.
+ *
+ * <p>Value type: Intent (Parcelable)
+ */
+ public static final String EXTRA_SETUP_INTENT = "com.android.tv.extra.SETUP_INTENT";
+ /**
+ * A constant of the key to indicate an Activity launch intent for the intent action {@link
+ * #INTENT_ACTION_INPUT_SETUP}.
+ *
+ * <p>Value type: Intent (Parcelable)
+ */
+ public static final String EXTRA_ACTIVITY_AFTER_COMPLETION =
+ "com.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION";
+ /**
+ * An intent action to launch setup activity of a TV input.
+ *
+ * <p>The intent should include TV input ID in the value of {@link #EXTRA_INPUT_ID}. Optionally,
+ * given the value of {@link #EXTRA_GOOGLE_ACTIVITY_AFTER_COMPLETION}, the activity will be
+ * launched after the setup activity successfully finishes.
+ *
+ * <p>Value type: Intent (Parcelable)
+ *
+ * @deprecated Use {@link #INTENT_ACTION_INPUT_SETUP} instead
+ */
+ @Deprecated
+ private static final String INTENT_GOOGLE_ACTION_INPUT_SETUP =
+ "com.google.android.tv.action.LAUNCH_INPUT_SETUP";
+ /**
+ * A Google specific constant of the key for intent to launch actual TV input setup activity
+ * used with {@link #INTENT_ACTION_INPUT_SETUP}.
+ *
+ * <p>Value type: Intent (Parcelable)
+ *
+ * @deprecated Use {@link #EXTRA_SETUP_INTENT} instead
+ */
+ @Deprecated
+ private static final String EXTRA_GOOGLE_SETUP_INTENT =
+ "com.google.android.tv.extra.SETUP_INTENT";
+ /**
+ * A Google specific constant of the key to indicate an Activity launch intent for the intent
+ * action {@link #INTENT_ACTION_INPUT_SETUP}.
+ *
+ * <p>Value type: Intent (Parcelable)
+ *
+ * @deprecated Use {@link #EXTRA_ACTIVITY_AFTER_COMPLETION} instead
+ */
+ @Deprecated
+ private static final String EXTRA_GOOGLE_ACTIVITY_AFTER_COMPLETION =
+ "com.google.android.tv.intent.extra.ACTIVITY_AFTER_COMPLETION";
+
+ public static void removeSetupIntent(Bundle extras) {
+ extras.remove(EXTRA_SETUP_INTENT);
+ extras.remove(EXTRA_GOOGLE_SETUP_INTENT);
+ }
+
+ @Nullable
+ public static Intent getExtraSetupIntent(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return null;
+ }
+ Intent setupIntent = extras.getParcelable(EXTRA_SETUP_INTENT);
+ return setupIntent != null ? setupIntent : extras.getParcelable(EXTRA_GOOGLE_SETUP_INTENT);
+ }
+
+ @Nullable
+ public static Intent getExtraActivityAfter(Intent intent) {
+ Bundle extras = intent.getExtras();
+ if (extras == null) {
+ return null;
+ }
+ Intent setupIntent = extras.getParcelable(EXTRA_ACTIVITY_AFTER_COMPLETION);
+ return setupIntent != null
+ ? setupIntent
+ : extras.getParcelable(EXTRA_GOOGLE_ACTIVITY_AFTER_COMPLETION);
+ }
+
+ public static boolean hasInputSetupAction(Intent intent) {
+ String action = intent.getAction();
+ return INTENT_ACTION_INPUT_SETUP.equals(action)
+ || INTENT_GOOGLE_ACTION_INPUT_SETUP.equals(action);
+ }
+}
diff --git a/common/src/com/android/tv/common/MemoryManageable.java b/common/src/com/android/tv/common/memory/MemoryManageable.java
index f782ccde..3e81fb5e 100644
--- a/common/src/com/android/tv/common/MemoryManageable.java
+++ b/common/src/com/android/tv/common/memory/MemoryManageable.java
@@ -14,7 +14,7 @@
* limitations under the License
*/
-package com.android.tv.common;
+package com.android.tv.common.memory;
/**
* Interface for the fine-grained memory management. The class which wants to release memory based
diff --git a/common/src/com/android/tv/common/util/CommonUtils.java b/common/src/com/android/tv/common/util/CommonUtils.java
index 6d9fb76a..00574586 100644
--- a/common/src/com/android/tv/common/util/CommonUtils.java
+++ b/common/src/com/android/tv/common/util/CommonUtils.java
@@ -23,6 +23,7 @@ import android.os.Build;
import android.util.ArraySet;
import com.android.tv.common.BuildConfig;
import com.android.tv.common.CommonConstants;
+import com.android.tv.common.actions.InputSetupActionUtils;
import com.android.tv.common.experiments.Experiments;
import java.io.File;
import java.text.SimpleDateFormat;
@@ -58,17 +59,17 @@ public final class CommonUtils {
/**
* Returns an intent to start the setup activity for the TV input using {@link
- * CommonConstants#INTENT_ACTION_INPUT_SETUP}.
+ * InputSetupActionUtils#INTENT_ACTION_INPUT_SETUP}.
*/
public static Intent createSetupIntent(Intent originalSetupIntent, String inputId) {
if (originalSetupIntent == null) {
return null;
}
Intent setupIntent = new Intent(originalSetupIntent);
- if (!CommonConstants.INTENT_ACTION_INPUT_SETUP.equals(originalSetupIntent.getAction())) {
- Intent intentContainer = new Intent(CommonConstants.INTENT_ACTION_INPUT_SETUP);
- intentContainer.putExtra(CommonConstants.EXTRA_SETUP_INTENT, originalSetupIntent);
- intentContainer.putExtra(CommonConstants.EXTRA_INPUT_ID, inputId);
+ if (!InputSetupActionUtils.hasInputSetupAction(originalSetupIntent)) {
+ Intent intentContainer = new Intent(InputSetupActionUtils.INTENT_ACTION_INPUT_SETUP);
+ intentContainer.putExtra(InputSetupActionUtils.EXTRA_SETUP_INTENT, originalSetupIntent);
+ intentContainer.putExtra(InputSetupActionUtils.EXTRA_INPUT_ID, inputId);
setupIntent = intentContainer;
}
return setupIntent;
@@ -76,7 +77,7 @@ public final class CommonUtils {
/**
* Returns an intent to start the setup activity for this TV input using {@link
- * CommonConstants#INTENT_ACTION_INPUT_SETUP}.
+ * InputSetupActionUtils#INTENT_ACTION_INPUT_SETUP}.
*/
public static Intent createSetupIntent(TvInputInfo input) {
return createSetupIntent(input.createSetupIntent(), input.getId());
diff --git a/common/src/com/android/tv/common/util/ContentUriUtils.java b/common/src/com/android/tv/common/util/ContentUriUtils.java
new file mode 100644
index 00000000..4f1a1ef6
--- /dev/null
+++ b/common/src/com/android/tv/common/util/ContentUriUtils.java
@@ -0,0 +1,29 @@
+package com.android.tv.common.util;
+
+import android.content.ContentUris;
+import android.net.Uri;
+import android.util.Log;
+
+/** Static utils for{@link android.content.ContentUris}. */
+public class ContentUriUtils {
+ private static final String TAG = "ContentUriUtils";
+
+ /**
+ * Converts the last path segment to a long.
+ *
+ * <p>This supports a common convention for content URIs where an ID is stored in the last
+ * segment.
+ *
+ * @return the long conversion of the last segment or -1 if the path is empty or there is any
+ * error
+ * @see ContentUris#parseId(Uri)
+ */
+ public static long safeParseId(Uri uri) {
+ try {
+ return ContentUris.parseId(uri);
+ } catch (Exception e) {
+ Log.d(TAG, "Error parsing " + uri, e);
+ return -1;
+ }
+ }
+}
diff --git a/res/layout/activity_dvr_history.xml b/res/layout/activity_dvr_history.xml
new file mode 100644
index 00000000..c44bc8a3
--- /dev/null
+++ b/res/layout/activity_dvr_history.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/dvr_history"
+ 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/values/strings.xml b/res/values/strings.xml
index bdc5811e..182171a8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -572,6 +572,8 @@
<!-- 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 DVR history. [CHAR LIMIT=25] -->
+ <string name="dvr_history_card_view_title">DVR History</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] -->
diff --git a/src/com/android/tv/AudioManagerHelper.java b/src/com/android/tv/AudioManagerHelper.java
index b0187617..942d431d 100644
--- a/src/com/android/tv/AudioManagerHelper.java
+++ b/src/com/android/tv/AudioManagerHelper.java
@@ -21,6 +21,7 @@ import android.media.AudioManager;
import android.os.Build;
import com.android.tv.receiver.AudioCapabilitiesReceiver;
import com.android.tv.ui.TunableTvView;
+import com.android.tv.ui.TunableTvViewPlayingApi;
/** A helper class to help {@link MainActivity} to handle audio-related stuffs. */
class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener {
@@ -29,14 +30,14 @@ class AudioManagerHelper implements AudioManager.OnAudioFocusChangeListener {
private static final float AUDIO_DUCKING_VOLUME = 0.3f;
private final Activity mActivity;
- private final TunableTvView mTvView;
+ private final TunableTvViewPlayingApi mTvView;
private final AudioManager mAudioManager;
private final AudioCapabilitiesReceiver mAudioCapabilitiesReceiver;
private boolean mAc3PassthroughSupported;
private int mAudioFocusStatus = AudioManager.AUDIOFOCUS_LOSS;
- AudioManagerHelper(Activity activity, TunableTvView tvView) {
+ AudioManagerHelper(Activity activity, TunableTvViewPlayingApi tvView) {
mActivity = activity;
mTvView = tvView;
mAudioManager = (AudioManager) activity.getSystemService(Context.AUDIO_SERVICE);
diff --git a/src/com/android/tv/ChannelTuner.java b/src/com/android/tv/ChannelTuner.java
index c6fb329c..8ab145a4 100644
--- a/src/com/android/tv/ChannelTuner.java
+++ b/src/com/android/tv/ChannelTuner.java
@@ -25,8 +25,8 @@ import android.support.annotation.Nullable;
import android.util.ArraySet;
import android.util.Log;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/src/com/android/tv/InputSessionManager.java b/src/com/android/tv/InputSessionManager.java
index 416dbb68..4f298ed6 100644
--- a/src/com/android/tv/InputSessionManager.java
+++ b/src/com/android/tv/InputSessionManager.java
@@ -36,7 +36,7 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.ui.TunableTvView;
import com.android.tv.ui.TunableTvView.OnTuneListener;
import com.android.tv.util.TvInputManagerHelper;
diff --git a/src/com/android/tv/MainActivity.java b/src/com/android/tv/MainActivity.java
index edbed077..b5c0b28d 100644
--- a/src/com/android/tv/MainActivity.java
+++ b/src/com/android/tv/MainActivity.java
@@ -70,24 +70,26 @@ import com.android.tv.analytics.SendConfigInfoRunnable;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.BuildConfig;
import com.android.tv.common.CommonPreferences;
-import com.android.tv.common.MemoryManageable;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.feature.CommonFeatures;
+import com.android.tv.common.memory.MemoryManageable;
import com.android.tv.common.ui.setup.OnActionClickListener;
import com.android.tv.common.util.CommonUtils;
+import com.android.tv.common.util.ContentUriUtils;
import com.android.tv.common.util.Debug;
import com.android.tv.common.util.DurationTimer;
import com.android.tv.common.util.PermissionUtils;
import com.android.tv.common.util.SystemProperties;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
import com.android.tv.data.StreamInfo;
import com.android.tv.data.WatchedHistoryManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener;
@@ -127,7 +129,6 @@ import com.android.tv.ui.sidepanel.SideFragment;
import com.android.tv.ui.sidepanel.parentalcontrols.ParentalControlsFragment;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.CaptionSettings;
-import com.android.tv.util.ImageCache;
import com.android.tv.util.OnboardingUtils;
import com.android.tv.util.RecurringRunner;
import com.android.tv.util.SetupUtils;
@@ -137,6 +138,7 @@ import com.android.tv.util.TvTrackInfoUtils;
import com.android.tv.util.Utils;
import com.android.tv.util.ViewCache;
import com.android.tv.util.account.AccountHelper;
+import com.android.tv.util.images.ImageCache;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -616,7 +618,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if (TextUtils.equals(input.getId(), currentInputId)) {
hideOverlays();
} else {
- tuneToChannel(Channel.createPassthroughChannel(input.getId()));
+ tuneToChannel(ChannelImpl.createPassthroughChannel(input.getId()));
}
}
@@ -1024,7 +1026,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
mChannelTuner.moveToChannel(mChannelTuner.findNearestBrowsableChannel(0));
} else {
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
- Channel channel = Channel.createPassthroughChannel(channelUri);
+ ChannelImpl channel = ChannelImpl.createPassthroughChannel(channelUri);
mChannelTuner.moveToChannel(channel);
} else {
long channelId = ContentUris.parseId(channelUri);
@@ -1487,15 +1489,17 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
String programUriString = intent.getStringExtra(SearchManager.EXTRA_DATA_KEY);
Uri programUriFromIntent =
programUriString == null ? null : Uri.parse(programUriString);
- long channelIdFromIntent = ContentUris.parseId(mInitChannelUri);
- if (programUriFromIntent != null) {
+ long channelIdFromIntent = ContentUriUtils.safeParseId(mInitChannelUri);
+ if (programUriFromIntent != null && channelIdFromIntent != Channel.INVALID_ID) {
new AsyncQueryProgramTask(
- TvSingletons.getSingletons(this).getDbExecutor(),
- getContentResolver(),
- programUriFromIntent,
- Program.PROJECTION,
- null, null, null,
- channelIdFromIntent)
+ TvSingletons.getSingletons(this).getDbExecutor(),
+ getContentResolver(),
+ programUriFromIntent,
+ Program.PROJECTION,
+ null,
+ null,
+ null,
+ channelIdFromIntent)
.executeOnDbThread();
}
if (mTuneParams == null) {
@@ -1554,8 +1558,14 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
private class AsyncQueryProgramTask extends AsyncDbTask.AsyncQueryTask<Program> {
private final long mChannelIdFromIntent;
- public AsyncQueryProgramTask(Executor executor, ContentResolver contentResolver, Uri uri,
- String[] projection, String selection, String[] selectionArgs, String orderBy,
+ public AsyncQueryProgramTask(
+ Executor executor,
+ ContentResolver contentResolver,
+ Uri uri,
+ String[] projection,
+ String selection,
+ String[] selectionArgs,
+ String orderBy,
long channelId) {
super(executor, contentResolver, uri, projection, selection, selectionArgs, orderBy);
mChannelIdFromIntent = channelId;
@@ -1592,9 +1602,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
&& scheduledRecording == null
&& mDvrManager.isProgramRecordable(program)) {
DvrUiHelper.requestRecordingFutureProgram(
- MainActivity.this,
- program,
- false);
+ MainActivity.this, program, false);
} else {
DvrUiHelper.showProgramInfoDialog(MainActivity.this, program);
}
@@ -1603,6 +1611,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
}
}
}
+
private void stopTv() {
stopTv(null, false);
}
@@ -1734,7 +1743,7 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
// For every tune, we need to inform the tuned channel or input to a user,
// if Talkback is turned on.
sendAccessibilityText(
- !mChannelTuner.isCurrentChannelPassthrough()
+ mChannelTuner.isCurrentChannelPassthrough()
? Utils.loadLabel(
this, mTvInputManagerHelper.getTvInputInfo(channel.getInputId()))
: channel.getDisplayText());
@@ -2826,7 +2835,8 @@ public class MainActivity extends Activity implements OnActionClickListener, OnP
if (channel == null) {
return;
}
- Channel currentChannel = mChannelDataManager.getChannel(ContentUris.parseId(channel));
+ Channel currentChannel =
+ mChannelDataManager.getChannel(ContentUriUtils.safeParseId(channel));
if (currentChannel == null) {
Log.e(
TAG,
diff --git a/src/com/android/tv/MainActivityWrapper.java b/src/com/android/tv/MainActivityWrapper.java
index 6a995cf1..6cecb436 100644
--- a/src/com/android/tv/MainActivityWrapper.java
+++ b/src/com/android/tv/MainActivityWrapper.java
@@ -20,7 +20,7 @@ import android.support.annotation.MainThread;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.ArraySet;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import java.util.Set;
/**
diff --git a/src/com/android/tv/MediaSessionWrapper.java b/src/com/android/tv/MediaSessionWrapper.java
index b3472ba5..43cd74dd 100644
--- a/src/com/android/tv/MediaSessionWrapper.java
+++ b/src/com/android/tv/MediaSessionWrapper.java
@@ -31,10 +31,10 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.VisibleForTesting;
import android.text.TextUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageLoader;
/**
* A wrapper class for {@link MediaSession} to support common operations on media sessions for
diff --git a/src/com/android/tv/SelectInputActivity.java b/src/com/android/tv/SelectInputActivity.java
index 4487fbe2..56747044 100644
--- a/src/com/android/tv/SelectInputActivity.java
+++ b/src/com/android/tv/SelectInputActivity.java
@@ -23,7 +23,7 @@ import android.media.tv.TvInputInfo;
import android.net.Uri;
import android.os.Bundle;
import android.view.KeyEvent;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.ui.SelectInputView;
import com.android.tv.ui.SelectInputView.OnInputSelectedCallback;
import com.android.tv.util.Utils;
@@ -67,7 +67,8 @@ public class SelectInputActivity extends Activity {
if (channelUriString != null) {
Uri channelUri = Uri.parse(channelUriString);
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
- mSelectInputView.setCurrentChannel(Channel.createPassthroughChannel(channelUri));
+ mSelectInputView.setCurrentChannel(
+ ChannelImpl.createPassthroughChannel(channelUri));
}
// No need to set the tuner channel because it's the default selection.
}
diff --git a/src/com/android/tv/SetupPassthroughActivity.java b/src/com/android/tv/SetupPassthroughActivity.java
index 83885df4..199ea51d 100644
--- a/src/com/android/tv/SetupPassthroughActivity.java
+++ b/src/com/android/tv/SetupPassthroughActivity.java
@@ -26,8 +26,8 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.MainThread;
import android.util.Log;
-import com.android.tv.common.CommonConstants;
import com.android.tv.common.SoftPreconditions;
+import com.android.tv.common.actions.InputSetupActionUtils;
import com.android.tv.common.experiments.Experiments;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ChannelDataManager.Listener;
@@ -64,11 +64,10 @@ public class SetupPassthroughActivity extends Activity {
TvSingletons tvSingletons = TvSingletons.getSingletons(this);
TvInputManagerHelper inputManager = tvSingletons.getTvInputManagerHelper();
Intent intent = getIntent();
- String inputId = intent.getStringExtra(CommonConstants.EXTRA_INPUT_ID);
+ String inputId = intent.getStringExtra(InputSetupActionUtils.EXTRA_INPUT_ID);
mTvInputInfo = inputManager.getTvInputInfo(inputId);
mEpgInputWhiteList = new EpgInputWhiteList(tvSingletons.getRemoteConfig());
- mActivityAfterCompletion =
- intent.getParcelableExtra(CommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION);
+ mActivityAfterCompletion = InputSetupActionUtils.getExtraActivityAfter(intent);
boolean needToFetchEpg =
mTvInputInfo != null
&& Utils.isInternalTvInput(this, mTvInputInfo.getId())
@@ -79,7 +78,7 @@ public class SetupPassthroughActivity extends Activity {
}
if (savedInstanceState == null) {
SoftPreconditions.checkArgument(
- CommonConstants.INTENT_ACTION_INPUT_SETUP.equals(intent.getAction()),
+ InputSetupActionUtils.hasInputSetupAction(intent),
TAG,
"Unsupported action %s",
intent.getAction());
@@ -94,8 +93,7 @@ public class SetupPassthroughActivity extends Activity {
finish();
return;
}
- Intent setupIntent =
- intent.getExtras().getParcelable(CommonConstants.EXTRA_SETUP_INTENT);
+ Intent setupIntent = InputSetupActionUtils.getExtraSetupIntent(intent);
if (DEBUG) Log.d(TAG, "Setup activity launch intent: " + setupIntent);
if (setupIntent == null) {
Log.w(TAG, "The input (" + mTvInputInfo.getId() + ") doesn't have setup.");
@@ -107,7 +105,7 @@ public class SetupPassthroughActivity extends Activity {
// If EXTRA_SETUP_INTENT is not removed, an infinite recursion happens during
// setupIntent.putExtras(intent.getExtras()).
Bundle extras = intent.getExtras();
- extras.remove(CommonConstants.EXTRA_SETUP_INTENT);
+ InputSetupActionUtils.removeSetupIntent(extras);
setupIntent.putExtras(extras);
try {
startActivityForResult(setupIntent, REQUEST_START_SETUP_ACTIVITY);
diff --git a/src/com/android/tv/TimeShiftManager.java b/src/com/android/tv/TimeShiftManager.java
index a72dd8c7..bb3574d7 100644
--- a/src/com/android/tv/TimeShiftManager.java
+++ b/src/com/android/tv/TimeShiftManager.java
@@ -30,12 +30,12 @@ import android.util.Range;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.ui.TunableTvView;
-import com.android.tv.ui.TunableTvView.TimeShiftListener;
+import com.android.tv.ui.TunableTvViewPlayingApi.TimeShiftListener;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.TimeShiftUtils;
import com.android.tv.util.Utils;
@@ -449,7 +449,7 @@ public class TimeShiftManager {
SoftPreconditions.checkState(isAvailable(), TAG, "Time shift is not available");
SoftPreconditions.checkState(mCurrentPositionMediator.mCurrentPositionMs != INVALID_TIME);
Program currentProgram = getProgramAt(mCurrentPositionMediator.mCurrentPositionMs);
- if (!Program.isValid(currentProgram)) {
+ if (!Program.isProgramValid(currentProgram)) {
currentProgram = null;
}
if (!Objects.equals(mCurrentProgram, currentProgram)) {
diff --git a/src/com/android/tv/TvFeatures.java b/src/com/android/tv/TvFeatures.java
index f8125814..d2cf76e7 100644
--- a/src/com/android/tv/TvFeatures.java
+++ b/src/com/android/tv/TvFeatures.java
@@ -49,7 +49,8 @@ public final class TvFeatures extends CommonFeatures {
/** When enabled use system setting for turning on analytics. */
public static final Feature ANALYTICS_OPT_IN =
ExperimentFeature.from(Experiments.ENABLE_ANALYTICS_VIA_CHECKBOX);
-
+ /** When enabled shows a list of failed recordings */
+ public static final Feature DVR_FAILED_LIST = ENG_ONLY_FEATURE;
/**
* Analytics that include sensitive information such as channel or program identifiers.
*
diff --git a/src/com/android/tv/analytics/SendChannelStatusRunnable.java b/src/com/android/tv/analytics/SendChannelStatusRunnable.java
index 601e82f7..4a84434c 100644
--- a/src/com/android/tv/analytics/SendChannelStatusRunnable.java
+++ b/src/com/android/tv/analytics/SendChannelStatusRunnable.java
@@ -20,8 +20,8 @@ import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.MainThread;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.RecurringRunner;
import java.util.List;
import java.util.concurrent.TimeUnit;
diff --git a/src/com/android/tv/analytics/StubTracker.java b/src/com/android/tv/analytics/StubTracker.java
index 4a926d58..e11b91c2 100644
--- a/src/com/android/tv/analytics/StubTracker.java
+++ b/src/com/android/tv/analytics/StubTracker.java
@@ -18,7 +18,7 @@ package com.android.tv.analytics;
import android.support.annotation.VisibleForTesting;
import com.android.tv.TimeShiftManager;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
/** A implementation of Tracker that does nothing. */
@VisibleForTesting
diff --git a/src/com/android/tv/analytics/Tracker.java b/src/com/android/tv/analytics/Tracker.java
index 8c72e3b4..0fcef5dc 100644
--- a/src/com/android/tv/analytics/Tracker.java
+++ b/src/com/android/tv/analytics/Tracker.java
@@ -17,7 +17,7 @@
package com.android.tv.analytics;
import com.android.tv.TimeShiftManager;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
/** Interface for sending user activity for analysis. */
public interface Tracker {
diff --git a/src/com/android/tv/app/LiveTvApplication.java b/src/com/android/tv/app/LiveTvApplication.java
index f6ac2441..461331d5 100644
--- a/src/com/android/tv/app/LiveTvApplication.java
+++ b/src/com/android/tv/app/LiveTvApplication.java
@@ -25,6 +25,7 @@ import com.android.tv.analytics.Analytics;
import com.android.tv.analytics.StubAnalytics;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.CommonConstants;
+import com.android.tv.common.actions.InputSetupActionUtils;
import com.android.tv.common.config.DefaultConfigManager;
import com.android.tv.common.config.api.RemoteConfig;
import com.android.tv.common.experiments.ExperimentLoader;
@@ -110,10 +111,10 @@ public class LiveTvApplication extends TvApplication {
Intent intent =
CommonUtils.createSetupIntent(
new Intent(context, LiveTvTunerSetupActivity.class), mEmbeddedInputId);
- intent.putExtra(CommonConstants.EXTRA_INPUT_ID, mEmbeddedInputId);
+ intent.putExtra(InputSetupActionUtils.EXTRA_INPUT_ID, mEmbeddedInputId);
Intent tvActivityIntent = new Intent();
tvActivityIntent.setComponent(new ComponentName(context, TV_ACTIVITY_CLASS_NAME));
- intent.putExtra(CommonConstants.EXTRA_ACTIVITY_AFTER_COMPLETION, tvActivityIntent);
+ intent.putExtra(InputSetupActionUtils.EXTRA_ACTIVITY_AFTER_COMPLETION, tvActivityIntent);
return intent;
}
diff --git a/src/com/android/tv/data/ChannelDataManager.java b/src/com/android/tv/data/ChannelDataManager.java
index 90e7d60a..1dfcf125 100644
--- a/src/com/android/tv/data/ChannelDataManager.java
+++ b/src/com/android/tv/data/ChannelDataManager.java
@@ -43,6 +43,7 @@ import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.util.PermissionUtils;
import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -82,7 +83,7 @@ public class ChannelDataManager {
// Use container class to support multi-thread safety. This value can be set only on the main
// thread.
private volatile UnmodifiableChannelData mData = new UnmodifiableChannelData();
- private final Channel.DefaultComparator mChannelComparator;
+ private final ChannelImpl.DefaultComparator mChannelComparator;
private final Handler mHandler;
private final Set<Long> mBrowsableUpdateChannelIds = new HashSet<>();
@@ -162,7 +163,7 @@ public class ChannelDataManager {
mInputManager = inputManager;
mDbExecutor = executor;
mContentResolver = contentResolver;
- mChannelComparator = new Channel.DefaultComparator(context, inputManager);
+ mChannelComparator = new ChannelImpl.DefaultComparator(context, inputManager);
// Detect duplicate channels while sorting.
mChannelComparator.setDetectDuplicatesEnabled(true);
mHandler = new ChannelDataManagerHandler(this);
diff --git a/src/com/android/tv/data/Channel.java b/src/com/android/tv/data/ChannelImpl.java
index 1204a49f..703f69c9 100644
--- a/src/com/android/tv/data/Channel.java
+++ b/src/com/android/tv/data/ChannelImpl.java
@@ -30,9 +30,10 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.CommonConstants;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageLoader;
import java.net.URISyntaxException;
import java.util.Comparator;
import java.util.HashMap;
@@ -40,13 +41,8 @@ import java.util.Map;
import java.util.Objects;
/** A convenience class to create and insert channel entries into the database. */
-public final class Channel {
- private static final String TAG = "Channel";
-
- public static final long INVALID_ID = -1;
- public static final int LOAD_IMAGE_TYPE_CHANNEL_LOGO = 1;
- public static final int LOAD_IMAGE_TYPE_APP_LINK_ICON = 2;
- public static final int LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART = 3;
+public final class ChannelImpl implements Channel {
+ private static final String TAG = "ChannelImpl";
/** Compares the channel numbers of channels which belong to the same input. */
public static final Comparator<Channel> CHANNEL_NUMBER_COMPARATOR =
@@ -57,27 +53,11 @@ public final class Channel {
}
};
- /**
- * When a TIS doesn't provide any information about app link, and it doesn't have a leanback
- * launch intent, there will be no app link card for the TIS.
- */
- public static final int APP_LINK_TYPE_NONE = -1;
- /**
- * When a TIS provide a specific app link information, the app link card will be {@code
- * APP_LINK_TYPE_CHANNEL} which contains all the provided information.
- */
- public static final int APP_LINK_TYPE_CHANNEL = 1;
- /**
- * When a TIS doesn't provide a specific app link information, but the app has a leanback launch
- * intent, the app link card will be {@code APP_LINK_TYPE_APP} which launches the application.
- */
- public static final int APP_LINK_TYPE_APP = 2;
-
private static final int APP_LINK_TYPE_NOT_SET = 0;
private static final String INVALID_PACKAGE_NAME = "packageName";
public static final String[] PROJECTION = {
- // Columns must match what is read in Channel.fromCursor()
+ // Columns must match what is read in ChannelImpl.fromCursor()
TvContract.Channels._ID,
TvContract.Channels.COLUMN_PACKAGE_NAME,
TvContract.Channels.COLUMN_INPUT_ID,
@@ -97,17 +77,14 @@ public final class Channel {
TvContract.Channels.COLUMN_INTERNAL_PROVIDER_FLAG2, // Only used in bundled input
};
- /** Channel number delimiter between major and minor parts. */
- public static final char CHANNEL_NUMBER_DELIMITER = '-';
-
/**
- * Creates {@code Channel} object from cursor.
+ * Creates {@code ChannelImpl} object from cursor.
*
* <p>The query that created the cursor MUST use {@link #PROJECTION}
*/
- public static Channel fromCursor(Cursor cursor) {
+ public static ChannelImpl fromCursor(Cursor cursor) {
// Columns read must match the order of {@link #PROJECTION}
- Channel channel = new Channel();
+ ChannelImpl channel = new ChannelImpl();
int index = 0;
channel.mId = cursor.getLong(index++);
channel.mPackageName = Utils.intern(cursor.getString(index++));
@@ -175,14 +152,16 @@ public final class Channel {
private boolean mChannelLogoExist;
- private Channel() {
+ private ChannelImpl() {
// Do nothing.
}
+ @Override
public long getId() {
return mId;
}
+ @Override
public Uri getUri() {
if (isPassthrough()) {
return TvContract.buildChannelUriForPassthroughInput(mInputId);
@@ -191,35 +170,43 @@ public final class Channel {
}
}
+ @Override
public String getPackageName() {
return mPackageName;
}
+ @Override
public String getInputId() {
return mInputId;
}
+ @Override
public String getType() {
return mType;
}
+ @Override
public String getDisplayNumber() {
return mDisplayNumber;
}
+ @Override
@Nullable
public String getDisplayName() {
return mDisplayName;
}
+ @Override
public String getDescription() {
return mDescription;
}
+ @Override
public String getVideoFormat() {
return mVideoFormat;
}
+ @Override
public boolean isPassthrough() {
return mIsPassthrough;
}
@@ -228,42 +215,51 @@ public final class Channel {
* Gets identification text for displaying or debugging. It's made from Channels' display number
* plus their display name.
*/
+ @Override
public String getDisplayText() {
return TextUtils.isEmpty(mDisplayName)
? mDisplayNumber
: mDisplayNumber + " " + mDisplayName;
}
+ @Override
public String getAppLinkText() {
return mAppLinkText;
}
+ @Override
public int getAppLinkColor() {
return mAppLinkColor;
}
+ @Override
public String getAppLinkIconUri() {
return mAppLinkIconUri;
}
+ @Override
public String getAppLinkPosterArtUri() {
return mAppLinkPosterArtUri;
}
+ @Override
public String getAppLinkIntentUri() {
return mAppLinkIntentUri;
}
/** Returns channel logo uri which is got from cloud, it's used only for ChannelLogoFetcher. */
+ @Override
public String getLogoUri() {
return mLogoUri;
}
+ @Override
public boolean isRecordingProhibited() {
return mRecordingProhibited;
}
/** Checks whether this channel is physical tuner channel or not. */
+ @Override
public boolean isPhysicalTunerChannel() {
return !TextUtils.isEmpty(mType) && !TvContract.Channels.TYPE_OTHER.equals(mType);
}
@@ -271,10 +267,10 @@ public final class Channel {
/** Checks if two channels equal by checking ids. */
@Override
public boolean equals(Object o) {
- if (!(o instanceof Channel)) {
+ if (!(o instanceof ChannelImpl)) {
return false;
}
- Channel other = (Channel) o;
+ ChannelImpl other = (ChannelImpl) o;
// All pass-through TV channels have INVALID_ID value for mId.
return mId == other.mId
&& TextUtils.equals(mInputId, other.mInputId)
@@ -286,15 +282,18 @@ public final class Channel {
return Objects.hash(mId, mInputId, mIsPassthrough);
}
+ @Override
public boolean isBrowsable() {
return mBrowsable;
}
/** Checks whether this channel is searchable or not. */
+ @Override
public boolean isSearchable() {
return mSearchable;
}
+ @Override
public boolean isLocked() {
return mLocked;
}
@@ -317,23 +316,24 @@ public final class Channel {
* channels have same logos. It also excludes browsable and locked, because two fields are
* changed by TV app.
*/
+ @Override
public boolean hasSameReadOnlyInfo(Channel other) {
return other != null
- && Objects.equals(mId, other.mId)
- && Objects.equals(mPackageName, other.mPackageName)
- && Objects.equals(mInputId, other.mInputId)
- && Objects.equals(mType, other.mType)
- && Objects.equals(mDisplayNumber, other.mDisplayNumber)
- && Objects.equals(mDisplayName, other.mDisplayName)
- && Objects.equals(mDescription, other.mDescription)
- && Objects.equals(mVideoFormat, other.mVideoFormat)
- && mIsPassthrough == other.mIsPassthrough
- && Objects.equals(mAppLinkText, other.mAppLinkText)
- && mAppLinkColor == other.mAppLinkColor
- && Objects.equals(mAppLinkIconUri, other.mAppLinkIconUri)
- && Objects.equals(mAppLinkPosterArtUri, other.mAppLinkPosterArtUri)
- && Objects.equals(mAppLinkIntentUri, other.mAppLinkIntentUri)
- && Objects.equals(mRecordingProhibited, other.mRecordingProhibited);
+ && Objects.equals(mId, other.getId())
+ && Objects.equals(mPackageName, other.getPackageName())
+ && Objects.equals(mInputId, other.getInputId())
+ && Objects.equals(mType, other.getType())
+ && Objects.equals(mDisplayNumber, other.getDisplayNumber())
+ && Objects.equals(mDisplayName, other.getDisplayName())
+ && Objects.equals(mDescription, other.getDescription())
+ && Objects.equals(mVideoFormat, other.getVideoFormat())
+ && mIsPassthrough == other.isPassthrough()
+ && Objects.equals(mAppLinkText, other.getAppLinkText())
+ && mAppLinkColor == other.getAppLinkColor()
+ && Objects.equals(mAppLinkIconUri, other.getAppLinkIconUri())
+ && Objects.equals(mAppLinkPosterArtUri, other.getAppLinkPosterArtUri())
+ && Objects.equals(mAppLinkIntentUri, other.getAppLinkIntentUri())
+ && Objects.equals(mRecordingProhibited, other.isRecordingProhibited());
}
@Override
@@ -370,7 +370,37 @@ public final class Channel {
+ "}";
}
- void copyFrom(Channel other) {
+ @Override
+ public void copyFrom(Channel channel) {
+ if (channel instanceof ChannelImpl) {
+ copyFrom((ChannelImpl) channel);
+ } else {
+ // copy what we can
+ mId = channel.getId();
+ mPackageName = channel.getPackageName();
+ mInputId = channel.getInputId();
+ mType = channel.getType();
+ mDisplayNumber = channel.getDisplayNumber();
+ mDisplayName = channel.getDisplayName();
+ mDescription = channel.getDescription();
+ mVideoFormat = channel.getVideoFormat();
+ mIsPassthrough = channel.isPassthrough();
+ mBrowsable = channel.isBrowsable();
+ mSearchable = channel.isSearchable();
+ mLocked = channel.isLocked();
+ mAppLinkText = channel.getAppLinkText();
+ mAppLinkColor = channel.getAppLinkColor();
+ mAppLinkIconUri = channel.getAppLinkIconUri();
+ mAppLinkPosterArtUri = channel.getAppLinkPosterArtUri();
+ mAppLinkIntentUri = channel.getAppLinkIntentUri();
+ mRecordingProhibited = channel.isRecordingProhibited();
+ mChannelLogoExist = channel.channelLogoExists();
+ }
+ }
+
+ @SuppressWarnings("ReferenceEquality")
+ public void copyFrom(ChannelImpl channel) {
+ ChannelImpl other = (ChannelImpl) channel;
if (this == other) {
return;
}
@@ -398,7 +428,7 @@ public final class Channel {
}
/** Creates a channel for a passthrough TV input. */
- public static Channel createPassthroughChannel(Uri uri) {
+ public static ChannelImpl createPassthroughChannel(Uri uri) {
if (!TvContract.isChannelUriForPassthroughInput(uri)) {
throw new IllegalArgumentException("URI is not a passthrough channel URI");
}
@@ -407,24 +437,24 @@ public final class Channel {
}
/** Creates a channel for a passthrough TV input with {@code inputId}. */
- public static Channel createPassthroughChannel(String inputId) {
+ public static ChannelImpl createPassthroughChannel(String inputId) {
return new Builder().setInputId(inputId).setPassthrough(true).build();
}
/** Checks whether the channel is valid or not. */
public static boolean isValid(Channel channel) {
- return channel != null && (channel.mId != INVALID_ID || channel.mIsPassthrough);
+ return channel != null && (channel.getId() != INVALID_ID || channel.isPassthrough());
}
/**
- * Builder class for {@code Channel}. Suppress using this outside of ChannelDataManager so
+ * Builder class for {@code ChannelImpl}. Suppress using this outside of ChannelDataManager so
* Channels could be managed by ChannelDataManager.
*/
public static final class Builder {
- private final Channel mChannel;
+ private final ChannelImpl mChannel;
public Builder() {
- mChannel = new Channel();
+ mChannel = new ChannelImpl();
// Fill initial data.
mChannel.mId = INVALID_ID;
mChannel.mPackageName = INVALID_PACKAGE_NAME;
@@ -438,7 +468,7 @@ public final class Channel {
}
public Builder(Channel other) {
- mChannel = new Channel();
+ mChannel = new ChannelImpl();
mChannel.copyFrom(other);
}
@@ -539,8 +569,8 @@ public final class Channel {
return this;
}
- public Channel build() {
- Channel channel = new Channel();
+ public ChannelImpl build() {
+ ChannelImpl channel = new ChannelImpl();
channel.copyFrom(mChannel);
return channel;
}
@@ -562,8 +592,8 @@ public final class Channel {
*
* @param context A context.
* @param type The type of bitmap which will be loaded. It should be one of follows: {@link
- * #LOAD_IMAGE_TYPE_CHANNEL_LOGO}, {@link #LOAD_IMAGE_TYPE_APP_LINK_ICON}, or {@link
- * #LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART}.
+ * Channel#LOAD_IMAGE_TYPE_CHANNEL_LOGO}, {@link Channel#LOAD_IMAGE_TYPE_APP_LINK_ICON}, or
+ * {@link Channel#LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART}.
* @param maxWidth The max width of the loaded bitmap.
* @param maxHeight The max height of the loaded bitmap.
* @param callback A callback which will be called after the loading finished.
@@ -583,7 +613,8 @@ public final class Channel {
* Sets if the channel logo exists. This method should be only called from {@link
* ChannelDataManager}.
*/
- void setChannelLogoExist(boolean exist) {
+ @Override
+ public void setChannelLogoExist(boolean exist) {
mChannelLogoExist = exist;
}
@@ -593,10 +624,11 @@ public final class Channel {
}
/**
- * Returns the type of app link for this channel. It returns {@link #APP_LINK_TYPE_CHANNEL} if
- * the channel has a non null app link text and a valid app link intent, it returns {@link
- * #APP_LINK_TYPE_APP} if the input service which holds the channel has leanback launch intent,
- * and it returns {@link #APP_LINK_TYPE_NONE} otherwise.
+ * Returns the type of app link for this channel. It returns {@link
+ * Channel#APP_LINK_TYPE_CHANNEL} if the channel has a non null app link text and a valid app
+ * link intent, it returns {@link Channel#APP_LINK_TYPE_APP} if the input service which holds
+ * the channel has leanback launch intent, and it returns {@link Channel#APP_LINK_TYPE_NONE}
+ * otherwise.
*/
public int getAppLinkType(Context context) {
if (mAppLinkType == APP_LINK_TYPE_NOT_SET) {
@@ -607,7 +639,7 @@ public final class Channel {
/**
* Returns the app link intent for this channel. If the type of app link is {@link
- * #APP_LINK_TYPE_NONE}, it returns {@code null}.
+ * Channel#APP_LINK_TYPE_NONE}, it returns {@code null}.
*/
public Intent getAppLinkIntent(Context context) {
if (mAppLinkType == APP_LINK_TYPE_NOT_SET) {
@@ -660,6 +692,17 @@ public final class Channel {
return null;
}
+ /**
+ * Default Channel ordering.
+ *
+ * <p>Ordering
+ * <li>{@link TvInputManagerHelper#isPartnerInput(String)}
+ * <li>{@link #getInputLabelForChannel(Channel)}
+ * <li>{@link #getInputId()}
+ * <li>{@link ChannelNumber#compare(String, String)}
+ * <li>
+ * </ol>
+ */
public static class DefaultComparator implements Comparator<Channel> {
private final Context mContext;
private final TvInputManagerHelper mInputManager;
@@ -675,6 +718,7 @@ public final class Channel {
mDetectDuplicatesEnabled = detectDuplicatesEnabled;
}
+ @SuppressWarnings("ReferenceEquality")
@Override
public int compare(Channel lhs, Channel rhs) {
if (lhs == rhs) {
diff --git a/src/com/android/tv/data/ChannelLogoFetcher.java b/src/com/android/tv/data/ChannelLogoFetcher.java
index bda78693..89d1e36c 100644
--- a/src/com/android/tv/data/ChannelLogoFetcher.java
+++ b/src/com/android/tv/data/ChannelLogoFetcher.java
@@ -30,8 +30,9 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.tv.common.util.PermissionUtils;
import com.android.tv.common.util.SharedPreferencesUtils;
-import com.android.tv.util.BitmapUtils;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.data.api.Channel;
+import com.android.tv.util.images.BitmapUtils;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
diff --git a/src/com/android/tv/data/ChannelNumber.java b/src/com/android/tv/data/ChannelNumber.java
index 1623b33d..afdcc580 100644
--- a/src/com/android/tv/data/ChannelNumber.java
+++ b/src/com/android/tv/data/ChannelNumber.java
@@ -20,6 +20,7 @@ import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.view.KeyEvent;
import com.android.tv.common.util.StringUtils;
+import com.android.tv.data.api.Channel;
import java.util.Objects;
/** A convenience class to handle channel number. */
@@ -120,8 +121,8 @@ public final class ChannelNumber implements Comparable<ChannelNumber> {
* Returns the ChannelNumber instance.
*
* <p>Note that all the channel number argument should be normalized by {@link
- * Channel#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager} are
- * already normalized.
+ * ChannelImpl#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager}
+ * are already normalized.
*/
public static ChannelNumber parseChannelNumber(String number) {
if (number == null) {
@@ -151,8 +152,8 @@ public final class ChannelNumber implements Comparable<ChannelNumber> {
* Compares the channel numbers.
*
* <p>Note that all the channel number arguments should be normalized by {@link
- * Channel#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager} are
- * already normalized.
+ * ChannelImpl#normalizeDisplayNumber}. The channels retrieved from {@link ChannelDataManager}
+ * are already normalized.
*/
public static int compare(String lhs, String rhs) {
ChannelNumber lhsNumber = parseChannelNumber(lhs);
diff --git a/src/com/android/tv/data/PreviewProgramContent.java b/src/com/android/tv/data/PreviewProgramContent.java
index 252092b0..b5156408 100644
--- a/src/com/android/tv/data/PreviewProgramContent.java
+++ b/src/com/android/tv/data/PreviewProgramContent.java
@@ -23,6 +23,7 @@ import android.support.media.tv.TvContractCompat;
import android.text.TextUtils;
import android.util.Pair;
import com.android.tv.TvSingletons;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.RecordedProgram;
import java.util.Objects;
@@ -104,6 +105,7 @@ public class PreviewProgramContent {
private PreviewProgramContent() {}
+ @SuppressWarnings("ReferenceEquality")
public void copyFrom(PreviewProgramContent other) {
if (this == other) {
return;
diff --git a/src/com/android/tv/data/Program.java b/src/com/android/tv/data/Program.java
index 30a3033e..2c64cdbb 100644
--- a/src/com/android/tv/data/Program.java
+++ b/src/com/android/tv/data/Program.java
@@ -36,8 +36,9 @@ import com.android.tv.common.BuildConfig;
import com.android.tv.common.TvContentRatingCache;
import com.android.tv.common.util.CollectionUtils;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageLoader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
@@ -236,7 +237,7 @@ public final class Program extends BaseProgram implements Comparable<Program>, P
}
/** Returns {@code true} if the program is valid and {@code false} otherwise. */
- public static boolean isValid(Program program) {
+ public static boolean isProgramValid(Program program) {
return program != null && program.isValid();
}
diff --git a/src/com/android/tv/data/ProgramDataManager.java b/src/com/android/tv/data/ProgramDataManager.java
index 524d23e3..4631806c 100644
--- a/src/com/android/tv/data/ProgramDataManager.java
+++ b/src/com/android/tv/data/ProgramDataManager.java
@@ -34,11 +34,12 @@ import android.util.Log;
import android.util.LongSparseArray;
import android.util.LruCache;
import com.android.tv.TvSingletons;
-import com.android.tv.common.MemoryManageable;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.config.api.RemoteConfig;
import com.android.tv.common.config.api.RemoteConfigValue;
+import com.android.tv.common.memory.MemoryManageable;
import com.android.tv.common.util.Clock;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.AsyncDbTask;
import com.android.tv.util.MultiLongSparseArray;
import com.android.tv.util.Utils;
@@ -304,10 +305,11 @@ public class ProgramDataManager implements MemoryManageable {
}
/**
- * Returns the index of program that is played at the specified time.
- * If there isn't, return the first program among programs that starts after the given time
- * if returnNextProgram is {@code true}.
- */
+ * Returns the index of program that is played at the specified time.
+ *
+ * <p>If there isn't, return the first program among programs that starts after the given time
+ * if returnNextProgram is {@code true}.
+ */
private int getProgramIndexAt(List<Program> programs, long time) {
Program key = mZeroLengthProgramCache.get(time);
if (key == null) {
@@ -391,7 +393,7 @@ public class ProgramDataManager implements MemoryManageable {
private void removePreviousProgramsAndUpdateCurrentProgramInCache(
long channelId, Program currentProgram) {
SoftPreconditions.checkState(mPrefetchEnabled, TAG, "Prefetch is disabled.");
- if (!Program.isValid(currentProgram)) {
+ if (!Program.isProgramValid(currentProgram)) {
return;
}
ArrayList<Program> cachedPrograms = mChannelIdProgramCache.remove(channelId);
diff --git a/src/com/android/tv/data/StreamInfo.java b/src/com/android/tv/data/StreamInfo.java
index 1f84235d..e4237bf4 100644
--- a/src/com/android/tv/data/StreamInfo.java
+++ b/src/com/android/tv/data/StreamInfo.java
@@ -17,6 +17,7 @@
package com.android.tv.data;
import android.media.tv.TvContentRating;
+import com.android.tv.data.api.Channel;
public interface StreamInfo {
int VIDEO_DEFINITION_LEVEL_UNKNOWN = 0;
diff --git a/src/com/android/tv/data/WatchedHistoryManager.java b/src/com/android/tv/data/WatchedHistoryManager.java
index 7dc48a75..7187efd1 100644
--- a/src/com/android/tv/data/WatchedHistoryManager.java
+++ b/src/com/android/tv/data/WatchedHistoryManager.java
@@ -28,6 +28,7 @@ import android.support.annotation.VisibleForTesting;
import android.support.annotation.WorkerThread;
import android.util.Log;
import com.android.tv.common.util.SharedPreferencesUtils;
+import com.android.tv.data.api.Channel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
diff --git a/src/com/android/tv/data/api/Channel.java b/src/com/android/tv/data/api/Channel.java
new file mode 100644
index 00000000..496331cf
--- /dev/null
+++ b/src/com/android/tv/data/api/Channel.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.tv.data.api;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.annotation.Nullable;
+import com.android.tv.util.images.ImageLoader.ImageLoaderCallback;
+
+/**
+ * Interface for {@link com.android.tv.data.ChannelImpl}.
+ *
+ * <p><b>NOTE</b> Normally you should not use an interface for a data object like {@code
+ * ChannelImpl}, however there are many circular dependencies. An interface is the easiest way to
+ * break the cycles.
+ */
+public interface Channel {
+
+ long INVALID_ID = -1;
+ int LOAD_IMAGE_TYPE_CHANNEL_LOGO = 1;
+ int LOAD_IMAGE_TYPE_APP_LINK_ICON = 2;
+ int LOAD_IMAGE_TYPE_APP_LINK_POSTER_ART = 3;
+ /**
+ * When a TIS doesn't provide any information about app link, and it doesn't have a leanback
+ * launch intent, there will be no app link card for the TIS.
+ */
+ int APP_LINK_TYPE_NONE = -1;
+ /**
+ * When a TIS provide a specific app link information, the app link card will be {@code
+ * APP_LINK_TYPE_CHANNEL} which contains all the provided information.
+ */
+ int APP_LINK_TYPE_CHANNEL = 1;
+ /**
+ * When a TIS doesn't provide a specific app link information, but the app has a leanback launch
+ * intent, the app link card will be {@code APP_LINK_TYPE_APP} which launches the application.
+ */
+ int APP_LINK_TYPE_APP = 2;
+ /** Channel number delimiter between major and minor parts. */
+ char CHANNEL_NUMBER_DELIMITER = '-';
+
+ long getId();
+
+ Uri getUri();
+
+ String getPackageName();
+
+ String getInputId();
+
+ String getType();
+
+ String getDisplayNumber();
+
+ @Nullable
+ String getDisplayName();
+
+ String getDescription();
+
+ String getVideoFormat();
+
+ boolean isPassthrough();
+
+ String getDisplayText();
+
+ String getAppLinkText();
+
+ int getAppLinkColor();
+
+ String getAppLinkIconUri();
+
+ String getAppLinkPosterArtUri();
+
+ String getAppLinkIntentUri();
+
+ String getLogoUri();
+
+ boolean isRecordingProhibited();
+
+ boolean isPhysicalTunerChannel();
+
+ boolean isBrowsable();
+
+ boolean isSearchable();
+
+ boolean isLocked();
+
+ boolean hasSameReadOnlyInfo(Channel mCurrentChannel);
+
+ void setChannelLogoExist(boolean result);
+
+ void setBrowsable(boolean browsable);
+
+ void setLocked(boolean locked);
+
+ void copyFrom(Channel channel);
+
+ void setLogoUri(String logoUri);
+
+ boolean channelLogoExists();
+
+ void loadBitmap(
+ Context context,
+ int loadImageTypeChannelLogo,
+ int mChannelLogoImageViewWidth,
+ int mChannelLogoImageViewHeight,
+ ImageLoaderCallback<?> channelLogoCallback);
+
+ int getAppLinkType(Context context);
+
+ Intent getAppLinkIntent(Context context);
+
+ void prefetchImage(
+ Context mContext,
+ int loadImageTypeChannelLogo,
+ int mPosterArtWidth,
+ int mPosterArtHeight);
+}
diff --git a/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java b/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java
index 90d109d7..795ad5c4 100644
--- a/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java
+++ b/src/com/android/tv/data/epg/AutoValue_EpgReader_EpgChannel.java
@@ -16,7 +16,7 @@
package com.android.tv.data.epg;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
/**
* Hand copy of generated Autovalue class.
diff --git a/src/com/android/tv/data/epg/EpgFetcherImpl.java b/src/com/android/tv/data/epg/EpgFetcherImpl.java
index 3660486f..2aaaa5b2 100644
--- a/src/com/android/tv/data/epg/EpgFetcherImpl.java
+++ b/src/com/android/tv/data/epg/EpgFetcherImpl.java
@@ -49,11 +49,12 @@ import com.android.tv.common.util.LocationUtils;
import com.android.tv.common.util.NetworkTrafficTags;
import com.android.tv.common.util.PermissionUtils;
import com.android.tv.common.util.PostalCodeUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.ChannelLogoFetcher;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.perf.EventNames;
import com.android.tv.perf.PerformanceMonitor;
import com.android.tv.perf.TimerEvent;
@@ -180,13 +181,13 @@ public class EpgFetcherImpl implements EpgFetcher {
context.getContentResolver()
.query(
TvContract.Channels.CONTENT_URI,
- Channel.PROJECTION,
+ ChannelImpl.PROJECTION,
selection,
selectionArgs,
null)) {
if (c != null) {
while (c.moveToNext()) {
- Channel channel = Channel.fromCursor(c);
+ Channel channel = ChannelImpl.fromCursor(c);
if (DEBUG) Log.d(TAG, "Found " + channel);
if (myPackageName.equals(channel.getPackageName())) {
channels.add(channel);
@@ -543,12 +544,12 @@ public class EpgFetcherImpl implements EpgFetcher {
mContext.getContentResolver()
.query(
TvContract.buildChannelsUriForInput(inputId),
- Channel.PROJECTION,
+ ChannelImpl.PROJECTION,
null,
null,
null)) {
while (cursor.moveToNext()) {
- result.add(Channel.fromCursor(cursor));
+ result.add(ChannelImpl.fromCursor(cursor));
}
return result;
}
diff --git a/src/com/android/tv/data/epg/EpgReader.java b/src/com/android/tv/data/epg/EpgReader.java
index 3cc70aa1..7147905a 100644
--- a/src/com/android/tv/data/epg/EpgReader.java
+++ b/src/com/android/tv/data/epg/EpgReader.java
@@ -19,9 +19,9 @@ package com.android.tv.data.epg;
import android.support.annotation.AnyThread;
import android.support.annotation.NonNull;
import android.support.annotation.WorkerThread;
-import com.android.tv.data.Channel;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.SeriesInfo;
import java.util.Collection;
import java.util.List;
@@ -32,7 +32,7 @@ import java.util.Set;
@WorkerThread
public interface EpgReader {
- /** Value class that holds a EpgChannelId and its corresponding Channel */
+ /** Value class that holds a EpgChannelId and its corresponding {@link Channel} */
// TODO(b/72052568): Get autovalue to work in aosp master
abstract class EpgChannel {
public static EpgChannel createEpgChannel(Channel channel, String epgChannelId) {
diff --git a/src/com/android/tv/data/epg/StubEpgReader.java b/src/com/android/tv/data/epg/StubEpgReader.java
index 9a87619d..3b001481 100644
--- a/src/com/android/tv/data/epg/StubEpgReader.java
+++ b/src/com/android/tv/data/epg/StubEpgReader.java
@@ -18,9 +18,9 @@ package com.android.tv.data.epg;
import android.content.Context;
import android.support.annotation.NonNull;
-import com.android.tv.data.Channel;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.SeriesInfo;
import java.util.Collection;
import java.util.Collections;
diff --git a/src/com/android/tv/dialog/DvrHistoryDialogFragment.java b/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
index 173a2891..7e36591f 100644
--- a/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
+++ b/src/com/android/tv/dialog/DvrHistoryDialogFragment.java
@@ -32,8 +32,8 @@ import android.widget.ListView;
import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.data.ScheduledRecording.RecordingState;
diff --git a/src/com/android/tv/dialog/RecentlyWatchedDialogFragment.java b/src/com/android/tv/dialog/RecentlyWatchedDialogFragment.java
index 84fddbe3..eb6940fb 100644
--- a/src/com/android/tv/dialog/RecentlyWatchedDialogFragment.java
+++ b/src/com/android/tv/dialog/RecentlyWatchedDialogFragment.java
@@ -31,8 +31,8 @@ import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
/** Displays the watch history */
public class RecentlyWatchedDialogFragment extends SafeDismissDialogFragment
diff --git a/src/com/android/tv/dvr/BaseDvrDataManager.java b/src/com/android/tv/dvr/BaseDvrDataManager.java
index 0befba9c..e890481b 100644
--- a/src/com/android/tv/dvr/BaseDvrDataManager.java
+++ b/src/com/android/tv/dvr/BaseDvrDataManager.java
@@ -245,6 +245,11 @@ public abstract class BaseDvrDataManager implements WritableDvrDataManager {
}
@Override
+ public List<ScheduledRecording> getFailedScheduledRecordings() {
+ return getRecordingsWithState(ScheduledRecording.STATE_RECORDING_FAILED);
+ }
+
+ @Override
public void changeState(ScheduledRecording scheduledRecording, @RecordingState int newState) {
if (scheduledRecording.getState() != newState) {
updateScheduledRecording(
diff --git a/src/com/android/tv/dvr/DvrDataManager.java b/src/com/android/tv/dvr/DvrDataManager.java
index 4ec0acfc..10dfc4c9 100644
--- a/src/com/android/tv/dvr/DvrDataManager.java
+++ b/src/com/android/tv/dvr/DvrDataManager.java
@@ -65,6 +65,9 @@ public interface DvrDataManager {
/** Returns scheduled but not started recordings that have not expired. */
List<ScheduledRecording> getNonStartedScheduledRecordings();
+ /** Returns failed recordings. */
+ List<ScheduledRecording> getFailedScheduledRecordings();
+
/** Returns series recordings. */
List<SeriesRecording> getSeriesRecordings();
diff --git a/src/com/android/tv/dvr/DvrDataManagerImpl.java b/src/com/android/tv/dvr/DvrDataManagerImpl.java
index dbb5a9f6..c74aa208 100644
--- a/src/com/android/tv/dvr/DvrDataManagerImpl.java
+++ b/src/com/android/tv/dvr/DvrDataManagerImpl.java
@@ -228,7 +228,6 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
protected void onPostExecute(List<ScheduledRecording> result) {
mPendingTasks.remove(this);
long maxId = 0;
- List<SeriesRecording> seriesRecordingsToAdd = new ArrayList<>();
List<ScheduledRecording> toUpdate = new ArrayList<>();
List<ScheduledRecording> toDelete = new ArrayList<>();
for (ScheduledRecording r : result) {
@@ -273,6 +272,7 @@ public class DvrDataManagerImpl extends BaseDvrDataManager {
case ScheduledRecording.STATE_RECORDING_CANCELED:
toDelete.add(r);
break;
+ default: // fall out
}
}
if (maxId < r.getId()) {
diff --git a/src/com/android/tv/dvr/DvrManager.java b/src/com/android/tv/dvr/DvrManager.java
index 14a17f2f..63a245a3 100644
--- a/src/com/android/tv/dvr/DvrManager.java
+++ b/src/com/android/tv/dvr/DvrManager.java
@@ -40,8 +40,8 @@ import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager.OnRecordedProgramLoadFinishedListener;
import com.android.tv.dvr.DvrDataManager.RecordedProgramListener;
import com.android.tv.dvr.DvrScheduleManager.OnInitializeListener;
diff --git a/src/com/android/tv/dvr/DvrScheduleManager.java b/src/com/android/tv/dvr/DvrScheduleManager.java
index cbb89290..d5126b12 100644
--- a/src/com/android/tv/dvr/DvrScheduleManager.java
+++ b/src/com/android/tv/dvr/DvrScheduleManager.java
@@ -27,9 +27,9 @@ import android.util.ArraySet;
import android.util.Range;
import com.android.tv.TvSingletons;
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.data.api.Channel;
import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -509,13 +509,13 @@ public class DvrScheduleManager {
public List<ScheduledRecording> getConflictingSchedules(Program program) {
SoftPreconditions.checkState(mInitialized, TAG, "Not initialized yet");
SoftPreconditions.checkState(
- Program.isValid(program), TAG, "Program is invalid: " + program);
+ Program.isProgramValid(program), TAG, "Program is invalid: " + program);
SoftPreconditions.checkState(
program.getStartTimeUtcMillis() < program.getEndTimeUtcMillis(),
TAG,
"Program duration is empty: " + program);
if (!mInitialized
- || !Program.isValid(program)
+ || !Program.isProgramValid(program)
|| program.getStartTimeUtcMillis() >= program.getEndTimeUtcMillis()) {
return Collections.emptyList();
}
diff --git a/src/com/android/tv/dvr/data/ScheduledRecording.java b/src/com/android/tv/dvr/data/ScheduledRecording.java
index aa1dfc72..bc569d96 100644
--- a/src/com/android/tv/dvr/data/ScheduledRecording.java
+++ b/src/com/android/tv/dvr/data/ScheduledRecording.java
@@ -30,8 +30,8 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.provider.DvrContract.Schedules;
import com.android.tv.util.CompositeComparator;
@@ -838,6 +838,11 @@ public final class ScheduledRecording implements Parcelable {
return mState == STATE_RECORDING_IN_PROGRESS;
}
+ /** Returns {@code true} if the recording is finished, otherwise @{code false}. */
+ public boolean isFinished() {
+ return mState == STATE_RECORDING_FINISHED;
+ }
+
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ScheduledRecording)) {
diff --git a/src/com/android/tv/dvr/recorder/ConflictChecker.java b/src/com/android/tv/dvr/recorder/ConflictChecker.java
index f5bc7b9f..bfd315e9 100644
--- a/src/com/android/tv/dvr/recorder/ConflictChecker.java
+++ b/src/com/android/tv/dvr/recorder/ConflictChecker.java
@@ -32,8 +32,8 @@ import com.android.tv.InputSessionManager.OnTvViewChannelChangeListener;
import com.android.tv.MainActivity;
import com.android.tv.TvSingletons;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager.ScheduledRecordingListener;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.data.ScheduledRecording;
diff --git a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
index 722e75fc..0f1ea3b0 100644
--- a/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
+++ b/src/com/android/tv/dvr/recorder/InputTaskScheduler.java
@@ -27,8 +27,8 @@ import android.util.Log;
import android.util.LongSparseArray;
import com.android.tv.InputSessionManager;
import com.android.tv.common.util.Clock;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.WritableDvrDataManager;
diff --git a/src/com/android/tv/dvr/recorder/RecordingTask.java b/src/com/android/tv/dvr/recorder/RecordingTask.java
index b337e244..ff37f3f0 100644
--- a/src/com/android/tv/dvr/recorder/RecordingTask.java
+++ b/src/com/android/tv/dvr/recorder/RecordingTask.java
@@ -37,7 +37,7 @@ import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.Clock;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
diff --git a/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java b/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
index f30308f3..dd106e1c 100644
--- a/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
+++ b/src/com/android/tv/dvr/recorder/ScheduledProgramReaper.java
@@ -17,7 +17,6 @@
package com.android.tv.dvr.recorder;
import android.support.annotation.MainThread;
-import android.support.annotation.VisibleForTesting;
import com.android.tv.common.util.Clock;
import com.android.tv.dvr.WritableDvrDataManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -27,9 +26,9 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
/** Deletes {@link ScheduledRecording} older than {@value @DAYS} days. */
-class ScheduledProgramReaper implements Runnable {
+public class ScheduledProgramReaper implements Runnable {
- @VisibleForTesting static final int DAYS = 2;
+ public static final int DAYS = 7;
private final WritableDvrDataManager mDvrDataManager;
private final Clock mClock;
diff --git a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
index 24a6fcd3..6be35cb2 100644
--- a/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrChannelRecordDurationOptionFragment.java
@@ -24,7 +24,7 @@ import android.support.v17.leanback.widget.GuidedAction;
import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.ui.DvrConflictFragment.DvrChannelRecordConflictFragment;
diff --git a/src/com/android/tv/dvr/ui/DvrConflictFragment.java b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
index 641f86c1..65759555 100644
--- a/src/com/android/tv/dvr/ui/DvrConflictFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrConflictFragment.java
@@ -31,8 +31,8 @@ import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.recorder.ConflictChecker;
import com.android.tv.dvr.recorder.ConflictChecker.OnUpcomingConflictChangeListener;
diff --git a/src/com/android/tv/dvr/ui/DvrFutureProgramInfoFragment.java b/src/com/android/tv/dvr/ui/DvrFutureProgramInfoFragment.java
index a51e583a..677a6cbb 100644
--- a/src/com/android/tv/dvr/ui/DvrFutureProgramInfoFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrFutureProgramInfoFragment.java
@@ -37,7 +37,7 @@ public class DvrFutureProgramInfoFragment extends DvrGuidedStepFragment {
@Override
public GuidanceStylist.Guidance onCreateGuidance(Bundle savedInstanceState) {
long startTime = mProgram.getStartTimeUtcMillis();
- // TODO(b/71717923): use R.string whe the strings are finalized
+ // TODO(b/71717923): use R.string when the strings are finalized
StringBuilder description = new StringBuilder()
.append("This program will start at ")
.append(Utils.getDurationString(getContext(), startTime, startTime, false));
diff --git a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
index 9383058a..37efa5ba 100644
--- a/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
+++ b/src/com/android/tv/dvr/ui/DvrSeriesSettingsFragment.java
@@ -28,9 +28,10 @@ import android.support.v17.leanback.widget.GuidedActionsStylist;
import android.util.LongSparseArray;
import com.android.tv.R;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
@@ -50,7 +51,6 @@ import java.util.Set;
public class DvrSeriesSettingsFragment 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;
@@ -127,7 +127,7 @@ public class DvrSeriesSettingsFragment extends GuidedStepFragment
mChannelOption = SeriesRecording.OPTION_CHANNEL_ALL;
}
}
- mChannels.sort(Channel.CHANNEL_NUMBER_COMPARATOR);
+ mChannels.sort(ChannelImpl.CHANNEL_NUMBER_COMPARATOR);
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);
diff --git a/src/com/android/tv/dvr/ui/DvrUiHelper.java b/src/com/android/tv/dvr/ui/DvrUiHelper.java
index 6977649f..e5786895 100644
--- a/src/com/android/tv/dvr/ui/DvrUiHelper.java
+++ b/src/com/android/tv/dvr/ui/DvrUiHelper.java
@@ -45,8 +45,8 @@ import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.recording.RecordingStorageStatusManager;
import com.android.tv.common.util.CommonUtils;
import com.android.tv.data.BaseProgram;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.RecordedProgram;
@@ -67,6 +67,7 @@ import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrSmallSizedStorageErro
import com.android.tv.dvr.ui.DvrHalfSizedDialogFragment.DvrStopRecordingDialogFragment;
import com.android.tv.dvr.ui.browse.DvrBrowseActivity;
import com.android.tv.dvr.ui.browse.DvrDetailsActivity;
+import com.android.tv.dvr.ui.list.DvrHistoryActivity;
import com.android.tv.dvr.ui.list.DvrSchedulesActivity;
import com.android.tv.dvr.ui.list.DvrSchedulesFragment;
import com.android.tv.dvr.ui.list.DvrSeriesSchedulesFragment;
@@ -245,9 +246,7 @@ public class DvrUiHelper {
return;
}
Bundle args = new Bundle();
- args.putParcelable(
- DvrHalfSizedDialogFragment.KEY_PROGRAM,
- program);
+ args.putParcelable(DvrHalfSizedDialogFragment.KEY_PROGRAM, program);
showDialogFragment(activity, new DvrFutureProgramInfoDialogFragment(), args, false, true);
}
@@ -421,6 +420,12 @@ public class DvrUiHelper {
}
/** Shows the schedules activity with full schedule. */
+ public static void startDvrHistoryActivity(Context context) {
+ Intent intent = new Intent(context, DvrHistoryActivity.class);
+ context.startActivity(intent);
+ }
+
+ /** Shows the schedules activity with full schedule. */
public static void startSchedulesActivity(
Context context, ScheduledRecording focusedScheduledRecording) {
Intent intent = new Intent(context, DvrSchedulesActivity.class);
diff --git a/src/com/android/tv/dvr/ui/browse/DetailsContent.java b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
index 70903373..56bbdb46 100644
--- a/src/com/android/tv/dvr/ui/browse/DetailsContent.java
+++ b/src/com/android/tv/dvr/ui/browse/DetailsContent.java
@@ -22,7 +22,7 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.R;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.data.SeriesRecording;
diff --git a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
index 90326a8b..6d66eea1 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrBrowseFragment.java
@@ -32,6 +32,7 @@ import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
import com.android.tv.R;
+import com.android.tv.TvFeatures;
import com.android.tv.TvSingletons;
import com.android.tv.data.GenreItems;
import com.android.tv.dvr.DvrDataManager;
@@ -185,6 +186,12 @@ public class DvrBrowseFragment extends BrowseFragment
.addClassPresenter(
FullScheduleCardHolder.class,
new FullSchedulesCardPresenter(context));
+
+ if (TvFeatures.DVR_FAILED_LIST.isEnabled(context)) {
+ mPresenterSelector.addClassPresenter(
+ DvrHistoryCardHolder.class,
+ new DvrHistoryCardPresenter(context));
+ }
mGenreLabels = new ArrayList<>(Arrays.asList(GenreItems.getLabels(context)));
mGenreLabels.add(getString(R.string.dvr_main_others));
prepareUiElements();
@@ -387,6 +394,9 @@ public class DvrBrowseFragment extends BrowseFragment
for (RecordedProgram recordedProgram : mDvrDataManager.getRecordedPrograms()) {
handleRecordedProgramAdded(recordedProgram, false);
}
+ if (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())) {
+ mRecentAdapter.addExtraItem(DvrHistoryCardHolder.DVR_HISTORY_CARD_HOLDER);
+ }
// Series Recordings. Series recordings should be added after recorded programs, because
// we build series recordings' latest program information while adding recorded
// programs.
@@ -576,7 +586,8 @@ public class DvrBrowseFragment extends BrowseFragment
private void updateRows() {
int visibleRowsCount = 1; // Schedule's Row will never be empty
- if (mRecentAdapter.isEmpty()) {
+ int recentRowMinSize = TvFeatures.DVR_FAILED_LIST.isEnabled(getContext()) ? 1 : 0;
+ if (mRecentAdapter.size() <= recentRowMinSize) {
mRowsAdapter.remove(mRecentRow);
} else {
if (mRowsAdapter.indexOf(mRecentRow) < 0) {
diff --git a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
index 209fc6e1..8f4e4dab 100644
--- a/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
+++ b/src/com/android/tv/dvr/ui/browse/DvrDetailsFragment.java
@@ -40,15 +40,15 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.dialog.PinDialogFragment.OnPinCheckedListener;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.dvr.ui.DvrUiHelper;
import com.android.tv.parental.ParentalControlSettings;
-import com.android.tv.util.ImageLoader;
import com.android.tv.util.ToastUtils;
+import com.android.tv.util.images.ImageLoader;
import java.io.File;
abstract class DvrDetailsFragment extends DetailsFragment {
diff --git a/src/com/android/tv/dvr/ui/browse/DvrHistoryCardHolder.java b/src/com/android/tv/dvr/ui/browse/DvrHistoryCardHolder.java
new file mode 100644
index 00000000..c6288ef0
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/browse/DvrHistoryCardHolder.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.ui.browse;
+
+/** Special object for schedule preview; */
+final class DvrHistoryCardHolder {
+ /** Full schedule card holder. */
+ static final DvrHistoryCardHolder DVR_HISTORY_CARD_HOLDER = new DvrHistoryCardHolder();
+
+ private DvrHistoryCardHolder() {}
+}
diff --git a/src/com/android/tv/dvr/ui/browse/DvrHistoryCardPresenter.java b/src/com/android/tv/dvr/ui/browse/DvrHistoryCardPresenter.java
new file mode 100644
index 00000000..62c050c9
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/browse/DvrHistoryCardPresenter.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tv.dvr.ui.browse;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.view.View;
+import com.android.tv.R;
+import com.android.tv.dvr.ui.DvrUiHelper;
+
+/** Presents a DVR history card view in the {@link DvrBrowseFragment}. */
+class DvrHistoryCardPresenter extends DvrItemPresenter<Object> {
+ private final Drawable mIconDrawable;
+ private final String mCardTitleText;
+
+ DvrHistoryCardPresenter(Context context) {
+ super(context);
+ mIconDrawable = mContext.getDrawable(R.drawable.dvr_full_schedule);
+ mCardTitleText = mContext.getString(R.string.dvr_history_card_view_title);
+ }
+
+ @Override
+ public DvrItemViewHolder onCreateDvrItemViewHolder() {
+ return new DvrItemViewHolder(new RecordingCardView(mContext));
+ }
+
+ @Override
+ public void onBindDvrItemViewHolder(DvrItemViewHolder vh, Object o) {
+ final RecordingCardView cardView = (RecordingCardView) vh.view;
+
+ cardView.setTitle(mCardTitleText);
+ cardView.setImage(mIconDrawable);
+ }
+
+ @Override
+ public void onUnbindViewHolder(ViewHolder vh) {
+ ((RecordingCardView) vh.view).reset();
+ super.onUnbindViewHolder(vh);
+ }
+
+ @Override
+ protected View.OnClickListener onCreateOnClickListener() {
+ return new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ DvrUiHelper.startDvrHistoryActivity(mContext);
+ }
+ };
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
index edee5d3a..fe3c52d9 100644
--- a/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
+++ b/src/com/android/tv/dvr/ui/browse/RecordingCardView.java
@@ -34,7 +34,7 @@ import android.widget.TextView;
import com.android.tv.R;
import com.android.tv.dvr.data.RecordedProgram;
import com.android.tv.ui.ViewUtils;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.util.images.ImageLoader;
/**
* A CardView for displaying info about a {@link com.android.tv.dvr.data.ScheduledRecording} or
diff --git a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
index 84298bdf..77a63508 100644
--- a/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
+++ b/src/com/android/tv/dvr/ui/list/BaseDvrSchedulesFragment.java
@@ -109,7 +109,8 @@ public abstract class BaseDvrSchedulesFragment extends DetailsFragment
public abstract ScheduleRowPresenter onCreateRowPresenter();
/** Creates rows adapter. */
- public abstract ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelecor);
+ public abstract ScheduleRowAdapter onCreateRowsAdapter(
+ ClassPresenterSelector presenterSelector);
/** Gets the first focus position in schedules list. */
protected int getFirstItemPosition() {
diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryActivity.java b/src/com/android/tv/dvr/ui/list/DvrHistoryActivity.java
new file mode 100644
index 00000000..623975e1
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrHistoryActivity.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.ui.list;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.tv.R;
+import com.android.tv.Starter;
+
+/** Activity to show the recording history. */
+public class DvrHistoryActivity extends Activity {
+
+ @Override
+ public void onCreate(final Bundle savedInstanceState) {
+ Starter.start(this);
+ // Pass null to prevent automatically re-creating fragments
+ super.onCreate(null);
+ setContentView(R.layout.activity_dvr_history);
+ DvrHistoryFragment dvrHistoryFragment = new DvrHistoryFragment();
+ getFragmentManager()
+ .beginTransaction()
+ .add(R.id.fragment_container, dvrHistoryFragment)
+ .commit();
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java
new file mode 100644
index 00000000..fbf0fe53
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrHistoryFragment.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.ui.list;
+
+import 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.R;
+import com.android.tv.TvSingletons;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRowPresenter.DateHeaderRowPresenter;
+
+/** A fragment to show the DVR history. */
+public class DvrHistoryFragment extends DetailsFragment {
+
+ private DvrHistoryRowAdapter mRowsAdapter;
+ private TextView mEmptyInfoScreenView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ ClassPresenterSelector presenterSelector = new ClassPresenterSelector();
+ presenterSelector.addClassPresenter(
+ SchedulesHeaderRow.class, new DateHeaderRowPresenter(getContext()));
+ presenterSelector.addClassPresenter(
+ ScheduleRow.class, new ScheduleRowPresenter(getContext()));
+ mRowsAdapter = new DvrHistoryRowAdapter(getContext(), presenterSelector);
+ setAdapter(mRowsAdapter);
+ mRowsAdapter.start();
+ TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ mEmptyInfoScreenView = (TextView) getActivity().findViewById(R.id.empty_info_screen);
+ // TODO: handle show/hide message
+ }
+
+ /** 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;
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java
new file mode 100644
index 00000000..7685b7e9
--- /dev/null
+++ b/src/com/android/tv/dvr/ui/list/DvrHistoryRowAdapter.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.dvr.ui.list;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Build.VERSION_CODES;
+import android.support.v17.leanback.widget.ArrayObjectAdapter;
+import android.support.v17.leanback.widget.ClassPresenterSelector;
+import android.text.format.DateUtils;
+import com.android.tv.R;
+import com.android.tv.TvSingletons;
+import com.android.tv.dvr.data.RecordedProgram;
+import com.android.tv.dvr.data.ScheduledRecording;
+import com.android.tv.dvr.recorder.ScheduledProgramReaper;
+import com.android.tv.dvr.ui.list.SchedulesHeaderRow.DateHeaderRow;
+import com.android.tv.util.Utils;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/** An adapter for DVR history. */
+@TargetApi(VERSION_CODES.N)
+@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
+class DvrHistoryRowAdapter extends ArrayObjectAdapter {
+ // TODO: handle row added/removed/updated
+
+ private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
+ private static final int MAX_HISTORY_DAYS = ScheduledProgramReaper.DAYS;
+
+ private Context mContext;
+ private final List<String> mTitles = new ArrayList<>();
+
+ public DvrHistoryRowAdapter(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_yesterday));
+ }
+
+ /** Returns context. */
+ protected Context getContext() {
+ return mContext;
+ }
+
+ /** Starts row adapter. */
+ public void start() {
+ clear();
+ List<ScheduledRecording> recordingList =
+ TvSingletons.getSingletons(mContext)
+ .getDvrDataManager()
+ .getFailedScheduledRecordings();
+ List<RecordedProgram> recordedProgramList =
+ TvSingletons.getSingletons(mContext)
+ .getDvrDataManager()
+ .getRecordedPrograms();
+
+ recordingList.addAll(
+ recordedProgramsToScheduledRecordings(recordedProgramList, MAX_HISTORY_DAYS));
+ recordingList
+ .sort(ScheduledRecording.START_TIME_THEN_PRIORITY_THEN_ID_COMPARATOR.reversed());
+ long deadLine = Utils.getFirstMillisecondOfDay(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;
+ }
+ }
+
+ private String calculateHeaderDate(long timeMs) {
+ int titleIndex =
+ (int)
+ ((Utils.getFirstMillisecondOfDay(System.currentTimeMillis()) - timeMs)
+ / ONE_DAY_MS);
+ String headerDate;
+ if (titleIndex < mTitles.size()) {
+ headerDate = mTitles.get(titleIndex);
+ } else {
+ headerDate =
+ DateUtils.formatDateTime(
+ getContext(),
+ timeMs,
+ DateUtils.FORMAT_SHOW_WEEKDAY
+ | DateUtils.FORMAT_SHOW_DATE
+ | DateUtils.FORMAT_ABBREV_MONTH);
+ }
+ return headerDate;
+ }
+
+ private List<ScheduledRecording> recordedProgramsToScheduledRecordings(
+ List<RecordedProgram> recordedPrograms, int maxDays) {
+ List<ScheduledRecording> result = new ArrayList<>(recordedPrograms.size());
+ long firstMillisecondToday = Utils.getFirstMillisecondOfDay(System.currentTimeMillis());
+ for (RecordedProgram recordedProgram : recordedPrograms) {
+ if (maxDays
+ < Utils.computeDateDifference(
+ recordedProgram.getStartTimeUtcMillis(),
+ firstMillisecondToday)) {
+ continue;
+ }
+ result.add(ScheduledRecording.builder(recordedProgram).build());
+ }
+ return result;
+ }
+}
diff --git a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java
index e5290601..d97b61f4 100644
--- a/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java
+++ b/src/com/android/tv/dvr/ui/list/DvrSchedulesFragment.java
@@ -43,8 +43,8 @@ public class DvrSchedulesFragment extends BaseDvrSchedulesFragment {
}
@Override
- public ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelecor) {
- return new ScheduleRowAdapter(getContext(), presenterSelecor);
+ public ScheduleRowAdapter onCreateRowsAdapter(ClassPresenterSelector presenterSelector) {
+ return new ScheduleRowAdapter(getContext(), presenterSelector);
}
@Override
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRow.java b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
index f54c4203..ce5f9516 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRow.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRow.java
@@ -110,6 +110,12 @@ class ScheduleRow {
&& mSchedule.getState() == ScheduledRecording.STATE_RECORDING_IN_PROGRESS;
}
+ /** Checks if the schedule is failed. */
+ public final boolean isRecordingFailed() {
+ return mSchedule != null
+ && mSchedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED;
+ }
+
/** Checks if the schedule has been canceled or not. */
public final boolean isScheduleCanceled() {
return mSchedule != null
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
index 1215c19a..bbccdb15 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowAdapter.java
@@ -16,7 +16,9 @@
package com.android.tv.dvr.ui.list;
+import android.annotation.TargetApi;
import android.content.Context;
+import android.os.Build.VERSION_CODES;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -26,6 +28,7 @@ import android.text.format.DateUtils;
import android.util.ArraySet;
import android.util.Log;
import com.android.tv.R;
+import com.android.tv.TvFeatures;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.dvr.DvrManager;
@@ -39,6 +42,8 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
/** An adapter for {@link ScheduleRow}. */
+@TargetApi(VERSION_CODES.N)
+@SuppressWarnings("AndroidApiChecker") // TODO(b/32513850) remove when error prone is updated
class ScheduleRowAdapter extends ArrayObjectAdapter {
private static final String TAG = "ScheduleRowAdapter";
private static final boolean DEBUG = false;
@@ -110,6 +115,33 @@ class ScheduleRowAdapter extends ArrayObjectAdapter {
}
deadLine += ONE_DAY_MS;
}
+ if (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())) {
+ List<ScheduledRecording> failedRecordingList =
+ TvSingletons.getSingletons(mContext)
+ .getDvrDataManager()
+ .getFailedScheduledRecordings();
+ Collections.sort(
+ failedRecordingList,
+ ScheduledRecording.START_TIME_COMPARATOR.reversed());
+ if (!failedRecordingList.isEmpty()) {
+ SchedulesHeaderRow headerRow =
+ // TODO(b/72638385): use R.string
+ // TODO(b/72638385): define another HeaderRow class
+ new DateHeaderRow(
+ "Failed recordings",
+ mContext.getResources()
+ .getQuantityString(
+ R.plurals.dvr_schedules_section_subtitle,
+ failedRecordingList.size(),
+ failedRecordingList.size()),
+ failedRecordingList.size(),
+ Long.MAX_VALUE);
+ add(headerRow);
+ for (ScheduledRecording recording : failedRecordingList) {
+ add(new ScheduleRow(recording, headerRow));
+ }
+ }
+ }
sendNextUpdateMessage(System.currentTimeMillis());
}
@@ -382,7 +414,9 @@ class ScheduleRowAdapter extends ArrayObjectAdapter {
Object item = get(i);
if (item instanceof ScheduleRow) {
ScheduleRow row = (ScheduleRow) item;
- if (row.getEndTimeMs() <= currentTimeMs) {
+ ScheduledRecording recording = row.getSchedule();
+ if (row.getEndTimeMs() <= currentTimeMs && (recording == null
+ || recording.getState() != ScheduledRecording.STATE_RECORDING_FAILED)) {
removeScheduleRow(row);
}
}
diff --git a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
index 5cab607a..48430956 100644
--- a/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
+++ b/src/com/android/tv/dvr/ui/list/ScheduleRowPresenter.java
@@ -18,7 +18,6 @@ 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;
@@ -38,9 +37,10 @@ import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.android.tv.R;
+import com.android.tv.TvFeatures;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.DvrScheduleManager;
@@ -268,19 +268,11 @@ class ScheduleRowPresenter extends RowPresenter {
.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();
- }
+ animation -> {
+ // Set width to the proper width for this animation step.
+ float fraction = 1f - animation.getAnimatedFraction();
+ lp.width = targetWidth + Math.round(deltaWidth * fraction);
+ mSelectorView.requestLayout();
})
.setDuration(animationDuration)
.setInterpolator(interpolator)
@@ -430,11 +422,22 @@ class ScheduleRowPresenter extends RowPresenter {
case 1:
viewHolder.mFirstActionView.setImageResource(getImageForAction(actions[0]));
break;
+ default: // fall out
}
}
- if (mDvrManager.isConflicting(row.getSchedule())) {
+ ScheduledRecording schedule = row.getSchedule();
+ if (mDvrManager.isConflicting(schedule)
+ || (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())
+ && schedule != null
+ && schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED)) {
String conflictInfo;
- if (mDvrScheduleManager.isPartiallyConflicting(row.getSchedule())) {
+ if (TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())
+ && schedule != null
+ && schedule.getState() == ScheduledRecording.STATE_RECORDING_FAILED) {
+ // TODO(b/72638385): show real error messages
+ // TODO(b/72638385): use a better name for ConflictInfoXXX
+ conflictInfo = "Failed";
+ } else if (mDvrScheduleManager.isPartiallyConflicting(row.getSchedule())) {
conflictInfo = mTunerConflictWillBePartiallyRecordedInfo;
} else {
conflictInfo = mTunerConflictWillNotBeRecordedInfo;
@@ -475,8 +478,13 @@ class ScheduleRowPresenter extends RowPresenter {
/** Returns time text for time view from scheduled recording. */
protected String onGetRecordingTimeText(ScheduleRow row) {
+ boolean showDate =
+ TvFeatures.DVR_FAILED_LIST.isEnabled(getContext())
+ && row.getSchedule() != null
+ && row.getSchedule().getState()
+ == ScheduledRecording.STATE_RECORDING_FAILED;
return Utils.getDurationString(
- mContext, row.getStartTimeMs(), row.getEndTimeMs(), true, false, true, 0);
+ mContext, row.getStartTimeMs(), row.getEndTimeMs(), true, showDate, true, 0);
}
/** Returns program info text for program title view. */
@@ -502,8 +510,10 @@ class ScheduleRowPresenter extends RowPresenter {
}
private boolean isInfoClickable(ScheduleRow row) {
- return row.getSchedule() != null
- && (row.getSchedule().isNotStarted() || row.getSchedule().isInProgress());
+ ScheduledRecording schedule = row.getSchedule();
+ // TODO: handle onClicked for finished schedules
+ return schedule != null
+ && (schedule.isNotStarted() || schedule.isInProgress() || schedule.isFinished());
}
/** Called when the button in a row is clicked. */
@@ -521,6 +531,7 @@ class ScheduleRowPresenter extends RowPresenter {
case ACTION_REMOVE_SCHEDULE:
onRemoveSchedule(row);
break;
+ default: // fall out
}
}
@@ -653,6 +664,9 @@ class ScheduleRowPresenter extends RowPresenter {
ScheduledRecording.buildFrom(row.getSchedule())
.setState(ScheduledRecording.STATE_RECORDING_CANCELED)
.build());
+ } else if (row.isRecordingFailed()) {
+ deletedInfo = getDeletedInfo(row);
+ mDvrManager.removeScheduledRecording(row.getSchedule());
}
}
if (deletedInfo != null) {
@@ -821,6 +835,10 @@ class ScheduleRowPresenter extends RowPresenter {
return new int[] {ACTION_REMOVE_SCHEDULE, ACTION_CREATE_SCHEDULE};
} else if (row.isRecordingNotStarted()) {
return new int[] {ACTION_REMOVE_SCHEDULE};
+ } else if (row.isRecordingFailed()) {
+ return new int[] {ACTION_REMOVE_SCHEDULE};
+ } else if (row.isRecordingFinished()) {
+ return new int[] {};
} else {
SoftPreconditions.checkState(
false,
diff --git a/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java b/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
index dd17b22d..bef036eb 100644
--- a/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
+++ b/src/com/android/tv/dvr/ui/playback/DvrPlaybackMediaSessionHelper.java
@@ -30,13 +30,13 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import com.android.tv.R;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.data.RecordedProgram;
-import com.android.tv.util.ImageLoader;
import com.android.tv.util.TimeShiftUtils;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageLoader;
class DvrPlaybackMediaSessionHelper {
private static final String TAG = "DvrPlaybackMediaSessionHelper";
diff --git a/src/com/android/tv/guide/ProgramItemView.java b/src/com/android/tv/guide/ProgramItemView.java
index 9daa9f2f..9f379e43 100644
--- a/src/com/android/tv/guide/ProgramItemView.java
+++ b/src/com/android/tv/guide/ProgramItemView.java
@@ -24,7 +24,6 @@ import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.graphics.drawable.StateListDrawable;
import android.os.Handler;
-import android.os.SystemClock;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
@@ -40,7 +39,10 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.data.Channel;
+import com.android.tv.common.util.Clock;
+import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.dvr.ui.DvrUiHelper;
@@ -70,8 +72,10 @@ public class ProgramItemView extends TextView {
private static TextAppearanceSpan sEpisodeTitleStyle;
private static TextAppearanceSpan sGrayedOutEpisodeTitleStyle;
+ private final DvrManager mDvrManager;
+ private final Clock mClock;
+ private final ChannelDataManager mChannelDataManager;
private ProgramGuide mProgramGuide;
- private DvrManager mDvrManager;
private TableEntry mTableEntry;
private int mMaxWidthForRipple;
private int mTextWidth;
@@ -86,6 +90,7 @@ public class ProgramItemView extends TextView {
@Override
public void onClick(final View view) {
TableEntry entry = ((ProgramItemView) view).mTableEntry;
+ Clock clock = ((ProgramItemView) view).mClock;
if (entry == null) {
// do nothing
return;
@@ -114,7 +119,7 @@ public class ProgramItemView extends TextView {
} else if (entry.program != null
&& CommonFeatures.DVR.isEnabled(view.getContext())) {
DvrManager dvrManager = singletons.getDvrManager();
- if (entry.entryStartUtcMillis > System.currentTimeMillis()
+ if (entry.entryStartUtcMillis > clock.currentTimeMillis()
&& dvrManager.isProgramRecordable(entry.program)) {
if (entry.scheduledRecording == null) {
DvrUiHelper.checkStorageStatusAndShowErrorMessage(
@@ -180,7 +185,8 @@ public class ProgramItemView extends TextView {
background.jumpToCurrentState();
}
int progress =
- getProgress(entry.entryStartUtcMillis, entry.entryEndUtcMillis);
+ getProgress(
+ mClock, entry.entryStartUtcMillis, entry.entryEndUtcMillis);
setProgress(background, R.id.reverse_progress, MAX_PROGRESS - progress);
}
if (getHandler() != null) {
@@ -188,8 +194,7 @@ public class ProgramItemView extends TextView {
.postAtTime(
this,
Utils.ceilTime(
- SystemClock.uptimeMillis(),
- FOCUS_UPDATE_FREQUENCY));
+ mClock.uptimeMillis(), FOCUS_UPDATE_FREQUENCY));
}
}
};
@@ -206,7 +211,10 @@ public class ProgramItemView extends TextView {
super(context, attrs, defStyle);
setOnClickListener(ON_CLICKED);
setOnFocusChangeListener(ON_FOCUS_CHANGED);
- mDvrManager = TvSingletons.getSingletons(getContext()).getDvrManager();
+ TvSingletons singletons = TvSingletons.getSingletons(getContext());
+ mDvrManager = singletons.getDvrManager();
+ mChannelDataManager = singletons.getChannelDataManager();
+ mClock = singletons.getClock();
}
private void initIfNeeded() {
@@ -266,7 +274,7 @@ public class ProgramItemView extends TextView {
@Override
protected int[] onCreateDrawableState(int extraSpace) {
if (mTableEntry != null) {
- int states[] =
+ int[] states =
super.onCreateDrawableState(
extraSpace + STATE_CURRENT_PROGRAM.length + STATE_TOO_WIDE.length);
if (mTableEntry.isCurrentProgram()) {
@@ -296,78 +304,154 @@ public class ProgramItemView extends TextView {
mTableEntry = entry;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
- layoutParams.width = entry.getWidth();
- setLayoutParams(layoutParams);
+ if (layoutParams != null) {
+ // There is no layoutParams in the tests so we skip this
+ layoutParams.width = entry.getWidth();
+ setLayoutParams(layoutParams);
+ }
+ String title = mTableEntry.program != null ? mTableEntry.program.getTitle() : null;
+ if (mTableEntry.isGap()) {
+ title = gapTitle;
+ }
+ if (TextUtils.isEmpty(title)) {
+ title = getResources().getString(R.string.program_title_for_no_information);
+ }
+ updateText(selectedGenreId, title);
+ updateIcons();
+ updateContentDescription(title);
+ measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ mTextWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
+ // Maximum width for us to use a ripple
+ mMaxWidthForRipple = GuideUtils.convertMillisToPixel(fromUtcMillis, toUtcMillis);
+ }
+
+ private boolean isEntryWideEnough() {
+ return mTableEntry != null && mTableEntry.getWidth() >= sVisibleThreshold;
+ }
+
+ private void updateText(int selectedGenreId, String title) {
+ if (!isEntryWideEnough()) {
+ setText(null);
+ return;
+ }
- String title = entry.program != null ? entry.program.getTitle() : null;
String episode =
- entry.program != null ? entry.program.getEpisodeDisplayTitle(getContext()) : null;
+ mTableEntry.program != null
+ ? mTableEntry.program.getEpisodeDisplayTitle(getContext())
+ : null;
TextAppearanceSpan titleStyle = sGrayedOutProgramTitleStyle;
TextAppearanceSpan episodeStyle = sGrayedOutEpisodeTitleStyle;
+ if (mTableEntry.isGap()) {
- if (entry.getWidth() < sVisibleThreshold) {
- setText(null);
+ episode = null;
+ } else if (mTableEntry.hasGenre(selectedGenreId)) {
+ titleStyle = sProgramTitleStyle;
+ episodeStyle = sEpisodeTitleStyle;
+ }
+ SpannableStringBuilder description = new SpannableStringBuilder();
+ description.append(title);
+ if (!TextUtils.isEmpty(episode)) {
+ description.append('\n');
+
+ // Add a 'zero-width joiner'/ZWJ in order to ensure we have the same line height for
+ // all lines. This is a non-printing character so it will not change the horizontal
+ // spacing however it will affect the line height. As we ensure the ZWJ has the same
+ // text style as the title it will make sure the line height is consistent.
+ description.append('\u200D');
+
+ int middle = description.length();
+ description.append(episode);
+
+ description.setSpan(titleStyle, 0, middle, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ description.setSpan(
+ episodeStyle, middle, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
- if (entry.isGap()) {
- title = gapTitle;
- episode = null;
- } else if (entry.hasGenre(selectedGenreId)) {
- titleStyle = sProgramTitleStyle;
- episodeStyle = sEpisodeTitleStyle;
+ description.setSpan(
+ titleStyle, 0, description.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ setText(description);
+ }
+
+ private void updateIcons() {
+ // Sets recording icons if needed.
+ int iconResId = 0;
+ if (isEntryWideEnough() && 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;
+ default:
+ // leave the iconResId=0
+ }
}
- if (TextUtils.isEmpty(title)) {
- title = getResources().getString(R.string.program_title_for_no_information);
+ }
+ setCompoundDrawablePadding(iconResId != 0 ? sCompoundDrawablePadding : 0);
+ setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, iconResId, 0);
+ }
+
+ private void updateContentDescription(String title) {
+ // The content description includes extra information that is displayed on the detail view
+ Resources resources = getResources();
+ String description = title;
+ // TODO(b/73282818): only say channel name when the row changes
+ Channel channel = mChannelDataManager.getChannel(mTableEntry.channelId);
+ if (channel != null) {
+ description = channel.getDisplayNumber() + " " + description;
+ }
+ description +=
+ " "
+ + Utils.getDurationString(
+ getContext(),
+ mClock,
+ mTableEntry.entryStartUtcMillis,
+ mTableEntry.entryEndUtcMillis,
+ true);
+ Program program = mTableEntry.program;
+ if (program != null) {
+ String episodeDescription = program.getEpisodeContentDescription(getContext());
+ if (!TextUtils.isEmpty(episodeDescription)) {
+ description += " " + episodeDescription;
}
- SpannableStringBuilder description = new SpannableStringBuilder();
- description.append(title);
- if (!TextUtils.isEmpty(episode)) {
- description.append('\n');
-
- // Add a 'zero-width joiner'/ZWJ in order to ensure we have the same line height for
- // all lines. This is a non-printing character so it will not change the horizontal
- // spacing however it will affect the line height. As we ensure the ZWJ has the same
- // text style as the title it will make sure the line height is consistent.
- description.append('\u200D');
-
- int middle = description.length();
- description.append(episode);
-
- description.setSpan(titleStyle, 0, middle, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- description.setSpan(
- episodeStyle,
- middle,
- description.length(),
- Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+ }
+ if (mTableEntry.scheduledRecording != null) {
+ if (mDvrManager.isConflicting(mTableEntry.scheduledRecording)) {
+ description +=
+ " " + resources.getString(R.string.dvr_epg_program_recording_conflict);
} else {
- description.setSpan(
- titleStyle, 0, description.length(), 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;
- }
+ switch (mTableEntry.scheduledRecording.getState()) {
+ case ScheduledRecording.STATE_RECORDING_NOT_STARTED:
+ description +=
+ " "
+ + resources.getString(
+ R.string.dvr_epg_program_recording_scheduled);
+ break;
+ case ScheduledRecording.STATE_RECORDING_IN_PROGRESS:
+ description +=
+ " "
+ + resources.getString(
+ R.string.dvr_epg_program_recording_in_progress);
+ break;
+ default:
+ // do nothing
}
}
- setCompoundDrawablePadding(iconResId != 0 ? sCompoundDrawablePadding : 0);
- setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, iconResId, 0);
}
- measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- mTextWidth = getMeasuredWidth() - getPaddingStart() - getPaddingEnd();
- // Maximum width for us to use a ripple
- mMaxWidthForRipple = GuideUtils.convertMillisToPixel(fromUtcMillis, toUtcMillis);
+ if (mTableEntry.isBlocked()) {
+ description += " " + resources.getString(R.string.program_guide_content_locked);
+ } else if (program != null) {
+ String programDescription = program.getDescription();
+ if (!TextUtils.isEmpty(programDescription)) {
+ description += " " + programDescription;
+ }
+ }
+ setContentDescription(description);
}
/** Update programItemView to handle alignments of text. */
@@ -423,8 +507,8 @@ public class ProgramItemView extends TextView {
mTableEntry = null;
}
- private static int getProgress(long start, long end) {
- long currentTime = System.currentTimeMillis();
+ private static int getProgress(Clock clock, long start, long end) {
+ long currentTime = clock.currentTimeMillis();
if (currentTime <= start) {
return 0;
} else if (currentTime >= end) {
diff --git a/src/com/android/tv/guide/ProgramListAdapter.java b/src/com/android/tv/guide/ProgramListAdapter.java
index d997db1e..397bacfb 100644
--- a/src/com/android/tv/guide/ProgramListAdapter.java
+++ b/src/com/android/tv/guide/ProgramListAdapter.java
@@ -23,7 +23,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.android.tv.R;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.guide.ProgramManager.TableEntriesUpdatedListener;
import com.android.tv.guide.ProgramManager.TableEntry;
diff --git a/src/com/android/tv/guide/ProgramManager.java b/src/com/android/tv/guide/ProgramManager.java
index 6d355c7a..3f20a837 100644
--- a/src/com/android/tv/guide/ProgramManager.java
+++ b/src/com/android/tv/guide/ProgramManager.java
@@ -18,13 +18,14 @@ package com.android.tv.guide;
import android.support.annotation.MainThread;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.util.ArraySet;
import android.util.Log;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrScheduleManager;
import com.android.tv.dvr.DvrScheduleManager.OnConflictStateChangeListener;
@@ -731,7 +732,7 @@ public class ProgramManager {
/** Returns true if this is a gap. */
boolean isGap() {
- return !Program.isValid(program);
+ return !Program.isProgramValid(program);
}
/** Returns true if this channel is blocked. */
@@ -772,6 +773,23 @@ public class ProgramManager {
}
}
+ @VisibleForTesting
+ public static TableEntry createTableEntryForTest(
+ long channelId,
+ Program program,
+ ScheduledRecording scheduledRecording,
+ long entryStartUtcMillis,
+ long entryEndUtcMillis,
+ boolean isBlocked) {
+ return new TableEntry(
+ channelId,
+ program,
+ scheduledRecording,
+ entryStartUtcMillis,
+ entryEndUtcMillis,
+ isBlocked);
+ }
+
interface Listener {
void onGenresUpdated();
diff --git a/src/com/android/tv/guide/ProgramRow.java b/src/com/android/tv/guide/ProgramRow.java
index 3765aa43..83175bb6 100644
--- a/src/com/android/tv/guide/ProgramRow.java
+++ b/src/com/android/tv/guide/ProgramRow.java
@@ -24,7 +24,7 @@ import android.util.Log;
import android.util.Range;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.guide.ProgramManager.TableEntry;
import com.android.tv.util.Utils;
import java.util.concurrent.TimeUnit;
diff --git a/src/com/android/tv/guide/ProgramTableAdapter.java b/src/com/android/tv/guide/ProgramTableAdapter.java
index 935f8b3a..6e7485ac 100644
--- a/src/com/android/tv/guide/ProgramTableAdapter.java
+++ b/src/com/android/tv/guide/ProgramTableAdapter.java
@@ -51,21 +51,21 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.feature.CommonFeatures;
import com.android.tv.common.util.CommonUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.Program.CriticScore;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.ScheduledRecording;
import com.android.tv.guide.ProgramManager.TableEntriesUpdatedListener;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.ui.HardwareLayerAnimatorListenerAdapter;
-import com.android.tv.util.ImageCache;
-import com.android.tv.util.ImageLoader;
-import com.android.tv.util.ImageLoader.ImageLoaderCallback;
-import com.android.tv.util.ImageLoader.LoadTvInputLogoTask;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageCache;
+import com.android.tv.util.images.ImageLoader;
+import com.android.tv.util.images.ImageLoader.ImageLoaderCallback;
+import com.android.tv.util.images.ImageLoader.LoadTvInputLogoTask;
import java.util.ArrayList;
import java.util.List;
@@ -316,7 +316,6 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
@Override
public void onAccessibilityStateChanged(boolean enable) {
enable &= !CommonUtils.isRunningInTest();
- mDetailView.setFocusable(enable);
mChannelHeaderView.setFocusable(enable);
}
};
@@ -370,7 +369,6 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
boolean accessibilityEnabled =
mAccessibilityManager.isEnabled() && !CommonUtils.isRunningInTest();
- mDetailView.setFocusable(accessibilityEnabled);
mChannelHeaderView.setFocusable(accessibilityEnabled);
}
@@ -471,7 +469,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
return;
}
- if (Program.isValid(mSelectedEntry.program)) {
+ if (Program.isProgramValid(mSelectedEntry.program)) {
Program program = mSelectedEntry.program;
if (getProgramBlock(program) == null) {
program.prefetchPosterArt(itemView.getContext(), mImageWidth, mImageHeight);
@@ -543,7 +541,7 @@ class ProgramTableAdapter extends RecyclerView.Adapter<ProgramTableAdapter.Progr
}
if (DEBUG) Log.d(TAG, "updateDetailView");
mCriticScoresLayout.removeAllViews();
- if (Program.isValid(mSelectedEntry.program)) {
+ if (Program.isProgramValid(mSelectedEntry.program)) {
mTitleView.setTextColor(mDetailTextColor);
Context context = itemView.getContext();
Program program = mSelectedEntry.program;
diff --git a/src/com/android/tv/menu/AppLinkCardView.java b/src/com/android/tv/menu/AppLinkCardView.java
index 3e60723f..fd93c314 100644
--- a/src/com/android/tv/menu/AppLinkCardView.java
+++ b/src/com/android/tv/menu/AppLinkCardView.java
@@ -35,10 +35,10 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
-import com.android.tv.util.BitmapUtils;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
+import com.android.tv.util.images.BitmapUtils;
+import com.android.tv.util.images.ImageLoader;
import java.util.Objects;
/** A view to render an app link card. */
@@ -141,7 +141,7 @@ public class AppLinkCardView extends BaseCardView<ChannelsRowItem> {
protected void onPostExecute(CharSequence appLabel) {
mTvInputManagerHelper.setTvInputApplicationLabel(
mLoadTvInputId, appLabel);
- if (mLoadTvInputId != mChannel.getInputId()
+ if (mLoadTvInputId.equals(mChannel.getInputId())
|| !isAttachedToWindow()) {
return;
}
@@ -339,7 +339,7 @@ public class AppLinkCardView extends BaseCardView<ChannelsRowItem> {
@Override
protected void onPostExecute(Drawable banner) {
- if (mLoadTvInputId != mChannel.getInputId() || !isAttachedToWindow()) {
+ if (mLoadTvInputId.equals(mChannel.getInputId()) || !isAttachedToWindow()) {
return;
}
if (banner != null) {
diff --git a/src/com/android/tv/menu/ChannelCardView.java b/src/com/android/tv/menu/ChannelCardView.java
index 31262b88..76056ee4 100644
--- a/src/com/android/tv/menu/ChannelCardView.java
+++ b/src/com/android/tv/menu/ChannelCardView.java
@@ -28,10 +28,10 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.parental.ParentalControlSettings;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.util.images.ImageLoader;
import java.util.Objects;
/** A view to render channel card. */
diff --git a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java
index 854bb5a8..9cecb9c0 100644
--- a/src/com/android/tv/menu/ChannelsPosterPrefetcher.java
+++ b/src/com/android/tv/menu/ChannelsPosterPrefetcher.java
@@ -26,9 +26,10 @@ import android.util.Log;
import com.android.tv.R;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
import java.util.List;
/** A poster image prefetcher to show the program poster art in the Channels row faster. */
@@ -94,7 +95,7 @@ public class ChannelsPosterPrefetcher {
return;
}
Channel channel = item.getChannel();
- if (!Channel.isValid(channel)) {
+ if (!ChannelImpl.isValid(channel)) {
continue;
}
channel.prefetchImage(
diff --git a/src/com/android/tv/menu/ChannelsRowAdapter.java b/src/com/android/tv/menu/ChannelsRowAdapter.java
index 2d86ec75..8536ef1f 100644
--- a/src/com/android/tv/menu/ChannelsRowAdapter.java
+++ b/src/com/android/tv/menu/ChannelsRowAdapter.java
@@ -24,7 +24,8 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.recommendation.Recommender;
import com.android.tv.util.TvInputManagerHelper;
@@ -168,7 +169,7 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels
}
if (needToShowAppLinkItem()) {
ChannelsRowItem.APP_LINK_ITEM.setChannel(
- new Channel.Builder(getMainActivity().getCurrentChannel()).build());
+ new ChannelImpl.Builder(getMainActivity().getCurrentChannel()).build());
items.add(ChannelsRowItem.APP_LINK_ITEM);
}
for (Channel channel : getRecentChannels()) {
@@ -193,7 +194,7 @@ public class ChannelsRowAdapter extends ItemListRowView.ItemListAdapter<Channels
.getCurrentChannel()
.hasSameReadOnlyInfo(ChannelsRowItem.APP_LINK_ITEM.getChannel())) {
ChannelsRowItem.APP_LINK_ITEM.setChannel(
- new Channel.Builder(getMainActivity().getCurrentChannel()).build());
+ new ChannelImpl.Builder(getMainActivity().getCurrentChannel()).build());
notifyItemChanged(currentIndex);
}
++currentIndex;
diff --git a/src/com/android/tv/menu/ChannelsRowItem.java b/src/com/android/tv/menu/ChannelsRowItem.java
index 25216920..608bb36e 100644
--- a/src/com/android/tv/menu/ChannelsRowItem.java
+++ b/src/com/android/tv/menu/ChannelsRowItem.java
@@ -18,7 +18,7 @@ package com.android.tv.menu;
import android.support.annotation.NonNull;
import com.android.tv.R;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
/** A class for the items in channels row. */
public class ChannelsRowItem {
diff --git a/src/com/android/tv/menu/MenuUpdater.java b/src/com/android/tv/menu/MenuUpdater.java
index 2d81b93a..5d277824 100644
--- a/src/com/android/tv/menu/MenuUpdater.java
+++ b/src/com/android/tv/menu/MenuUpdater.java
@@ -21,7 +21,7 @@ import com.android.tv.ChannelTuner;
import com.android.tv.TvOptionsManager;
import com.android.tv.TvOptionsManager.OptionChangedListener;
import com.android.tv.TvOptionsManager.OptionType;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.menu.MenuRowFactory.TvOptionsRow;
import com.android.tv.ui.TunableTvView;
import com.android.tv.ui.TunableTvView.OnScreenBlockingChangedListener;
diff --git a/src/com/android/tv/menu/PlayControlsRowView.java b/src/com/android/tv/menu/PlayControlsRowView.java
index 35f1d503..496d1969 100644
--- a/src/com/android/tv/menu/PlayControlsRowView.java
+++ b/src/com/android/tv/menu/PlayControlsRowView.java
@@ -31,8 +31,8 @@ import com.android.tv.TimeShiftManager.TimeShiftActionId;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.feature.CommonFeatures;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.HalfSizedDialogFragment;
import com.android.tv.dvr.DvrDataManager;
import com.android.tv.dvr.DvrDataManager.OnDvrScheduleLoadFinishedListener;
diff --git a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
index 5da802c4..410b8252 100644
--- a/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
+++ b/src/com/android/tv/recommendation/ChannelPreviewUpdater.java
@@ -30,10 +30,10 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.tv.Starter;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
import com.android.tv.data.PreviewDataManager;
import com.android.tv.data.PreviewProgramContent;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.util.Utils;
import java.util.ArrayList;
diff --git a/src/com/android/tv/recommendation/ChannelRecord.java b/src/com/android/tv/recommendation/ChannelRecord.java
index 34679452..c7a7cb37 100644
--- a/src/com/android/tv/recommendation/ChannelRecord.java
+++ b/src/com/android/tv/recommendation/ChannelRecord.java
@@ -20,9 +20,9 @@ import android.content.Context;
import android.support.annotation.GuardedBy;
import android.support.annotation.VisibleForTesting;
import com.android.tv.TvSingletons;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
import java.util.ArrayDeque;
import java.util.Deque;
diff --git a/src/com/android/tv/recommendation/NotificationService.java b/src/com/android/tv/recommendation/NotificationService.java
index 65da651f..f40a0862 100644
--- a/src/com/android/tv/recommendation/NotificationService.java
+++ b/src/com/android/tv/recommendation/NotificationService.java
@@ -46,13 +46,13 @@ import com.android.tv.Starter;
import com.android.tv.TvSingletons;
import com.android.tv.common.CommonConstants;
import com.android.tv.common.WeakHandler;
-import com.android.tv.data.Channel;
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.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.BitmapUtils;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.images.ImageLoader;
import java.util.ArrayList;
import java.util.List;
@@ -409,8 +409,7 @@ public class NotificationService extends Service
Channel.LOAD_IMAGE_TYPE_CHANNEL_LOGO,
mChannelLogoMaxWidth,
mChannelLogoMaxHeight,
- createChannelLogoCallback(
- this, notificationId, channel, program, posterArtBitmap));
+ createChannelLogoCallback(this, notificationId, channel, program, posterArtBitmap));
if (mNotificationChannels[notificationId] == Channel.INVALID_ID) {
++mCurrentNotificationCount;
@@ -481,11 +480,7 @@ public class NotificationService extends Service
@Override
public void onBitmapLoaded(NotificationService service, Bitmap channelLogo) {
service.sendNotification(
- notificationId,
- channelLogo,
- channel,
- posterArtBitmap,
- program);
+ notificationId, channelLogo, channel, posterArtBitmap, program);
}
};
}
diff --git a/src/com/android/tv/recommendation/RecommendationDataManager.java b/src/com/android/tv/recommendation/RecommendationDataManager.java
index 08825a9a..649920fb 100644
--- a/src/com/android/tv/recommendation/RecommendationDataManager.java
+++ b/src/com/android/tv/recommendation/RecommendationDataManager.java
@@ -36,10 +36,10 @@ import android.support.annotation.WorkerThread;
import com.android.tv.TvSingletons;
import com.android.tv.common.WeakHandler;
import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.Program;
import com.android.tv.data.WatchedHistoryManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvUriMatcher;
import java.util.ArrayList;
import java.util.Collection;
diff --git a/src/com/android/tv/recommendation/Recommender.java b/src/com/android/tv/recommendation/Recommender.java
index 7542286f..f350799f 100644
--- a/src/com/android/tv/recommendation/Recommender.java
+++ b/src/com/android/tv/recommendation/Recommender.java
@@ -20,7 +20,7 @@ import android.content.Context;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.Pair;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
diff --git a/src/com/android/tv/search/DataManagerSearch.java b/src/com/android/tv/search/DataManagerSearch.java
index e17c4c86..82fb5016 100644
--- a/src/com/android/tv/search/DataManagerSearch.java
+++ b/src/com/android/tv/search/DataManagerSearch.java
@@ -27,10 +27,10 @@ import android.support.annotation.MainThread;
import android.text.TextUtils;
import android.util.Log;
import com.android.tv.TvSingletons;
-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.data.api.Channel;
import com.android.tv.search.LocalSearchProvider.SearchResult;
import com.android.tv.util.MainThreadExecutor;
import com.android.tv.util.Utils;
diff --git a/src/com/android/tv/search/ProgramGuideSearchFragment.java b/src/com/android/tv/search/ProgramGuideSearchFragment.java
index 3d8050c6..cb26252b 100644
--- a/src/com/android/tv/search/ProgramGuideSearchFragment.java
+++ b/src/com/android/tv/search/ProgramGuideSearchFragment.java
@@ -41,7 +41,7 @@ import android.view.ViewGroup;
import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.util.ImageLoader;
+import com.android.tv.util.images.ImageLoader;
import java.util.List;
public class ProgramGuideSearchFragment extends SearchFragment {
@@ -136,8 +136,9 @@ public class ProgramGuideSearchFragment extends SearchFragment {
LocalSearchProvider.SearchResult result = (LocalSearchProvider.SearchResult) o;
mMainActivity.getFragmentManager().popBackStack();
mMainActivity.tuneToChannel(
- mMainActivity.getChannelDataManager().getChannel(
- result.getChannelId()));
+ mMainActivity
+ .getChannelDataManager()
+ .getChannel(result.getChannelId()));
}
};
diff --git a/src/com/android/tv/setup/SystemSetupActivity.java b/src/com/android/tv/setup/SystemSetupActivity.java
index 3fefc0c8..c6b10e52 100644
--- a/src/com/android/tv/setup/SystemSetupActivity.java
+++ b/src/com/android/tv/setup/SystemSetupActivity.java
@@ -27,6 +27,7 @@ import android.widget.Toast;
import com.android.tv.R;
import com.android.tv.SetupPassthroughActivity;
import com.android.tv.TvSingletons;
+import com.android.tv.common.CommonConstants;
import com.android.tv.common.ui.setup.SetupActivity;
import com.android.tv.common.ui.setup.SetupMultiPaneFragment;
import com.android.tv.common.util.CommonUtils;
@@ -37,7 +38,8 @@ 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 String SYSTEM_SETUP =
+ CommonConstants.BASE_PACKAGE + ".action.LAUNCH_SYSTEM_SETUP";
private static final int SHOW_RIPPLE_DURATION_MS = 266;
private static final int REQUEST_CODE_START_SETUP_ACTIVITY = 1;
diff --git a/src/com/android/tv/ui/ChannelBannerView.java b/src/com/android/tv/ui/ChannelBannerView.java
index df487bb5..c3b8173f 100644
--- a/src/com/android/tv/ui/ChannelBannerView.java
+++ b/src/com/android/tv/ui/ChannelBannerView.java
@@ -50,17 +50,17 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
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.data.StreamInfo;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.DvrManager;
import com.android.tv.dvr.data.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;
-import com.android.tv.util.ImageLoader.LoadTvInputLogoTask;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageCache;
+import com.android.tv.util.images.ImageLoader;
+import com.android.tv.util.images.ImageLoader.ImageLoaderCallback;
+import com.android.tv.util.images.ImageLoader.LoadTvInputLogoTask;
/** A view to render channel banner. */
public class ChannelBannerView extends FrameLayout implements TvTransitionManager.TransitionLayout {
@@ -500,7 +500,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
return new ImageLoaderCallback<ChannelBannerView>(channelBannerView) {
@Override
public void onBitmapLoaded(ChannelBannerView view, @Nullable Bitmap logo) {
- if (channel != view.mCurrentChannel) {
+ if (channel.equals(view.mCurrentChannel)) {
// The logo is obsolete.
return;
}
@@ -579,7 +579,7 @@ public class ChannelBannerView extends FrameLayout implements TvTransitionManage
return;
}
updateProgramTextView(
- program == mLockedChannelProgram,
+ program.equals(mLockedChannelProgram),
program.getTitle(),
program.getEpisodeDisplayTitle(getContext()));
}
diff --git a/src/com/android/tv/ui/InputBannerView.java b/src/com/android/tv/ui/InputBannerView.java
index 17bfcab7..5ac715bf 100644
--- a/src/com/android/tv/ui/InputBannerView.java
+++ b/src/com/android/tv/ui/InputBannerView.java
@@ -25,7 +25,7 @@ import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
public class InputBannerView extends LinearLayout implements TvTransitionManager.TransitionLayout {
private final long mShowDurationMillis;
diff --git a/src/com/android/tv/ui/KeypadChannelSwitchView.java b/src/com/android/tv/ui/KeypadChannelSwitchView.java
index 5919dbf1..e2625811 100644
--- a/src/com/android/tv/ui/KeypadChannelSwitchView.java
+++ b/src/com/android/tv/ui/KeypadChannelSwitchView.java
@@ -41,8 +41,8 @@ import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.DurationTimer;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelNumber;
+import com.android.tv.data.api.Channel;
import java.util.ArrayList;
import java.util.List;
diff --git a/src/com/android/tv/ui/SelectInputView.java b/src/com/android/tv/ui/SelectInputView.java
index 2ec498a8..f4949f08 100644
--- a/src/com/android/tv/ui/SelectInputView.java
+++ b/src/com/android/tv/ui/SelectInputView.java
@@ -36,7 +36,7 @@ import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.analytics.Tracker;
import com.android.tv.common.util.DurationTimer;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.util.TvInputManagerHelper;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/src/com/android/tv/ui/TunableTvView.java b/src/com/android/tv/ui/TunableTvView.java
index f1e72afb..9c75bc80 100644
--- a/src/com/android/tv/ui/TunableTvView.java
+++ b/src/com/android/tv/ui/TunableTvView.java
@@ -70,23 +70,24 @@ import com.android.tv.common.util.CommonUtils;
import com.android.tv.common.util.Debug;
import com.android.tv.common.util.DurationTimer;
import com.android.tv.common.util.PermissionUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
import com.android.tv.data.StreamInfo;
import com.android.tv.data.WatchedHistoryManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
import com.android.tv.recommendation.NotificationService;
-import com.android.tv.util.ImageLoader;
import com.android.tv.util.NetworkUtils;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
+import com.android.tv.util.images.ImageLoader;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
-public class TunableTvView extends FrameLayout implements StreamInfo {
+/** Includes the real {@link AppLayerTvView} handling tuning, block and other display events. */
+public class TunableTvView extends FrameLayout implements StreamInfo, TunableTvViewPlayingApi {
private static final boolean DEBUG = false;
private static final String TAG = "TunableTvView";
@@ -594,6 +595,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mIsUnderShrunken = isUnderShrunken;
}
+ @Override
public boolean isPlaying() {
return mStarted;
}
@@ -706,6 +708,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
mCurrentChannel = currentChannel;
}
+ @Override
public void setStreamVolume(float volume) {
if (!mStarted) {
throw new IllegalStateException("TvView isn't started");
@@ -1260,6 +1263,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
*
* @param listener The instance of {@link TimeShiftListener}.
*/
+ @Override
public void setTimeShiftListener(TimeShiftListener listener) {
mTimeShiftListener = listener;
}
@@ -1295,11 +1299,13 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
/** Returns if the time shift is available for the current channel. */
+ @Override
public boolean isTimeShiftAvailable() {
return mTimeShiftAvailable;
}
/** Plays the media, if the current input supports time-shifting. */
+ @Override
public void timeshiftPlay() {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1311,6 +1317,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
/** Pauses the media, if the current input supports time-shifting. */
+ @Override
public void timeshiftPause() {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1326,6 +1333,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.
*/
+ @Override
public void timeshiftRewind(int speed) {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1345,6 +1353,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.
*/
+ @Override
public void timeshiftFastForward(int speed) {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1364,6 +1373,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
*
* @param timeMs The time in milliseconds to seek to.
*/
+ @Override
public void timeshiftSeekTo(long timeMs) {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1372,6 +1382,7 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
}
/** Returns the current playback position in milliseconds. */
+ @Override
public long timeshiftGetCurrentPositionMs() {
if (!isTimeShiftAvailable()) {
throw new IllegalStateException("Time-shift is not supported for the current channel");
@@ -1405,21 +1416,6 @@ public class TunableTvView extends FrameLayout implements StreamInfo {
};
}
- /** Used to receive the time-shift events. */
- public abstract static class TimeShiftListener {
- /**
- * Called when the availability of the time-shift for the current channel has been changed.
- * It should be guaranteed that this is called only when the availability is really changed.
- */
- public abstract void onAvailabilityChanged();
-
- /**
- * 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);
- }
-
/** A listener which receives the notification when the screen is blocked/unblocked. */
public abstract static class OnScreenBlockingChangedListener {
/** Called when the screen is blocked/unblocked. */
diff --git a/src/com/android/tv/ui/TunableTvViewPlayingApi.java b/src/com/android/tv/ui/TunableTvViewPlayingApi.java
new file mode 100644
index 00000000..3f19b61f
--- /dev/null
+++ b/src/com/android/tv/ui/TunableTvViewPlayingApi.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.tv.ui;
+
+/** API to play pause and set the volume of a TunableTvView */
+public interface TunableTvViewPlayingApi {
+
+ boolean isPlaying();
+
+ void setStreamVolume(float volume);
+
+ void setTimeShiftListener(TimeShiftListener listener);
+
+ boolean isTimeShiftAvailable();
+
+ void timeshiftPlay();
+
+ void timeshiftPause();
+
+ void timeshiftRewind(int speed);
+
+ void timeshiftFastForward(int speed);
+
+ void timeshiftSeekTo(long timeMs);
+
+ long timeshiftGetCurrentPositionMs();
+
+ /** Used to receive the time-shift events. */
+ abstract class TimeShiftListener {
+ /**
+ * Called when the availability of the time-shift for the current channel has been changed.
+ * It should be guaranteed that this is called only when the availability is really changed.
+ */
+ public abstract void onAvailabilityChanged();
+
+ /**
+ * 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);
+ }
+}
diff --git a/src/com/android/tv/ui/TvTransitionManager.java b/src/com/android/tv/ui/TvTransitionManager.java
index e3f72dc1..5af3e6f2 100644
--- a/src/com/android/tv/ui/TvTransitionManager.java
+++ b/src/com/android/tv/ui/TvTransitionManager.java
@@ -32,7 +32,7 @@ import android.widget.FrameLayout;
import android.widget.FrameLayout.LayoutParams;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java
index 07f7119f..2726839c 100644
--- a/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java
+++ b/src/com/android/tv/ui/sidepanel/ChannelCheckItem.java
@@ -20,12 +20,12 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import com.android.tv.R;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
import com.android.tv.data.ChannelDataManager.ChannelListener;
import com.android.tv.data.OnCurrentProgramUpdatedListener;
import com.android.tv.data.Program;
import com.android.tv.data.ProgramDataManager;
+import com.android.tv.data.api.Channel;
public abstract class ChannelCheckItem extends CompoundButtonItem {
private final ChannelDataManager mChannelDataManager;
diff --git a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
index 8660c830..48b80723 100644
--- a/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
+++ b/src/com/android/tv/ui/sidepanel/CustomizeChannelListFragment.java
@@ -29,8 +29,9 @@ import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
import com.android.tv.common.util.SharedPreferencesUtils;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.ChannelNumber;
+import com.android.tv.data.api.Channel;
import com.android.tv.ui.OnRepeatedKeyInterceptListener;
import com.android.tv.util.TvInputManagerHelper;
import com.android.tv.util.Utils;
@@ -53,7 +54,7 @@ public class CustomizeChannelListFragment extends SideFragment {
private static Integer sGroupingType;
private TvInputManagerHelper mInputManager;
- private Channel.DefaultComparator mChannelComparator;
+ private ChannelImpl.DefaultComparator mChannelComparator;
private boolean mGroupByFragmentRunning;
private final List<Item> mItems = new ArrayList<>();
@@ -63,7 +64,7 @@ public class CustomizeChannelListFragment extends SideFragment {
super.onCreate(savedInstanceState);
mInputManager = getMainActivity().getTvInputManagerHelper();
mInitialChannelId = getMainActivity().getCurrentChannelId();
- mChannelComparator = new Channel.DefaultComparator(getActivity(), mInputManager);
+ mChannelComparator = new ChannelImpl.DefaultComparator(getActivity(), mInputManager);
if (sGroupingType == null) {
SharedPreferences sharedPreferences =
getContext()
diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
index d70cf97a..4e3cf7fb 100644
--- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
+++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ChannelsBlockedFragment.java
@@ -30,8 +30,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.android.tv.R;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelNumber;
+import com.android.tv.data.api.Channel;
import com.android.tv.recommendation.ChannelPreviewUpdater;
import com.android.tv.ui.OnRepeatedKeyInterceptListener;
import com.android.tv.ui.sidepanel.ActionItem;
diff --git a/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java b/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java
index 3bd066e0..1c91ba9b 100644
--- a/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java
+++ b/src/com/android/tv/ui/sidepanel/parentalcontrols/ParentalControlsFragment.java
@@ -20,7 +20,7 @@ import android.view.View;
import android.widget.TextView;
import com.android.tv.MainActivity;
import com.android.tv.R;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.dialog.PinDialogFragment;
import com.android.tv.ui.sidepanel.ActionItem;
import com.android.tv.ui.sidepanel.Item;
diff --git a/src/com/android/tv/util/AsyncDbTask.java b/src/com/android/tv/util/AsyncDbTask.java
index d1ea7aa8..60fa3018 100644
--- a/src/com/android/tv/util/AsyncDbTask.java
+++ b/src/com/android/tv/util/AsyncDbTask.java
@@ -30,8 +30,9 @@ import android.util.Range;
import com.android.tv.TvSingletons;
import com.android.tv.common.BuildConfig;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.dvr.data.RecordedProgram;
import java.util.ArrayList;
import java.util.List;
@@ -287,7 +288,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
executor,
contentResolver,
TvContract.Channels.CONTENT_URI,
- Channel.PROJECTION,
+ ChannelImpl.PROJECTION,
null,
null,
null);
@@ -295,7 +296,7 @@ public abstract class AsyncDbTask<Params, Progress, Result>
@Override
protected final Channel fromCursor(Cursor c) {
- return Channel.fromCursor(c);
+ return ChannelImpl.fromCursor(c);
}
}
diff --git a/src/com/android/tv/util/SetupUtils.java b/src/com/android/tv/util/SetupUtils.java
index ad5d5024..0d536320 100644
--- a/src/com/android/tv/util/SetupUtils.java
+++ b/src/com/android/tv/util/SetupUtils.java
@@ -35,8 +35,8 @@ import android.util.Log;
import com.android.tv.TvSingletons;
import com.android.tv.common.BaseApplication;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
diff --git a/src/com/android/tv/util/TvInputManagerHelper.java b/src/com/android/tv/util/TvInputManagerHelper.java
index c4feafb7..625fb7b2 100644
--- a/src/com/android/tv/util/TvInputManagerHelper.java
+++ b/src/com/android/tv/util/TvInputManagerHelper.java
@@ -36,6 +36,8 @@ import com.android.tv.common.SoftPreconditions;
import com.android.tv.common.util.CommonUtils;
import com.android.tv.parental.ContentRatingsManager;
import com.android.tv.parental.ParentalControlSettings;
+import com.android.tv.util.images.ImageCache;
+import com.android.tv.util.images.ImageLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -179,7 +181,9 @@ public class TvInputManagerHelper {
TvInputInfo info = mTvInputManager.getTvInputInfo(inputId);
if (info != null) {
mInputMap.put(inputId, info);
- mTvInputLabels.put(inputId, info.loadLabel(mContext).toString());
+ CharSequence label = info.loadLabel(mContext);
+ // in tests the label may be missing just use the input id
+ mTvInputLabels.put(inputId, label != null ? label.toString() : inputId);
CharSequence inputCustomLabel = info.loadCustomLabel(mContext);
if (inputCustomLabel != null) {
mTvInputCustomLabels.put(inputId, inputCustomLabel.toString());
diff --git a/src/com/android/tv/util/Utils.java b/src/com/android/tv/util/Utils.java
index 4850811e..a75bd446 100644
--- a/src/com/android/tv/util/Utils.java
+++ b/src/com/android/tv/util/Utils.java
@@ -43,10 +43,11 @@ import android.view.View;
import com.android.tv.R;
import com.android.tv.TvSingletons;
import com.android.tv.common.SoftPreconditions;
-import com.android.tv.data.Channel;
+import com.android.tv.common.util.Clock;
import com.android.tv.data.GenreItems;
import com.android.tv.data.Program;
import com.android.tv.data.StreamInfo;
+import com.android.tv.data.api.Channel;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -366,6 +367,32 @@ public class Utils {
0);
}
+ /**
+ * Returns duration string according to the date & time format. If {@code startUtcMillis} and
+ * {@code endUtcMills} are equal, formatted time will be returned instead.
+ *
+ * @param clock the clock used to get the current time.
+ * @param startUtcMillis start of duration in millis. Should be less than {code endUtcMillis}.
+ * @param endUtcMillis end of duration in millis. Should be larger than {@code startUtcMillis}.
+ * @param useShortFormat {@code true} if abbreviation is needed to save space. In that case,
+ * date will be omitted if duration starts from today and is less than a day. If it's
+ * necessary, {@link DateUtils#FORMAT_NUMERIC_DATE} is used otherwise.
+ */
+ public static String getDurationString(
+ Context context,
+ Clock clock,
+ long startUtcMillis,
+ long endUtcMillis,
+ boolean useShortFormat) {
+ return getDurationString(
+ context,
+ clock.currentTimeMillis(),
+ startUtcMillis,
+ endUtcMillis,
+ useShortFormat,
+ 0);
+ }
+
@VisibleForTesting
static String getDurationString(
Context context,
@@ -461,13 +488,21 @@ public class Utils {
/** 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();
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(millis));
+ calendar.set(Calendar.HOUR_OF_DAY, 23);
+ calendar.set(Calendar.MINUTE, 59);
+ calendar.set(Calendar.SECOND, 59);
+ calendar.set(Calendar.MILLISECOND, 999);
+ return calendar.getTimeInMillis();
+ }
+
+ /** Returns the last millisecond of a day which the millis belongs to. */
+ public static long getFirstMillisecondOfDay(long millis) {
+ Calendar calendar = Calendar.getInstance();
+ calendar.setTime(new Date(millis));
+ resetCalendar(calendar);
+ return calendar.getTimeInMillis();
}
public static String getAspectRatioString(int width, int height) {
@@ -787,7 +822,7 @@ public class Utils {
/** Returns the TV input for the given {@code program}. */
@Nullable
public static TvInputInfo getTvInputInfoForProgram(Context context, Program program) {
- if (!Program.isValid(program)) {
+ if (!Program.isProgramValid(program)) {
return null;
}
return getTvInputInfoForChannelId(context, program.getChannelId());
diff --git a/src/com/android/tv/util/BitmapUtils.java b/src/com/android/tv/util/images/BitmapUtils.java
index 4c67d934..d6bd5a31 100644
--- a/src/com/android/tv/util/BitmapUtils.java
+++ b/src/com/android/tv/util/images/BitmapUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.content.ContentResolver;
import android.content.Context;
diff --git a/src/com/android/tv/util/ImageCache.java b/src/com/android/tv/util/images/ImageCache.java
index 1017cb14..e260d67a 100644
--- a/src/com/android/tv/util/ImageCache.java
+++ b/src/com/android/tv/util/images/ImageCache.java
@@ -14,13 +14,13 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.support.annotation.VisibleForTesting;
import android.util.Log;
import android.util.LruCache;
-import com.android.tv.common.MemoryManageable;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.common.memory.MemoryManageable;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
/** A convenience class for caching bitmap. */
public class ImageCache implements MemoryManageable {
diff --git a/src/com/android/tv/util/ImageLoader.java b/src/com/android/tv/util/images/ImageLoader.java
index 32ac89f0..e844e2ca 100644
--- a/src/com/android/tv/util/ImageLoader.java
+++ b/src/com/android/tv/util/images/ImageLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import android.content.Context;
import android.graphics.Bitmap;
@@ -32,7 +32,7 @@ import android.util.ArraySet;
import android.util.Log;
import com.android.tv.R;
import com.android.tv.common.concurrent.NamedThreadFactory;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
diff --git a/tests/common/src/com/android/tv/testing/EpgTestData.java b/tests/common/src/com/android/tv/testing/EpgTestData.java
index 87bfb4ed..49a92181 100644
--- a/tests/common/src/com/android/tv/testing/EpgTestData.java
+++ b/tests/common/src/com/android/tv/testing/EpgTestData.java
@@ -16,9 +16,10 @@
package com.android.tv.testing;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableListMultimap;
@@ -173,7 +174,7 @@ public abstract class EpgTestData {
}
public static Channel toTvChannel(android.support.media.tv.Channel original) {
- return new Channel.Builder()
+ return new ChannelImpl.Builder()
.setDisplayName(original.getDisplayName())
.setDisplayNumber(original.getDisplayNumber())
// TODO implement the reset
diff --git a/tests/common/src/com/android/tv/testing/FakeEpgReader.java b/tests/common/src/com/android/tv/testing/FakeEpgReader.java
index a3505279..710ada55 100644
--- a/tests/common/src/com/android/tv/testing/FakeEpgReader.java
+++ b/tests/common/src/com/android/tv/testing/FakeEpgReader.java
@@ -19,10 +19,11 @@ package com.android.tv.testing;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Range;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
import com.android.tv.data.ChannelNumber;
import com.android.tv.data.Lineup;
import com.android.tv.data.Program;
+import com.android.tv.data.api.Channel;
import com.android.tv.data.epg.EpgReader;
import com.android.tv.dvr.data.SeriesInfo;
import com.google.common.base.Function;
@@ -90,7 +91,7 @@ public final class FakeEpgReader implements EpgReader {
},
null);
if (match != null) {
- Channel updatedChannel = new Channel.Builder(match).build();
+ ChannelImpl updatedChannel = new ChannelImpl.Builder(match).build();
updatedChannel.setLogoUri(channel.getLogoUri());
result.add(EpgChannel.createEpgChannel(updatedChannel, channel.getDisplayNumber()));
}
diff --git a/tests/common/src/com/android/tv/testing/TestSingletonApp.java b/tests/common/src/com/android/tv/testing/TestSingletonApp.java
index 4f16bd64..f1798352 100644
--- a/tests/common/src/com/android/tv/testing/TestSingletonApp.java
+++ b/tests/common/src/com/android/tv/testing/TestSingletonApp.java
@@ -20,6 +20,7 @@ import android.app.Application;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.media.tv.TvInputManager;
import android.os.AsyncTask;
import com.android.tv.InputSessionManager;
import com.android.tv.MainActivityWrapper;
@@ -43,6 +44,7 @@ import com.android.tv.dvr.DvrWatchedPositionManager;
import com.android.tv.dvr.recorder.RecordingScheduler;
import com.android.tv.perf.PerformanceMonitor;
import com.android.tv.perf.StubPerformanceMonitor;
+import com.android.tv.testing.testdata.TestData;
import com.android.tv.tuner.TunerInputController;
import com.android.tv.util.SetupUtils;
import com.android.tv.util.TvInputManagerHelper;
@@ -59,10 +61,12 @@ public class TestSingletonApp extends Application implements TvSingletons {
public FakeTvInputManagerHelper tvInputManagerHelper;
public SetupUtils setupUtils;
+ public DvrManager dvrManager;
private final Provider<EpgReader> mEpgReaderProvider = SingletonProvider.create(epgReader);
private TunerInputController mTunerInputController;
private PerformanceMonitor mPerformanceMonitor;
+ private ChannelDataManager mChannelDataManager;
@Override
public void onCreate() {
@@ -74,10 +78,19 @@ public class TestSingletonApp extends Application implements TvSingletons {
tvInputManagerHelper = new FakeTvInputManagerHelper(this);
setupUtils = SetupUtils.createForTvSingletons(this);
tvInputManagerHelper.start();
+ mChannelDataManager = new ChannelDataManager(this, tvInputManagerHelper);
+ mChannelDataManager.start();
// HACK reset the singleton for tests
BaseApplication.sSingletons = this;
}
+ public void loadTestData(TestData testData, long durationMs) {
+ tvInputManagerHelper
+ .getFakeTvInputManager()
+ .add(testData.getTvInputInfo(), TvInputManager.INPUT_STATE_CONNECTED);
+ testData.init(this, fakeClock, durationMs);
+ }
+
@Override
public Analytics getAnalytics() {
return null;
@@ -88,7 +101,7 @@ public class TestSingletonApp extends Application implements TvSingletons {
@Override
public ChannelDataManager getChannelDataManager() {
- return new ChannelDataManager(this, tvInputManagerHelper);
+ return mChannelDataManager;
}
@Override
@@ -123,7 +136,7 @@ public class TestSingletonApp extends Application implements TvSingletons {
@Override
public DvrManager getDvrManager() {
- return null;
+ return dvrManager;
}
@Override
diff --git a/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java b/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java
new file mode 100644
index 00000000..3eb97b5f
--- /dev/null
+++ b/tests/common/src/com/android/tv/testing/robo/RobotTestAppHelper.java
@@ -0,0 +1,21 @@
+package com.android.tv.testing.robo;
+
+import android.media.tv.TvContract;
+import com.android.tv.testing.FakeTvProvider;
+import com.android.tv.testing.TestSingletonApp;
+import com.android.tv.testing.testdata.TestData;
+import java.util.concurrent.TimeUnit;
+import org.robolectric.Robolectric;
+
+/** Static utilities for using {@link TestSingletonApp} in roboletric tests. */
+public final class RobotTestAppHelper {
+
+ public static void loadTestData(TestSingletonApp app, TestData testData) {
+ ContentProviders.register(FakeTvProvider.class, TvContract.AUTHORITY);
+ app.loadTestData(testData, TimeUnit.DAYS.toMillis(1));
+ Robolectric.flushBackgroundThreadScheduler();
+ Robolectric.flushForegroundThreadScheduler();
+ }
+
+ private RobotTestAppHelper() {}
+}
diff --git a/tests/common/src/com/android/tv/testing/testdata/TestData.java b/tests/common/src/com/android/tv/testing/testdata/TestData.java
index c96a9906..e7e52348 100644
--- a/tests/common/src/com/android/tv/testing/testdata/TestData.java
+++ b/tests/common/src/com/android/tv/testing/testdata/TestData.java
@@ -17,10 +17,12 @@
package com.android.tv.testing.testdata;
import android.content.Context;
+import android.media.tv.TvInputInfo;
import com.android.tv.common.util.Clock;
import com.android.tv.testing.data.ChannelInfo;
import com.android.tv.testing.data.ChannelUtils;
import com.android.tv.testing.data.ProgramUtils;
+import com.android.tv.testing.utils.TestUtils;
import java.util.List;
/**
@@ -33,7 +35,7 @@ import java.util.List;
* <li>Channel List
* </ul>
*
- * Call {@link #init(Context)}, update the TvProvider data base with the given values.
+ * Call {@link #init(Context)}, to update the TvProvider data base with the given values.
*/
public abstract class TestData {
private List<ChannelInfo> channelList;
@@ -46,18 +48,39 @@ public abstract class TestData {
ProgramUtils.updateProgramForAllChannelsOf(context, getInputId(), clock, durationMs);
}
- protected abstract String getInputId();
+ public abstract TvInputInfo getTvInputInfo();
+
+ public final String getInputId() {
+ return getTvInputInfo().getId();
+ }
public static final TestData DEFAULT_10_CHANNELS =
new TestData() {
+ private TvInputInfo mTvInputInfo = createTvInputInfo();
+
+ private TvInputInfo createTvInputInfo() {
+ try {
+ return TestUtils.createTvInputInfo(
+ TestUtils.createResolveInfo(
+ "com.android.tv.testing.testdata",
+ "com.android.tv.testing.testdata.Default10Channels"),
+ "com.android.tv.testing.testdata/.Default10Channels",
+ null,
+ TvInputInfo.TYPE_TUNER,
+ true);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
@Override
protected List<ChannelInfo> createChannels(Context context) {
return ChannelUtils.createChannelInfos(context, 10);
}
@Override
- protected String getInputId() {
- return "com.android.tv.testing.testdata/.Default10Channels";
+ public TvInputInfo getTvInputInfo() {
+ return mTvInputInfo;
}
};
}
diff --git a/tests/unit/src/com/android/tv/util/TestUtils.java b/tests/common/src/com/android/tv/testing/utils/TestUtils.java
index 92669070..6604c9ad 100644
--- a/tests/unit/src/com/android/tv/util/TestUtils.java
+++ b/tests/common/src/com/android/tv/testing/utils/TestUtils.java
@@ -14,8 +14,9 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.testing.utils;
+import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.graphics.drawable.Icon;
@@ -186,6 +187,7 @@ public class TestUtils {
resolveInfo.serviceInfo.packageName = packageName;
resolveInfo.serviceInfo.name = name;
resolveInfo.serviceInfo.metaData = new Bundle();
+ resolveInfo.serviceInfo.applicationInfo = new ApplicationInfo();
return resolveInfo;
}
}
diff --git a/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java b/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
index 84283d90..795f6370 100644
--- a/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
+++ b/tests/unit/src/com/android/tv/BaseMainActivityTestCase.java
@@ -21,8 +21,8 @@ import android.content.Context;
import android.os.SystemClock;
import android.support.test.rule.ActivityTestRule;
import android.text.TextUtils;
-import com.android.tv.data.Channel;
import com.android.tv.data.ChannelDataManager;
+import com.android.tv.data.api.Channel;
import com.android.tv.testing.data.ChannelInfo;
import com.android.tv.testing.testinput.ChannelStateData;
import com.android.tv.testing.testinput.TestInputControlConnection;
diff --git a/tests/unit/src/com/android/tv/MainActivityTest.java b/tests/unit/src/com/android/tv/MainActivityTest.java
index d28a8cd2..5bd526cc 100644
--- a/tests/unit/src/com/android/tv/MainActivityTest.java
+++ b/tests/unit/src/com/android/tv/MainActivityTest.java
@@ -23,7 +23,7 @@ import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.TextView;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.testing.testinput.TvTestInputConstants;
import com.android.tv.ui.ChannelBannerView;
import java.util.List;
diff --git a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
index b3d76390..96c1f7a1 100644
--- a/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelDataManagerTest.java
@@ -40,6 +40,7 @@ import android.test.mock.MockCursor;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
+import com.android.tv.data.api.Channel;
import com.android.tv.testing.constants.Constants;
import com.android.tv.testing.data.ChannelInfo;
import com.android.tv.util.TvInputManagerHelper;
diff --git a/tests/unit/src/com/android/tv/data/ChannelTest.java b/tests/unit/src/com/android/tv/data/ChannelImplTest.java
index 9b101ed3..b791a7e4 100644
--- a/tests/unit/src/com/android/tv/data/ChannelTest.java
+++ b/tests/unit/src/com/android/tv/data/ChannelImplTest.java
@@ -27,6 +27,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.tv.data.api.Channel;
import com.android.tv.testing.ComparatorTester;
import com.android.tv.util.TvInputManagerHelper;
import java.util.Comparator;
@@ -38,10 +39,10 @@ import org.mockito.Mockito;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
-/** Tests for {@link Channel}. */
+/** Tests for {@link ChannelImpl}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class ChannelTest {
+public class ChannelImplTest {
// Used for testing TV inputs with invalid input package. This could happen when a TV input is
// uninstalled while drawing an app link card.
private static final String INVALID_TV_INPUT_PACKAGE_NAME = "com.android.tv.invalid_tv_input";
@@ -232,10 +233,11 @@ public class ChannelTest {
private void assertAppLinkType(
int expectedType, String inputPackageName, String appLinkText, Intent appLinkIntent) {
- // In Channel, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag should be
+ // In ChannelImpl, Intent.URI_INTENT_SCHEME is used to parse the URI. So the same flag
+ // should be
// used when the URI is created.
- Channel testChannel =
- new Channel.Builder()
+ ChannelImpl testChannel =
+ new ChannelImpl.Builder()
.setPackageName(inputPackageName)
.setAppLinkText(appLinkText)
.setAppLinkIntentUri(
@@ -263,40 +265,40 @@ public class ChannelTest {
Comparator<Channel> comparator = new TestChannelComparator(manager);
ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId(PARTNER_INPUT_ID).build());
- comparatorTester.addComparableGroup(new Channel.Builder().setInputId("1").build());
+ new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).build());
+ comparatorTester.addComparableGroup(new ChannelImpl.Builder().setInputId("1").build());
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId("1").setDisplayNumber("2").build());
+ new ChannelImpl.Builder().setInputId("1").setDisplayNumber("2").build());
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId("2").setDisplayNumber("1.0").build());
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("1.0").build());
// display name does not affect comparator
comparatorTester.addComparableGroup(
- new Channel.Builder()
+ new ChannelImpl.Builder()
.setInputId("2")
.setDisplayNumber("1.62")
.setDisplayName("test1")
.build(),
- new Channel.Builder()
+ new ChannelImpl.Builder()
.setInputId("2")
.setDisplayNumber("1.62")
.setDisplayName("test2")
.build(),
- new Channel.Builder()
+ new ChannelImpl.Builder()
.setInputId("2")
.setDisplayNumber("1.62")
.setDisplayName("test3")
.build());
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId("2").setDisplayNumber("2.0").build());
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("2.0").build());
// Numeric display number sorting
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId("2").setDisplayNumber("12.2").build());
+ new ChannelImpl.Builder().setInputId("2").setDisplayNumber("12.2").build());
comparatorTester.test();
}
/**
- * Test Input Label handled by {@link com.android.tv.data.Channel.DefaultComparator}.
+ * Test Input Label handled by {@link ChannelImpl.DefaultComparator}.
*
* <p>Sort partner inputs first, then sort by input label, then by input id. See <a
* href="http://b/23031603">b/23031603</a>.
@@ -317,15 +319,15 @@ public class ChannelTest {
ComparatorTester<Channel> comparatorTester = ComparatorTester.withoutEqualsTest(comparator);
comparatorTester.addComparableGroup(
- new Channel.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build());
+ new ChannelImpl.Builder().setInputId(PARTNER_INPUT_ID).setDescription("A").build());
// The description is used as a label for this test.
comparatorTester.addComparableGroup(
- new Channel.Builder().setDescription("A").setInputId("1").build());
+ new ChannelImpl.Builder().setDescription("A").setInputId("1").build());
comparatorTester.addComparableGroup(
- new Channel.Builder().setDescription("A").setInputId("2").build());
+ new ChannelImpl.Builder().setDescription("A").setInputId("2").build());
comparatorTester.addComparableGroup(
- new Channel.Builder().setDescription("B").setInputId("1").build());
+ new ChannelImpl.Builder().setDescription("B").setInputId("1").build());
comparatorTester.test();
}
@@ -351,10 +353,10 @@ public class ChannelTest {
}
private void assertNormalizedDisplayNumber(String displayNumber, String normalized) {
- assertThat(Channel.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized);
+ assertThat(ChannelImpl.normalizeDisplayNumber(displayNumber)).isEqualTo(normalized);
}
- private static final class TestChannelComparator extends Channel.DefaultComparator {
+ private static final class TestChannelComparator extends ChannelImpl.DefaultComparator {
public TestChannelComparator(TvInputManagerHelper manager) {
super(null, manager);
}
@@ -366,7 +368,7 @@ public class ChannelTest {
}
private static final class ChannelComparatorWithDescriptionAsLabel
- extends Channel.DefaultComparator {
+ extends ChannelImpl.DefaultComparator {
public ChannelComparatorWithDescriptionAsLabel(TvInputManagerHelper manager) {
super(null, manager);
}
diff --git a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
index 8bf3efbc..8e892cce 100644
--- a/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
+++ b/tests/unit/src/com/android/tv/data/TvInputNewComparatorTest.java
@@ -22,8 +22,8 @@ import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.util.Pair;
import com.android.tv.testing.ComparatorTester;
+import com.android.tv.testing.utils.TestUtils;
import com.android.tv.util.SetupUtils;
-import com.android.tv.util.TestUtils;
import com.android.tv.util.TvInputManagerHelper;
import java.util.Comparator;
import java.util.LinkedHashMap;
diff --git a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
index 539698bf..43bfde09 100644
--- a/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
+++ b/tests/unit/src/com/android/tv/data/WatchedHistoryManagerTest.java
@@ -69,7 +69,7 @@ public class WatchedHistoryManagerTest {
long fakeId = 100000000;
long time = System.currentTimeMillis();
long duration = TimeUnit.MINUTES.toMillis(10);
- Channel channel = new Channel.Builder().setId(fakeId).build();
+ ChannelImpl channel = new ChannelImpl.Builder().setId(fakeId).build();
mWatchedHistoryManager.logChannelViewStop(channel, time, duration);
WatchedRecord record = mWatchedHistoryManager.getRecord(0);
@@ -90,7 +90,7 @@ public class WatchedHistoryManagerTest {
int size = MAX_HISTORY_SIZE * 2;
for (int i = 0; i < size; ++i) {
- Channel channel = new Channel.Builder().setId(startChannelId + i).build();
+ ChannelImpl channel = new ChannelImpl.Builder().setId(startChannelId + i).build();
mWatchedHistoryManager.logChannelViewStop(channel, time + duration * i, duration);
}
for (int i = 0; i < MAX_HISTORY_SIZE; ++i) {
diff --git a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
index 6e76bf36..f62a5e05 100644
--- a/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
+++ b/tests/unit/src/com/android/tv/recommendation/EvaluatorTestCase.java
@@ -20,7 +20,7 @@ import static android.support.test.InstrumentationRegistry.getContext;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper;
import com.android.tv.recommendation.Recommender.Evaluator;
import com.android.tv.testing.utils.Utils;
diff --git a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
index 2fc4bb1c..b929a0ae 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecommendationUtils.java
@@ -17,7 +17,8 @@
package com.android.tv.recommendation;
import android.content.Context;
-import com.android.tv.data.Channel;
+import com.android.tv.data.ChannelImpl;
+import com.android.tv.data.api.Channel;
import com.android.tv.testing.utils.Utils;
import java.util.ArrayList;
import java.util.Collection;
@@ -106,7 +107,7 @@ public class RecommendationUtils {
*/
public Channel addChannel() {
long channelId = size();
- Channel channel = new Channel.Builder().setId(channelId).build();
+ ChannelImpl channel = new ChannelImpl.Builder().setId(channelId).build();
ChannelRecord channelRecord = new ChannelRecord(mContext, channel, false);
put(channelId, channelRecord);
return channel;
diff --git a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
index e2b0b249..1b5cca72 100644
--- a/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
+++ b/tests/unit/src/com/android/tv/recommendation/RecommenderTest.java
@@ -23,7 +23,7 @@ import static org.junit.Assert.assertTrue;
import android.support.test.filters.SmallTest;
import android.test.MoreAsserts;
-import com.android.tv.data.Channel;
+import com.android.tv.data.api.Channel;
import com.android.tv.recommendation.RecommendationUtils.ChannelRecordSortedMapHelper;
import com.android.tv.testing.utils.Utils;
import java.util.ArrayList;
diff --git a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
index 168e7c6e..6dfed64a 100644
--- a/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
+++ b/tests/unit/src/com/android/tv/util/TvInputManagerHelperTest.java
@@ -23,6 +23,7 @@ import android.media.tv.TvInputInfo;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import com.android.tv.testing.ComparatorTester;
+import com.android.tv.testing.utils.TestUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
diff --git a/tests/unit/src/com/android/tv/util/ImageCacheTest.java b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java
index cd34895e..b094adc3 100644
--- a/tests/unit/src/com/android/tv/util/ImageCacheTest.java
+++ b/tests/unit/src/com/android/tv/util/images/ImageCacheTest.java
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
-import static com.android.tv.util.BitmapUtils.createScaledBitmapInfo;
+import static com.android.tv.util.images.BitmapUtils.createScaledBitmapInfo;
import static org.junit.Assert.assertSame;
import android.graphics.Bitmap;
import android.support.test.filters.MediumTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java b/tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java
index 9bb69f80..0bde0981 100644
--- a/tests/unit/src/com/android/tv/util/ScaledBitmapInfoTest.java
+++ b/tests/unit/src/com/android/tv/util/images/ScaledBitmapInfoTest.java
@@ -13,14 +13,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.tv.util;
+package com.android.tv.util.images;
import static org.junit.Assert.assertEquals;
import android.graphics.Bitmap;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.tv.util.BitmapUtils.ScaledBitmapInfo;
+import com.android.tv.util.images.BitmapUtils.ScaledBitmapInfo;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java
index c765818d..15e90437 100644
--- a/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java
+++ b/tuner/SampleDvbTuner/src/com/android/tv/tuner/sample/dvb/app/SampleDvbTuner.java
@@ -21,7 +21,7 @@ import android.content.Context;
import android.content.Intent;
import android.media.tv.TvContract;
import com.android.tv.common.BaseApplication;
-import com.android.tv.common.CommonConstants;
+import com.android.tv.common.actions.InputSetupActionUtils;
import com.android.tv.common.config.DefaultConfigManager;
import com.android.tv.common.config.api.RemoteConfig;
import com.android.tv.common.util.CommonUtils;
@@ -39,7 +39,7 @@ public class SampleDvbTuner extends BaseApplication {
Intent intent =
CommonUtils.createSetupIntent(
new Intent(context, LiveTvTunerSetupActivity.class), mEmbeddedInputId);
- intent.putExtra(CommonConstants.EXTRA_INPUT_ID, mEmbeddedInputId);
+ intent.putExtra(InputSetupActionUtils.EXTRA_INPUT_ID, mEmbeddedInputId);
return intent;
}
diff --git a/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml b/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml
index c3192c37..3e6946a9 100644
--- a/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml
+++ b/tuner/tests/unittests/javatests/com/android/tv/tuner/layout/tests/AndroidManifest.xml
@@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.tv.tuner"
android:versionCode="1">
- <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="21"/>
+ <uses-sdk android:targetSdkVersion="26" android:minSdkVersion="23"/>
<application android:label="TunerTvInputLayoutTests" >
<activity android:name="com.android.tv.tuner.layout.tests.ScaledLayoutActivity"
android:label="ScaledLayout Test" />