diff --git a/app/build.gradle b/app/build.gradle index cba54cd5..1155d00a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,15 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 31 + buildToolsVersion "30.0.3" defaultConfig { applicationId "com.example.android.classicalmusicquiz" - minSdkVersion 15 - targetSdkVersion 25 + minSdkVersion 17 + targetSdkVersion 31 versionCode 1 versionName "1.0" - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' } buildTypes { release { @@ -20,12 +20,12 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.google.android.exoplayer:exoplayer:r2.2.0' - compile 'com.android.support:appcompat-v7:25.3.0' - testCompile 'junit:junit:4.12' - compile 'com.android.support.constraint:constraint-layout:1.0.2' + implementation 'com.google.android.exoplayer:exoplayer:2.16.1' + implementation 'androidx.appcompat:appcompat:1.4.1' + testImplementation 'junit:junit:4.13.2' + implementation 'androidx.constraintlayout:constraintlayout:2.1.3' } diff --git a/app/src/androidTest/java/com/example/android/classicalmusicquiz/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/android/classicalmusicquiz/ExampleInstrumentedTest.java index 1b90a51c..25a97ed4 100644 --- a/app/src/androidTest/java/com/example/android/classicalmusicquiz/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/com/example/android/classicalmusicquiz/ExampleInstrumentedTest.java @@ -1,8 +1,8 @@ package com.example.android.classicalmusicquiz; import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.runner.AndroidJUnit4; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b25b2a08..2ca8df66 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,7 +22,8 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> - + @@ -31,7 +32,8 @@ - + diff --git a/app/src/main/java/com/example/android/classicalmusicquiz/MainActivity.java b/app/src/main/java/com/example/android/classicalmusicquiz/MainActivity.java index 48060b63..bcbbf6b0 100644 --- a/app/src/main/java/com/example/android/classicalmusicquiz/MainActivity.java +++ b/app/src/main/java/com/example/android/classicalmusicquiz/MainActivity.java @@ -18,7 +18,7 @@ import android.content.Intent; import android.os.Bundle; -import android.support.v7.app.AppCompatActivity; +import androidx.appcompat.app.AppCompatActivity; import android.view.View; import android.widget.TextView; diff --git a/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java b/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java index 7b4623f8..9f01e61b 100644 --- a/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java +++ b/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java @@ -21,58 +21,57 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; +import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.PorterDuff; +import android.graphics.drawable.BitmapDrawable; import android.net.Uri; import android.os.Bundle; import android.os.Handler; -import android.support.v4.content.ContextCompat; -import android.support.v4.media.session.MediaButtonReceiver; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.app.NotificationCompat; import android.view.View; import android.widget.Button; import android.widget.Toast; +import androidx.core.content.ContextCompat; +import androidx.appcompat.app.AppCompatActivity; +import androidx.media.app.NotificationCompat; +import androidx.media.session.MediaButtonReceiver; +import androidx.core.app.NotificationCompat.Builder; + 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.LoadControl; -import com.google.android.exoplayer2.SimpleExoPlayer; -import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.Player; 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.source.ProgressiveMediaSource; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelector; -import com.google.android.exoplayer2.ui.SimpleExoPlayerView; +import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Util; import java.util.ArrayList; -public class QuizActivity extends AppCompatActivity implements View.OnClickListener, ExoPlayer.EventListener { +public class QuizActivity extends AppCompatActivity implements View.OnClickListener, Player.Listener { private static final int CORRECT_ANSWER_DELAY_MILLIS = 1000; private static final String REMAINING_SONGS_KEY = "remaining_songs"; - private static final String TAG = QuizActivity.class.getSimpleName(); private int[] mButtonIDs = {R.id.buttonA, R.id.buttonB, R.id.buttonC, R.id.buttonD}; private ArrayList mRemainingSampleIDs; private ArrayList mQuestionSampleIDs; + private static final String TAG = QuizActivity.class.getSimpleName(); private int mAnswerSampleID; private int mCurrentScore; private int mHighScore; private Button[] mButtons; - private SimpleExoPlayer mExoPlayer; - private SimpleExoPlayerView mPlayerView; + private ExoPlayer mExoPlayer; + private PlayerView mPlayerView; private static MediaSessionCompat mMediaSession; - private PlaybackStateCompat.Builder mStateBuilder; + public static PlaybackStateCompat.Builder mStateBuilder; private NotificationManager mNotificationManager; @@ -83,8 +82,7 @@ protected void onCreate(Bundle savedInstanceState) { // Initialize the player view. - mPlayerView = (SimpleExoPlayerView) findViewById(R.id.playerView); - + mPlayerView = (PlayerView) findViewById(R.id.playerView); boolean isNewGame = !getIntent().hasExtra(REMAINING_SONGS_KEY); @@ -106,8 +104,7 @@ protected void onCreate(Bundle savedInstanceState) { mAnswerSampleID = QuizUtils.getCorrectAnswerID(mQuestionSampleIDs); // Load the question mark as the background image until the user answers the question. - mPlayerView.setDefaultArtwork(BitmapFactory.decodeResource - (getResources(), R.drawable.question_mark)); + mPlayerView.setDefaultArtwork(new BitmapDrawable(BitmapFactory.decodeResource(getResources(), R.drawable.question_mark))); // If there is only one answer left, end the game. if (mQuestionSampleIDs.size() < 2) { @@ -118,7 +115,6 @@ protected void onCreate(Bundle savedInstanceState) { // Initialize the buttons with the composers names. mButtons = initializeButtons(mQuestionSampleIDs); - // Initialize the Media Session. initializeMediaSession(); Sample answerSample = Sample.getSampleByID(this, mAnswerSampleID); @@ -133,6 +129,7 @@ protected void onCreate(Bundle savedInstanceState) { initializePlayer(Uri.parse(answerSample.getUri())); } + /** * Initializes the Media Session to be enabled with media buttons, transport controls, callbacks * and media controller. @@ -169,6 +166,7 @@ private void initializeMediaSession() { } + /** * Initializes the button to the correct views, and sets the text to the composers names, * and set's the OnClick listener to the buttons. @@ -192,12 +190,13 @@ private Button[] initializeButtons(ArrayList answerSampleIDs) { /** - * Shows Media Style notification, with actions that depend on the current MediaSession + * Shows Media Style notification, with an action that depends on the current MediaSession * PlaybackState. * @param state The PlaybackState of the MediaSession. */ private void showNotification(PlaybackStateCompat state) { - NotificationCompat.Builder builder = new NotificationCompat.Builder(this); + //no channelId created as it's not part of our course + androidx.core.app.NotificationCompat.Builder builder = new Builder(this,""); int icon; String play_pause; @@ -210,12 +209,12 @@ private void showNotification(PlaybackStateCompat state) { } - NotificationCompat.Action playPauseAction = new NotificationCompat.Action( + androidx.core.app.NotificationCompat.Action playPauseAction =new androidx.core.app.NotificationCompat.Action( icon, play_pause, MediaButtonReceiver.buildMediaButtonPendingIntent(this, PlaybackStateCompat.ACTION_PLAY_PAUSE)); - NotificationCompat.Action restartAction = new android.support.v4.app.NotificationCompat + androidx.core.app.NotificationCompat.Action restartAction =new androidx.core.app.NotificationCompat .Action(R.drawable.exo_controls_previous, getString(R.string.restart), MediaButtonReceiver.buildMediaButtonPendingIntent (this, PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS)); @@ -227,7 +226,7 @@ private void showNotification(PlaybackStateCompat state) { .setContentText(getString(R.string.notification_text)) .setContentIntent(contentPendingIntent) .setSmallIcon(R.drawable.ic_music_note) - .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) + .setVisibility(androidx.core.app.NotificationCompat.VISIBILITY_PUBLIC) .addAction(restartAction) .addAction(playPauseAction) .setStyle(new NotificationCompat.MediaStyle() @@ -249,16 +248,22 @@ private void initializePlayer(Uri mediaUri) { // Create an instance of the ExoPlayer. TrackSelector trackSelector = new DefaultTrackSelector(); LoadControl loadControl = new DefaultLoadControl(); - mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl); + mExoPlayer = new ExoPlayer.Builder(this) + .setTrackSelector(trackSelector) + .setLoadControl(loadControl).build(); mPlayerView.setPlayer(mExoPlayer); // Set the ExoPlayer.EventListener to this activity. mExoPlayer.addListener(this); - + // Prepare the MediaSource. String userAgent = Util.getUserAgent(this, "ClassicalMusicQuiz"); - MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory( - this, userAgent), new DefaultExtractorsFactory(), null, null); + + DefaultDataSourceFactory defaultDataSourceFactory = new DefaultDataSourceFactory(this, userAgent); + DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory(); + MediaSource mediaSource = new ProgressiveMediaSource.Factory(defaultDataSourceFactory, + defaultExtractorsFactory).createMediaSource(mediaUri); + mExoPlayer.prepare(mediaSource); mExoPlayer.setPlayWhenReady(true); } @@ -330,12 +335,14 @@ public void run() { }, CORRECT_ANSWER_DELAY_MILLIS); } + /** * Disables the buttons and changes the background colors and player art to * show the correct answer. */ private void showCorrectAnswer() { - mPlayerView.setDefaultArtwork(Sample.getComposerArtBySampleID(this, mAnswerSampleID)); + Bitmap bitmap=Sample.getComposerArtBySampleID(this, mAnswerSampleID); + mPlayerView.setDefaultArtwork(new BitmapDrawable(bitmap)); for (int i = 0; i < mQuestionSampleIDs.size(); i++) { int buttonSampleID = mQuestionSampleIDs.get(i); @@ -366,21 +373,8 @@ protected void onDestroy() { mMediaSession.setActive(false); } - - // ExoPlayer Event Listeners - - @Override - public void onTimelineChanged(Timeline timeline, Object manifest) { - } - - @Override - public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) { - } - - @Override - public void onLoadingChanged(boolean isLoading) { - } + // ExoPlayer Event Listener /** * Method that is called when the ExoPlayer state changes. Used to update the MediaSession * PlayBackState to keep in sync, and post the media notification. @@ -390,10 +384,10 @@ public void onLoadingChanged(boolean isLoading) { */ @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { - if((playbackState == ExoPlayer.STATE_READY) && playWhenReady){ + if ((playbackState == ExoPlayer.STATE_READY) && playWhenReady) { mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING, mExoPlayer.getCurrentPosition(), 1f); - } else if((playbackState == ExoPlayer.STATE_READY)){ + } else if ((playbackState == ExoPlayer.STATE_READY)) { mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED, mExoPlayer.getCurrentPosition(), 1f); } @@ -401,18 +395,10 @@ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { showNotification(mStateBuilder.build()); } - @Override - public void onPlayerError(ExoPlaybackException error) { - } - - @Override - public void onPositionDiscontinuity() { - } - /** * Media Session Callbacks, where all external clients control the player. */ - private class MySessionCallback extends MediaSessionCompat.Callback { + public class MySessionCallback extends MediaSessionCompat.Callback { @Override public void onPlay() { mExoPlayer.setPlayWhenReady(true); diff --git a/app/src/main/java/com/example/android/classicalmusicquiz/Sample.java b/app/src/main/java/com/example/android/classicalmusicquiz/Sample.java index 610a89f4..7a42b0f9 100644 --- a/app/src/main/java/com/example/android/classicalmusicquiz/Sample.java +++ b/app/src/main/java/com/example/android/classicalmusicquiz/Sample.java @@ -16,6 +16,8 @@ * limitations under the License. */ +import static com.google.android.exoplayer2.upstream.DataSourceUtil.closeQuietly; + import android.content.Context; import android.content.res.AssetManager; import android.graphics.Bitmap; @@ -30,6 +32,7 @@ import com.google.android.exoplayer2.upstream.DefaultDataSource; import com.google.android.exoplayer2.util.Util; +import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -182,7 +185,7 @@ private static JsonReader readJSONFile(Context context) throws IOException { } String userAgent = Util.getUserAgent(context, "ClassicalMusicQuiz"); - DataSource dataSource = new DefaultDataSource(context, null, userAgent, false); + DataSource dataSource = new DefaultDataSource(context, userAgent,1000,1000, false); DataSpec dataSpec = new DataSpec(Uri.parse(uri)); InputStream inputStream = new DataSourceInputStream(dataSource, dataSpec); @@ -190,7 +193,7 @@ private static JsonReader readJSONFile(Context context) throws IOException { try { reader = new JsonReader(new InputStreamReader(inputStream, "UTF-8")); } finally { - Util.closeQuietly(dataSource); + closeQuietly(dataSource); } return reader; diff --git a/app/src/main/res/drawable/ic_music_note.xml b/app/src/main/res/drawable/ic_music_note.xml index 736c004e..c6dae872 100644 --- a/app/src/main/res/drawable/ic_music_note.xml +++ b/app/src/main/res/drawable/ic_music_note.xml @@ -1,9 +1,9 @@ + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> - + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index ce372fcb..da130a9b 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -11,7 +11,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.--> - - + diff --git a/app/src/main/res/layout/activity_quiz.xml b/app/src/main/res/layout/activity_quiz.xml index 29c580ce..41d436db 100644 --- a/app/src/main/res/layout/activity_quiz.xml +++ b/app/src/main/res/layout/activity_quiz.xml @@ -12,7 +12,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.--> - - - - + diff --git a/app/src/main/res/layout/exo_playback_control_view.xml b/app/src/main/res/layout/exo_playback_control_view.xml index b054fe67..97c2be42 100644 --- a/app/src/main/res/layout/exo_playback_control_view.xml +++ b/app/src/main/res/layout/exo_playback_control_view.xml @@ -1,12 +1,9 @@