From bc8d0d165b43676160a47bb5171b95c819614fbe Mon Sep 17 00:00:00 2001 From: dmolchanov Date: Fri, 18 Apr 2025 10:58:26 +0300 Subject: [PATCH] [Showcase] update LeanbackShowcase sample --- LeanbackShowcase/app/build.gradle | 96 ++++++------ .../leanbackshowcase/ApplicationTest.java | 19 ++- .../app/src/main/AndroidManifest.xml | 5 +- .../details/DetailViewExampleFragment.java | 4 +- ...iewExampleWithVideoBackgroundFragment.java | 4 +- .../app/media/ExoPlayerAdapter.java | 137 +++++++++--------- .../MusicConsumptionExampleFragment.java | 6 +- .../app/media/MusicPlaybackService.java | 10 +- ...nsumptionExampleWithExoPlayerFragment.java | 1 - .../room/ui/FullWidthDetailsPresenter.java | 4 +- .../app/room/ui/VideoCardPresenter.java | 2 +- .../app/room/viewmodel/VideosViewModel.java | 34 ++--- .../app/rows/PublishChannelFragment.java | 2 +- .../app/rows/VideoContentCardPresenter.java | 2 +- .../presenters/SingleLineCardPresenter.java | 4 +- LeanbackShowcase/build.gradle | 36 +---- LeanbackShowcase/gradle.properties | 3 +- LeanbackShowcase/gradle/libs.versions.toml | 64 ++++++++ .../gradle/wrapper/gradle-wrapper.properties | 4 +- LeanbackShowcase/settings.gradle | 17 +++ 20 files changed, 264 insertions(+), 190 deletions(-) create mode 100644 LeanbackShowcase/gradle/libs.versions.toml diff --git a/LeanbackShowcase/app/build.gradle b/LeanbackShowcase/app/build.gradle index a42a3da32..f4ffad705 100644 --- a/LeanbackShowcase/app/build.gradle +++ b/LeanbackShowcase/app/build.gradle @@ -14,20 +14,24 @@ * limitations under the License. */ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.kapt) +} android { - compileSdkVersion 28 - buildToolsVersion rootProject.buildToolsVersion + + namespace 'androidx.leanback.leanbackshowcase' + compileSdkVersion 35 + defaultConfig { - applicationId 'com.example.android.persistence' + applicationId 'androidx.leanback.leanbackshowcase' minSdkVersion 21 - targetSdkVersion 28 - compileSdkVersion 28 - versionCode 1 - versionName "1.0" + targetSdkVersion 35 + compileSdkVersion 35 + versionCode 2 + versionName "1.1" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -50,55 +54,63 @@ android { lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_17 + targetCompatibility JavaVersion.VERSION_17 + } + kotlinOptions { + jvmTarget = "17" + } } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation libs.material + implementation libs.cardview + implementation libs.recyclerview + implementation libs.room.runtime + implementation libs.androidx.lifecycle.extensions - implementation 'com.google.android.material:material:' + rootProject.materialVersion - implementation 'androidx.cardview:cardview:' + rootProject.supportLibVersion - implementation 'androidx.recyclerview:recyclerview:' + rootProject.supportLibVersion - implementation 'androidx.lifecycle:lifecycle-extensions:' + rootProject.archLifecycleVersion - implementation 'androidx.room:room-runtime:' + rootProject.archRoomVersion - kapt "androidx.lifecycle:lifecycle-compiler:" + rootProject.archLifecycleVersion - kapt "androidx.room:room-compiler:" + rootProject.archRoomVersion + kapt libs.androidx.lifecycle.compiler + kapt libs.androidx.room.compiler - testImplementation 'junit:junit:4.12' + testImplementation libs.junit // Testing-only dependencies - androidTestImplementation 'androidx.test:runner:' + rootProject.testVersion - androidTestImplementation 'androidx.test:rules:' + rootProject.testVersion - androidTestImplementation 'androidx.test.espresso:espresso-core:' + rootProject.espressoVersion + androidTestImplementation libs.androidx.runner + androidTestImplementation libs.androidx.rules + androidTestImplementation libs.androidx.junit + androidTestImplementation libs.androidx.espresso.core - androidTestImplementation 'androidx.test.espresso:espresso-contrib:' + rootProject.espressoVersion + androidTestImplementation libs.androidx.espresso.contrib // Force usage of dependencies in the test app, since it is internally used by the runner module. - androidTestImplementation 'com.google.android.material:material:' + rootProject.materialVersion - androidTestImplementation 'androidx.recyclerview:recyclerview:' + rootProject.supportLibVersion + androidTestImplementation libs.material + androidTestImplementation libs.recyclerview - implementation 'androidx.leanback:leanback:' + rootProject.supportLibVersion - implementation 'androidx.appcompat:appcompat:' + rootProject.supportLibVersion + implementation libs.leanback + implementation libs.appcompat - implementation 'androidx.preference:preference:' + rootProject.supportLibVersion - implementation 'androidx.leanback:leanback-preference:' + rootProject.supportLibVersion - implementation 'androidx.legacy:legacy-preference-v14:' + rootProject.supportLibVersion + implementation libs.preference.ktx + implementation libs.leanback.preference + implementation libs.legacy.preference.v14 - implementation "com.google.code.gson:gson:2.8.2" - implementation "androidx.palette:palette:" + rootProject.supportLibVersion - implementation 'com.google.android.exoplayer:exoplayer:r2.2.0' + implementation libs.gson + implementation libs.androidx.palette.ktx + implementation libs.androidx.media3.exoplayer - implementation 'com.github.bumptech.glide:glide:4.0.0-RC1' - implementation 'androidx.tvprovider:tvprovider:' + rootProject.supportLibVersion + implementation libs.glide + implementation libs.androidx.tvprovider - implementation 'com.squareup.retrofit2:converter-gson:2.3.0' - implementation 'com.squareup.retrofit2:retrofit:2.3.0' + implementation libs.converter.gson + implementation libs.retrofit - implementation "com.google.dagger:dagger:" + rootProject.daggerVersion - implementation "com.google.dagger:dagger-android:" + rootProject.daggerVersion - implementation "com.google.dagger:dagger-android-support:" + rootProject.daggerVersion + implementation libs.dagger + implementation libs.dagger.android + implementation libs.dagger.android.support - kapt "com.google.dagger:dagger-android-processor:" + rootProject.daggerVersion - kapt "com.google.dagger:dagger-compiler:" + rootProject.daggerVersion + kapt libs.dagger.android.processor + kapt libs.dagger.compiler } diff --git a/LeanbackShowcase/app/src/androidTest/java/androidx/leanback/leanbackshowcase/ApplicationTest.java b/LeanbackShowcase/app/src/androidTest/java/androidx/leanback/leanbackshowcase/ApplicationTest.java index f19467289..7e4111c2b 100644 --- a/LeanbackShowcase/app/src/androidTest/java/androidx/leanback/leanbackshowcase/ApplicationTest.java +++ b/LeanbackShowcase/app/src/androidTest/java/androidx/leanback/leanbackshowcase/ApplicationTest.java @@ -14,14 +14,25 @@ package androidx.leanback.leanbackshowcase; +import androidx.test.core.app.ApplicationProvider; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertNotNull; + import android.app.Application; -import android.test.ApplicationTestCase; /** * Testing Fundamentals */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); +@RunWith(AndroidJUnit4.class) +public class ApplicationTest { + + @Test + public void testApplicationContext() { + Application app = ApplicationProvider.getApplicationContext(); + assertNotNull(app); } } \ No newline at end of file diff --git a/LeanbackShowcase/app/src/main/AndroidManifest.xml b/LeanbackShowcase/app/src/main/AndroidManifest.xml index e9dac20aa..0ac019b28 100644 --- a/LeanbackShowcase/app/src/main/AndroidManifest.xml +++ b/LeanbackShowcase/app/src/main/AndroidManifest.xml @@ -13,6 +13,7 @@ + @@ -113,7 +115,8 @@ + android:name=".app.rows.VideoPlaybackActivity" + android:exported="true"> diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleFragment.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleFragment.java index ecda9efdf..78c649c83 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleFragment.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleFragment.java @@ -91,11 +91,11 @@ protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { RowPresenter.ViewHolder viewHolder = super.createRowViewHolder(parent); View actionsView = viewHolder.view. - findViewById(R.id.details_overview_actions_background); + findViewById(androidx.leanback.R.id.details_overview_actions_background); actionsView.setBackgroundColor(getActivity().getResources(). getColor(R.color.detail_view_actionbar_background)); - View detailsView = viewHolder.view.findViewById(R.id.details_frame); + View detailsView = viewHolder.view.findViewById(androidx.leanback.R.id.details_frame); detailsView.setBackgroundColor( getResources().getColor(R.color.detail_view_background)); return viewHolder; diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleWithVideoBackgroundFragment.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleWithVideoBackgroundFragment.java index 286115f0e..e8f27d51a 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleWithVideoBackgroundFragment.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/details/DetailViewExampleWithVideoBackgroundFragment.java @@ -103,11 +103,11 @@ protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { RowPresenter.ViewHolder viewHolder = super.createRowViewHolder(parent); View actionsView = viewHolder.view. - findViewById(R.id.details_overview_actions_background); + findViewById(androidx.leanback.R.id.details_overview_actions_background); actionsView.setBackgroundColor(getActivity().getResources(). getColor(R.color.detail_view_actionbar_background)); - View detailsView = viewHolder.view.findViewById(R.id.details_frame); + View detailsView = viewHolder.view.findViewById(androidx.leanback.R.id.details_frame); detailsView.setBackgroundColor( getResources().getColor(R.color.detail_view_background)); return viewHolder; diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/ExoPlayerAdapter.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/ExoPlayerAdapter.java index 0c287f3c9..e4662d808 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/ExoPlayerAdapter.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/ExoPlayerAdapter.java @@ -21,32 +21,35 @@ import androidx.leanback.media.PlaybackGlueHost; import androidx.leanback.media.PlayerAdapter; import androidx.leanback.media.SurfaceHolderGlueHost; -import androidx.leanback.leanbackshowcase.R; import android.view.SurfaceHolder; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.DefaultLoadControl; -import com.google.android.exoplayer2.ExoPlaybackException; -import com.google.android.exoplayer2.ExoPlayer; -import com.google.android.exoplayer2.ExoPlayerFactory; -import com.google.android.exoplayer2.SimpleExoPlayer; -import com.google.android.exoplayer2.Timeline; -import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; -import com.google.android.exoplayer2.source.ExtractorMediaSource; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; -import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; -import com.google.android.exoplayer2.util.Util; +import androidx.media3.common.AudioAttributes; +import androidx.media3.common.C; +import androidx.media3.common.PlaybackException; +import androidx.media3.common.Player; +import androidx.media3.common.Tracks; +import androidx.media3.common.VideoSize; +import androidx.media3.common.util.UnstableApi; +import androidx.media3.common.util.Util; +import androidx.media3.exoplayer.ExoPlaybackException; +import androidx.media3.exoplayer.ExoPlayer; +import androidx.media3.common.MediaItem; +import androidx.media3.datasource.DefaultDataSource; +import androidx.media3.exoplayer.source.MediaSource; +import androidx.media3.exoplayer.source.ProgressiveMediaSource; +import androidx.media3.common.Timeline; +import androidx.media3.exoplayer.trackselection.DefaultTrackSelector; + +import java.util.Objects; /** - * This implementation extends the {@link PlayerAdapter} with a {@link SimpleExoPlayer}. + * This implementation extends the {@link PlayerAdapter} with a {@link ExoPlayer}. */ -public class ExoPlayerAdapter extends PlayerAdapter implements ExoPlayer.EventListener{ +@UnstableApi +public class ExoPlayerAdapter extends PlayerAdapter implements Player.Listener { Context mContext; - final SimpleExoPlayer mPlayer; + final ExoPlayer mPlayer; SurfaceHolderGlueHost mSurfaceHolderGlueHost; final Runnable mRunnable = new Runnable() { @Override @@ -61,16 +64,20 @@ public void run() { Uri mMediaSourceUri = null; boolean mHasDisplay; boolean mBufferingStart; - @C.StreamType int mAudioStreamType; + + private AudioAttributes mAudioAttributes = new AudioAttributes.Builder() + .setUsage(C.USAGE_MEDIA) + .setContentType(C.AUDIO_CONTENT_TYPE_MOVIE) + .build(); /** * Constructor. */ public ExoPlayerAdapter(Context context) { mContext = context; - mPlayer = ExoPlayerFactory.newSimpleInstance(mContext, - new DefaultTrackSelector(), - new DefaultLoadControl()); + mPlayer = new ExoPlayer.Builder(context) + .setTrackSelector(new DefaultTrackSelector(context)) + .build(); mPlayer.addListener(this); } @@ -112,7 +119,7 @@ void notifyBufferingStartEnd() { } /** - * Release internal {@link SimpleExoPlayer}. Should not use the object after call release(). + * Release internal {@link ExoPlayer}. Should not use the object after call release(). */ public void release() { changeToUninitialized(); @@ -131,7 +138,7 @@ public void onDetachedFromHost() { } /** - * @see SimpleExoPlayer#setVideoSurfaceHolder(SurfaceHolder) + * @see ExoPlayer#setVideoSurfaceHolder(SurfaceHolder) */ void setDisplay(SurfaceHolder surfaceHolder) { boolean hadDisplay = mHasDisplay; @@ -167,7 +174,7 @@ int getUpdatePeriod() { @Override public boolean isPlaying() { - boolean exoPlayerIsPlaying = mPlayer.getPlaybackState() == ExoPlayer.STATE_READY + boolean exoPlayerIsPlaying = mPlayer.getPlaybackState() == Player.STATE_READY && mPlayer.getPlayWhenReady(); return mInitialized && exoPlayerIsPlaying; } @@ -182,7 +189,6 @@ public long getCurrentPosition() { return mInitialized ? mPlayer.getCurrentPosition() : -1; } - @Override public void play() { if (!mInitialized || isPlaying()) { @@ -224,10 +230,10 @@ public Context getContext() { * * @return Returns true if uri represents a new media; false * otherwise. - * @see ExoPlayer#prepare(MediaSource) + * @see ExoPlayer#setMediaItem(MediaItem) */ public boolean setDataSource(Uri uri) { - if (mMediaSourceUri != null ? mMediaSourceUri.equals(uri) : uri == null) { + if (Objects.equals(mMediaSourceUri, uri)) { return false; } mMediaSourceUri = uri; @@ -235,48 +241,45 @@ public boolean setDataSource(Uri uri) { return true; } - public int getAudioStreamType() { - return mAudioStreamType; - } - - public void setAudioStreamType(@C.StreamType int audioStreamType) { - mAudioStreamType = audioStreamType; + public void setAudioAttributes(AudioAttributes audioAttributes) { + mAudioAttributes = audioAttributes; + if (mPlayer != null) { + mPlayer.setAudioAttributes(audioAttributes, /* handleAudioFocus= */ false); + } } /** - * Set {@link MediaSource} for {@link SimpleExoPlayer}. An app may override this method in order + * Set {@link MediaSource} for {@link ExoPlayer}. An app may override this method in order * to use different {@link MediaSource}. * @param uri The url of media source * @return MediaSource for the player */ public MediaSource onCreateMediaSource(Uri uri) { String userAgent = Util.getUserAgent(mContext, "ExoPlayerAdapter"); - return new ExtractorMediaSource(uri, - new DefaultDataSourceFactory(mContext, userAgent), - new DefaultExtractorsFactory(), - null, - null); + return new ProgressiveMediaSource.Factory( + new DefaultDataSource.Factory(mContext)) + .createMediaSource(MediaItem.fromUri(uri)); } private void prepareMediaForPlaying() { reset(); if (mMediaSourceUri != null) { MediaSource mediaSource = onCreateMediaSource(mMediaSourceUri); - mPlayer.prepare(mediaSource); + mPlayer.setMediaSource(mediaSource); + mPlayer.prepare(); } else { return; } - mPlayer.setAudioStreamType(mAudioStreamType); - mPlayer.setVideoListener(new SimpleExoPlayer.VideoListener() { - @Override - public void onVideoSizeChanged(int width, int height, int unappliedRotationDegrees, - float pixelWidthHeightRatio) { - getCallback().onVideoSizeChanged(ExoPlayerAdapter.this, width, height); - } + mPlayer.setAudioAttributes(mAudioAttributes, /* handleAudioFocus= */ false); + mPlayer.addListener(new Player.Listener() { @Override - public void onRenderedFirstFrame() { + public void onVideoSizeChanged(VideoSize videoSize) { + getCallback().onVideoSizeChanged( + ExoPlayerAdapter.this, + videoSize.width, + videoSize.height); } }); notifyBufferingStartEnd(); @@ -315,16 +318,16 @@ public void surfaceDestroyed(SurfaceHolder surfaceHolder) { // ExoPlayer Event Listeners @Override - public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { + public void onPlaybackStateChanged(int playbackState) { mBufferingStart = false; - if (playbackState == ExoPlayer.STATE_READY && !mInitialized) { + if (playbackState == Player.STATE_READY && !mInitialized) { mInitialized = true; if (mSurfaceHolderGlueHost == null || mHasDisplay) { getCallback().onPreparedStateChanged(ExoPlayerAdapter.this); } - } else if (playbackState == ExoPlayer.STATE_BUFFERING) { + } else if (playbackState == Player.STATE_BUFFERING) { mBufferingStart = true; - } else if (playbackState == ExoPlayer.STATE_ENDED) { + } else if (playbackState == Player.STATE_ENDED) { getCallback().onPlayStateChanged(ExoPlayerAdapter.this); getCallback().onPlayCompleted(ExoPlayerAdapter.this); } @@ -332,26 +335,28 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { } @Override - public void onPlayerError(ExoPlaybackException error) { - getCallback().onError(ExoPlayerAdapter.this, error.type, - mContext.getString(R.string.lb_media_player_error, - error.type, - error.rendererIndex)); - } + public void onPlayerError(PlaybackException error) { + int rendererIndex = -1; // Default value if not available - @Override - public void onLoadingChanged(boolean isLoading) { + if (error instanceof ExoPlaybackException exoError) { + rendererIndex = exoError.rendererIndex; + } + getCallback().onError(ExoPlayerAdapter.this, error.errorCode, + mContext.getString(androidx.leanback.R.string.lb_media_player_error, + error.errorCode, + rendererIndex)); } @Override - public void onTimelineChanged(Timeline timeline, Object manifest) { + public void onTimelineChanged(Timeline timeline, int reason) { } @Override - public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { + public void onTracksChanged(Tracks tracks) { } @Override - public void onPositionDiscontinuity() { + public void onPositionDiscontinuity(Player.PositionInfo oldPosition, + Player.PositionInfo newPosition, int reason) { } -} +} \ No newline at end of file diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicConsumptionExampleFragment.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicConsumptionExampleFragment.java index 10772bcf3..9a2d1694e 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicConsumptionExampleFragment.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicConsumptionExampleFragment.java @@ -162,11 +162,11 @@ protected void onBindMediaDetails(ViewHolder vh, Object item) { } else { Context context = vh.getMediaItemNumberView().getContext(); vh.getMediaItemNumberView().setTextAppearance(context, - R.style.TextAppearance_Leanback_PlaybackMediaItemNumber); + androidx.leanback.R.style.TextAppearance_Leanback_PlaybackMediaItemNumber); vh.getMediaItemNameView().setTextAppearance(context, - R.style.TextAppearance_Leanback_PlaybackMediaItemName); + androidx.leanback.R.style.TextAppearance_Leanback_PlaybackMediaItemName); vh.getMediaItemDurationView().setTextAppearance(context, - R.style.TextAppearance_Leanback_PlaybackMediaItemDuration); + androidx.leanback.R.style.TextAppearance_Leanback_PlaybackMediaItemDuration); } } } diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicPlaybackService.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicPlaybackService.java index 198cad528..e0f5df011 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicPlaybackService.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/MusicPlaybackService.java @@ -372,7 +372,7 @@ private void updateMediaSessionIntent() { } Intent nowPlayIntent = new Intent(getApplicationContext(), MusicExampleActivity.class); PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, nowPlayIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); mMediaSession.setSessionActivity(pi); } @@ -496,7 +496,7 @@ void setUpAsForeground(String text) { Intent notificationIntent = new Intent(this, MusicExampleActivity.class); PendingIntent pi = PendingIntent.getActivity(getApplicationContext(), 0, notificationIntent, - PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); if (shouldCreateNowPlayingChannel()) { createNowPlayingChannel(); @@ -539,6 +539,12 @@ private NotificationManager getNotificationManager() { return mNotificationManager; } + @Override + public boolean onUnbind(Intent intent) { + stopSelf(); + return super.onUnbind(intent); + } + @Override public void onDestroy() { super.onDestroy(); diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/VideoConsumptionExampleWithExoPlayerFragment.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/VideoConsumptionExampleWithExoPlayerFragment.java index 5ec37e8dc..5a62ac5d6 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/VideoConsumptionExampleWithExoPlayerFragment.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/media/VideoConsumptionExampleWithExoPlayerFragment.java @@ -61,7 +61,6 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ExoPlayerAdapter playerAdapter = new ExoPlayerAdapter(getActivity()); - playerAdapter.setAudioStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); mMediaPlayerGlue = new VideoMediaPlayerGlue(getActivity(), playerAdapter); mMediaPlayerGlue.setHost(mHost); AudioManager audioManager = (AudioManager) getActivity() diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/FullWidthDetailsPresenter.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/FullWidthDetailsPresenter.java index 78160aa67..4bfe33ac7 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/FullWidthDetailsPresenter.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/FullWidthDetailsPresenter.java @@ -39,11 +39,11 @@ protected RowPresenter.ViewHolder createRowViewHolder(ViewGroup parent) { RowPresenter.ViewHolder viewHolder = super.createRowViewHolder(parent); View actionsView = viewHolder.view. - findViewById(R.id.details_overview_actions_background); + findViewById(androidx.leanback.R.id.details_overview_actions_background); actionsView.setBackgroundColor(SampleApplication.getInstance(). getColor(R.color.detail_view_actionbar_background)); - View detailsView = viewHolder.view.findViewById(R.id.details_frame); + View detailsView = viewHolder.view.findViewById(androidx.leanback.R.id.details_frame); detailsView.setBackgroundColor( SampleApplication.getInstance().getResources().getColor(R.color.detail_view_background)); return viewHolder; diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/VideoCardPresenter.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/VideoCardPresenter.java index f35d49470..6404009f9 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/VideoCardPresenter.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/ui/VideoCardPresenter.java @@ -131,7 +131,7 @@ private void updateCardBackgroundColor(ImageCardView view, boolean selected) { int color = selected ? sSelectedBackgroundColor : sDefaultBackgroundColor; view.setBackgroundColor(color); - view.findViewById(R.id.info_field).setBackgroundColor(color); + view.findViewById(androidx.leanback.R.id.info_field).setBackgroundColor(color); } /** diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/viewmodel/VideosViewModel.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/viewmodel/VideosViewModel.java index 07877fe11..81418bec0 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/viewmodel/VideosViewModel.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/room/viewmodel/VideosViewModel.java @@ -17,14 +17,13 @@ package androidx.leanback.leanbackshowcase.app.room.viewmodel; import android.app.Application; -import androidx.arch.core.util.Function; +import androidx.leanback.leanbackshowcase.app.room.db.entity.CategoryEntity; +import androidx.leanback.leanbackshowcase.app.room.db.entity.VideoEntity; +import androidx.leanback.leanbackshowcase.app.room.db.repo.VideosRepository; import androidx.lifecycle.AndroidViewModel; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.Transformations; -import androidx.leanback.leanbackshowcase.app.room.db.repo.VideosRepository; -import androidx.leanback.leanbackshowcase.app.room.db.entity.CategoryEntity; -import androidx.leanback.leanbackshowcase.app.room.db.entity.VideoEntity; import java.util.List; import javax.inject.Inject; @@ -51,33 +50,18 @@ public VideosViewModel(Application application, VideosRepository repository) { mAllCategories = mRepository.getAllCategories(); - mSearchResults = Transformations.switchMap( - mQuery, new Function>>() { - @Override - public LiveData> apply(final String queryMessage) { - return mRepository.getSearchResult(queryMessage); - } - }); - + mSearchResults = Transformations.switchMap(mQuery, mRepository::getSearchResult); - mVideoById = Transformations.switchMap( - mVideoId, new Function>() { - @Override - public LiveData apply(final Long videoId) { - return mRepository.getVideoById(videoId); - } - }); + mVideoById = Transformations.switchMap(mVideoId, mRepository::getVideoById); /** * Using switch map function to react to the change of observed variable, the benefits of * this mapping method is we don't have to re-create the live data every time. */ - mAllVideosByCategory = Transformations.switchMap(mVideoCategory, new Function>>() { - @Override - public LiveData> apply(String category) { - return mRepository.getVideosInSameCategoryLiveData(category); - } - }); + mAllVideosByCategory = Transformations.switchMap( + mVideoCategory, + mRepository::getVideosInSameCategoryLiveData + ); } public LiveData> getSearchResult() { diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/PublishChannelFragment.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/PublishChannelFragment.java index 1b41f01bc..dc8fd75f2 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/PublishChannelFragment.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/PublishChannelFragment.java @@ -100,7 +100,7 @@ private static void addCheckedAction(List actions, */ @Override public int onProvideTheme() { - return R.style.Theme_Leanback_GuidedStep; + return androidx.leanback.preference.R.style.Theme_Leanback_GuidedStep; } /** diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/VideoContentCardPresenter.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/VideoContentCardPresenter.java index 642ed5bb5..45532f4e7 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/VideoContentCardPresenter.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/app/rows/VideoContentCardPresenter.java @@ -60,7 +60,7 @@ private static void updateCardBackgroundColor(ImageCardView view, boolean select // Both background colors should be set because the view's background is temporarily visible // during animations. view.setBackgroundColor(color); - view.findViewById(R.id.info_field).setBackgroundColor(color); + view.findViewById(androidx.leanback.R.id.info_field).setBackgroundColor(color); } @Override diff --git a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/cards/presenters/SingleLineCardPresenter.java b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/cards/presenters/SingleLineCardPresenter.java index 4ec0acdf9..f5d859b12 100644 --- a/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/cards/presenters/SingleLineCardPresenter.java +++ b/LeanbackShowcase/app/src/main/java/androidx/leanback/leanbackshowcase/cards/presenters/SingleLineCardPresenter.java @@ -33,8 +33,8 @@ public SingleLineCardPresenter(Context context) { @Override public void onBindViewHolder(Card card, ImageCardView cardView) { super.onBindViewHolder(card, cardView); - TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(R.styleable.lbImageCardView); - android.util.Log.d("SHAAN", "lbImageCardViewType ="+typedArray.getInt(R.styleable.lbImageCardView_lbImageCardViewType, -1)); + TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(androidx.leanback.R.styleable.lbImageCardView); + android.util.Log.d("SHAAN", "lbImageCardViewType ="+typedArray.getInt(androidx.leanback.R.styleable.lbImageCardView_lbImageCardViewType, -1)); cardView.setInfoAreaBackgroundColor(card.getFooterColor()); } diff --git a/LeanbackShowcase/build.gradle b/LeanbackShowcase/build.gradle index 56f373eaf..b70e6c038 100644 --- a/LeanbackShowcase/build.gradle +++ b/LeanbackShowcase/build.gradle @@ -16,38 +16,10 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. -buildscript { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.2.1' - classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.10' - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files - } +plugins { + alias(libs.plugins.android.application) apply false + alias(libs.plugins.kotlin.android) apply false + alias(libs.plugins.kotlin.kapt) apply false } -allprojects { - repositories { - jcenter() - google() - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} - -ext { - buildToolsVersion = "30.0.2" - supportLibVersion = "1.0.0" - daggerVersion = "2.21" - materialVersion="1.0.0" - testVersion = "1.2.0" - espressoVersion = "3.1.0" - archLifecycleVersion = "2.0.0" - archRoomVersion = "2.0.0-rc01" -} diff --git a/LeanbackShowcase/gradle.properties b/LeanbackShowcase/gradle.properties index 5465fec0e..1a8274341 100644 --- a/LeanbackShowcase/gradle.properties +++ b/LeanbackShowcase/gradle.properties @@ -1,2 +1,3 @@ android.enableJetifier=true -android.useAndroidX=true \ No newline at end of file +android.useAndroidX=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/LeanbackShowcase/gradle/libs.versions.toml b/LeanbackShowcase/gradle/libs.versions.toml new file mode 100644 index 000000000..77215ebf1 --- /dev/null +++ b/LeanbackShowcase/gradle/libs.versions.toml @@ -0,0 +1,64 @@ +[versions] +appcompat = "1.7.0" +cardview = "1.0.0" +converter-gson = "2.11.0" +dagger = "2.21" +espresso-core = "3.6.1" +glide = "4.15.1" +gson = "2.12.1" +junit = "4.13.2" +kotlin-android = "2.1.10" +android-gradle-plugin = "8.9.1" +leanback = "1.0.0" +legacy-preference-v14 = "1.0.0" +lifecycle-extensions = "2.2.0" +lifecycle-version = "2.8.7" +material = "1.12.0" +media3-exoplayer = "1.6.1" +palette-ktx = "1.0.0" +preference-ktx = "1.2.1" +recyclerview = "1.4.0" +room-runtime = "2.7.0" +runner = "1.6.1" +androidx-junit = "1.2.1" +tvprovider = "1.0.0" + + +[libraries] +androidx-espresso-contrib = { module = "androidx.test.espresso:espresso-contrib", version.ref = "espresso-core" } +androidx-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso-core" } +androidx-lifecycle-compiler = { module = "androidx.lifecycle:lifecycle-compiler", version.ref = "lifecycle-version" } +androidx-lifecycle-extensions = { module = "androidx.lifecycle:lifecycle-extensions", version.ref = "lifecycle-extensions" } +androidx-media3-exoplayer = { module = "androidx.media3:media3-exoplayer", version.ref = "media3-exoplayer" } +androidx-palette-ktx = { module = "androidx.palette:palette-ktx", version.ref = "palette-ktx" } +androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room-runtime" } +androidx-rules = { module = "androidx.test:rules", version.ref = "runner" } +androidx-runner = { module = "androidx.test:runner", version.ref = "runner" } +androidx-junit = { module = "androidx.test.ext:junit", version.ref = "androidx-junit" } +androidx-tvprovider = { module = "androidx.tvprovider:tvprovider", version.ref = "tvprovider" } +appcompat = { module = "androidx.appcompat:appcompat", version.ref = "appcompat" } +cardview = { module = "androidx.cardview:cardview", version.ref = "cardview" } +converter-gson = { module = "com.squareup.retrofit2:converter-gson", version.ref = "converter-gson" } +dagger = { module = "com.google.dagger:dagger", version.ref = "dagger" } +dagger-android = { module = "com.google.dagger:dagger-android", version.ref = "dagger" } +dagger-android-processor = { module = "com.google.dagger:dagger-android-processor", version.ref = "dagger" } +dagger-android-support = { module = "com.google.dagger:dagger-android-support", version.ref = "dagger" } +dagger-compiler = { module = "com.google.dagger:dagger-compiler", version.ref = "dagger" } +glide = { module = "com.github.bumptech.glide:glide", version.ref = "glide" } +gson = { module = "com.google.code.gson:gson", version.ref = "gson" } + +junit = { module = "junit:junit", version.ref = "junit" } +leanback = { module = "androidx.leanback:leanback", version.ref = "leanback" } +leanback-preference = { module = "androidx.leanback:leanback-preference", version.ref = "leanback" } +legacy-preference-v14 = { module = "androidx.legacy:legacy-preference-v14", version.ref = "legacy-preference-v14" } +material = { module = "com.google.android.material:material", version.ref = "material" } +preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preference-ktx" } +recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" } +retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "converter-gson" } +room-runtime = { module = "androidx.room:room-runtime", version.ref = "room-runtime" } + + +[plugins] +android-application = { id = "com.android.application", version.ref = "android-gradle-plugin" } +kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin-android" } +kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin-android" } \ No newline at end of file diff --git a/LeanbackShowcase/gradle/wrapper/gradle-wrapper.properties b/LeanbackShowcase/gradle/wrapper/gradle-wrapper.properties index 3719f9494..bcd613e48 100644 --- a/LeanbackShowcase/gradle/wrapper/gradle-wrapper.properties +++ b/LeanbackShowcase/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Jun 03 17:11:19 PDT 2019 +#Thu Apr 17 13:28:12 MSK 2025 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip diff --git a/LeanbackShowcase/settings.gradle b/LeanbackShowcase/settings.gradle index e7b4def49..907440155 100644 --- a/LeanbackShowcase/settings.gradle +++ b/LeanbackShowcase/settings.gradle @@ -1 +1,18 @@ +pluginManagement { + repositories { + gradlePluginPortal() + google() + mavenCentral() + } +} +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "LeanbackShowcase" + include ':app'