diff --git a/app/build.gradle b/app/build.gradle old mode 100644 new mode 100755 index cba54cd5..819b27ad --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 25 - buildToolsVersion "25.0.2" + compileSdkVersion 27 + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.example.android.classicalmusicquiz" minSdkVersion 15 - targetSdkVersion 25 + targetSdkVersion 27 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -20,12 +20,13 @@ 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('com.android.support.test.espresso:espresso-core:2.2.2', { 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.8.0' + //noinspection GradleCompatible + implementation 'com.android.support:appcompat-v7:27.1.1' + testImplementation 'junit:junit:4.12' + implementation 'com.android.support.constraint:constraint-layout:1.1.0' } diff --git a/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java b/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java old mode 100644 new mode 100755 index 0e47cf46..8ba1e00e --- a/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java +++ b/app/src/main/java/com/example/android/classicalmusicquiz/QuizActivity.java @@ -17,15 +17,30 @@ package com.example.android.classicalmusicquiz; import android.content.Intent; +import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.PorterDuff; +import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.support.v4.content.ContextCompat; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.Button; -import android.widget.ImageView; +import android.widget.Toast; + +import com.google.android.exoplayer2.DefaultLoadControl; +import com.google.android.exoplayer2.ExoPlayerFactory; +import com.google.android.exoplayer2.LoadControl; +import com.google.android.exoplayer2.SimpleExoPlayer; +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.trackselection.DefaultTrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelector; +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; @@ -40,6 +55,8 @@ public class QuizActivity extends AppCompatActivity implements View.OnClickListe private int mCurrentScore; private int mHighScore; private Button[] mButtons; + private PlayerView mPlayerView; + private SimpleExoPlayer mExoPlayer; @Override @@ -47,8 +64,8 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); - // TODO (2): Replace the ImageView with the SimpleExoPlayerView, and remove the method calls on the composerView. - ImageView composerView = (ImageView) findViewById(R.id.composerView); + // COMPLETED (2): Replace the ImageView with the PlayerView, and remove the method calls on the composerView. + mPlayerView = (PlayerView) findViewById(R.id.playerView); boolean isNewGame = !getIntent().hasExtra(REMAINING_SONGS_KEY); @@ -69,9 +86,9 @@ protected void onCreate(Bundle savedInstanceState) { mQuestionSampleIDs = QuizUtils.generateQuestion(mRemainingSampleIDs); mAnswerSampleID = QuizUtils.getCorrectAnswerID(mQuestionSampleIDs); - // TODO (3): Replace the default artwork in the SimpleExoPlayerView with the question mark drawable. + // COMPLETED (3): Replace the default artwork in the PlayerView with the question mark drawable. // Load the image of the composer for the answer into the ImageView. - composerView.setImageBitmap(Sample.getComposerArtBySampleID(this, mAnswerSampleID)); + mPlayerView.setDefaultArtwork(BitmapFactory.decodeResource(getResources(), R.drawable.question_mark)); // If there is only one answer left, end the game. if (mQuestionSampleIDs.size() < 2) { @@ -82,16 +99,22 @@ protected void onCreate(Bundle savedInstanceState) { // Initialize the buttons with the composers names. mButtons = initializeButtons(mQuestionSampleIDs); - // TODO (4): Create a Sample object using the Sample.getSampleByID() method and passing in mAnswerSampleID; - // TODO (5): Create a method called initializePlayer() that takes a Uri as an argument and call it here, passing in the Sample URI. - + // COMPLETED (4): Create a Sample object using the Sample.getSampleByID() method and passing in mAnswerSampleID; + Sample answerSample = Sample.getSampleByID(this, mAnswerSampleID); + if(answerSample == null) { + Toast.makeText(this, getString(R.string.sample_not_found_error), + Toast.LENGTH_SHORT).show(); + return; + } + // COMPLETED (5): Create a method called initializePlayer() that takes a Uri as an argument and call it here, passing in the Sample URI. + initializePlayer(Uri.parse(answerSample.getUri())); } // In initializePayer - // TODO (6): Instantiate a SimpleExoPlayer object using DefaultTrackSelector and DefaultLoadControl. - // TODO (7): Prepare the MediaSource using DefaultDataSourceFactory and DefaultExtractorsFactory, as well as the Sample URI you passed in. - // TODO (8): Prepare the ExoPlayer with the MediaSource, start playing the sample and set the SimpleExoPlayer to the SimpleExoPlayerView. + // COMPLETED (6): Instantiate a SimpleExoPlayer object using DefaultTrackSelector and DefaultLoadControl. + // COMPLETED (7): Prepare the MediaSource using DefaultDataSourceFactory and DefaultExtractorsFactory, as well as the Sample URI you passed in. + // COMPLETED (8): Prepare the ExoPlayer with the MediaSource, start playing the sample and set the SimpleExoPlayer to the PlayerView. /** @@ -115,6 +138,26 @@ private Button[] initializeButtons(ArrayList answerSampleIDs) { return buttons; } + private void initializePlayer(Uri mediaUri) { + if(mExoPlayer == null) { + TrackSelector trackSelector = new DefaultTrackSelector(); + LoadControl loadControl = new DefaultLoadControl(); + mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl); + mPlayerView.setPlayer(mExoPlayer); + + String userAgent = Util.getUserAgent(this, "ClassicalMusicQuiz"); + MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory( + this, userAgent), new DefaultExtractorsFactory(), null, null); + mExoPlayer.prepare(mediaSource); + mExoPlayer.setPlayWhenReady(true); + } + } + + private void releasePlayer() { + mExoPlayer.stop(); + mExoPlayer.release(); + mExoPlayer = null; + } /** * The OnClick method for all of the answer buttons. The method uses the index of the button @@ -161,7 +204,8 @@ public void onClick(View v) { handler.postDelayed(new Runnable() { @Override public void run() { - // TODO (9): Stop the playback when you go to the next question. + // COMPLETED (9): Stop the playback when you go to the next question. + mExoPlayer.stop(); Intent nextQuestionIntent = new Intent(QuizActivity.this, QuizActivity.class); nextQuestionIntent.putExtra(REMAINING_SONGS_KEY, mRemainingSampleIDs); finish(); @@ -178,8 +222,10 @@ private void showCorrectAnswer() { for (int i = 0; i < mQuestionSampleIDs.size(); i++) { int buttonSampleID = mQuestionSampleIDs.get(i); - // TODO (10): Change the default artwork in the SimpleExoPlayerView to show the picture of the composer, when the user has answered the question. + // COMPLETED (10): Change the default artwork in the PlayerView to show the picture of the composer, when the user has answered the question. mButtons[i].setEnabled(false); + mPlayerView.setDefaultArtwork(Sample.getComposerArtBySampleID(this, mAnswerSampleID)); + if (buttonSampleID == mAnswerSampleID) { mButtons[i].getBackground().setColorFilter(ContextCompat.getColor (this, android.R.color.holo_green_light), @@ -195,5 +241,11 @@ private void showCorrectAnswer() { } } - // TODO (11): Override onDestroy() to stop and release the player when the Activity is destroyed. + // COMPLETED (11): Override onDestroy() to stop and release the player when the Activity is destroyed. + + @Override + protected void onDestroy() { + super.onDestroy(); + releasePlayer(); + } } diff --git a/app/src/main/res/layout/activity_quiz.xml b/app/src/main/res/layout/activity_quiz.xml old mode 100644 new mode 100755 index db8287d0..733293bd --- a/app/src/main/res/layout/activity_quiz.xml +++ b/app/src/main/res/layout/activity_quiz.xml @@ -67,9 +67,9 @@ app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toBottomOf="@+id/buttonB" /> - - + + app:layout_constraintTop_toTopOf="parent"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml old mode 100644 new mode 100755 index 0bcf88fb..8ef2c74a --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -21,4 +21,5 @@ Can you guess the composer? Press play to hear the piece! Error loading one or more samples! + Sample Not Found diff --git a/build.gradle b/build.gradle old mode 100644 new mode 100755 index 1ea4bd05..44bac8f9 --- a/build.gradle +++ b/build.gradle @@ -3,9 +3,10 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:3.1.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -15,6 +16,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 7aff1511..5afc033d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Mar 07 11:16:24 PST 2017 +#Fri May 18 11:01:52 CDT 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip