Created
May 28, 2018 11:19
-
-
Save abusoid/f6642c655488355f58cd7dad631a0bc5 to your computer and use it in GitHub Desktop.
Miwok app Android Basics Nanodegree by Google
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<!-- Copyright (C) 2016 The Android Open Source Project | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
--> | |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:background="@color/tan_background" | |
android:orientation="vertical" | |
tools:context="com.example.android.miwok.MainActivity"> | |
<TextView | |
android:id="@+id/numbers" | |
style="@style/CategoryStyle" | |
android:background="@color/category_numbers" | |
android:text="@string/category_numbers" /> | |
<TextView | |
android:id="@+id/family" | |
style="@style/CategoryStyle" | |
android:background="@color/category_family" | |
android:text="@string/category_family" /> | |
<TextView | |
android:id="@+id/colors" | |
style="@style/CategoryStyle" | |
android:background="@color/category_colors" | |
android:text="@string/category_colors" /> | |
<TextView | |
android:id="@+id/phrases" | |
style="@style/CategoryStyle" | |
android:background="@color/category_phrases" | |
android:text="@string/category_phrases" /> | |
</LinearLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Context; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.ListView; | |
import java.util.ArrayList; | |
public class ColorsActivity extends AppCompatActivity { | |
/** Handles playback of all the sound files */ | |
private MediaPlayer mMediaPlayer; | |
/** Handles audio focus when playing a sound file */ | |
private AudioManager mAudioManager; | |
/** | |
* This listener gets triggered when the {@link MediaPlayer} has completed | |
* playing the audio file. | |
*/ | |
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() { | |
@Override | |
public void onCompletion(MediaPlayer mediaPlayer) { | |
// Now that the sound file has finished playing, release the media player resources. | |
releaseMediaPlayer(); | |
} | |
}; | |
/** | |
* This listener gets triggered whenever the audio focus changes | |
* (i.e., we gain or lose audio focus because of another app or device). | |
*/ | |
private AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { | |
@Override | |
public void onAudioFocusChange(int focusChange) { | |
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || | |
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { | |
// The AUDIOFOCUS_LOSS_TRANSIENT case means that we've lost audio focus for a | |
// short amount of time. The AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK case means that | |
// our app is allowed to continue playing sound but at a lower volume. We'll treat | |
// both cases the same way because our app is playing short sound files. | |
// Pause playback and reset player to the start of the file. That way, we can | |
// play the word from the beginning when we resume playback. | |
mMediaPlayer.pause(); | |
mMediaPlayer.seekTo(0); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { | |
// The AUDIOFOCUS_GAIN case means we have regained focus and can resume playback. | |
mMediaPlayer.start(); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { | |
// The AUDIOFOCUS_LOSS case means we've lost audio focus and | |
// Stop playback and clean up resources | |
releaseMediaPlayer(); | |
} | |
} | |
}; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.word_list); | |
// Create and setup the {@link AudioManager} to request audio focus | |
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); | |
// Create a list of words | |
final ArrayList<Word> words = new ArrayList<Word>(); | |
words.add(new Word("red", "weṭeṭṭi", R.drawable.color_red, R.raw.color_red)); | |
words.add(new Word("mustard yellow", "chiwiiṭә", R.drawable.color_mustard_yellow, | |
R.raw.color_mustard_yellow)); | |
words.add(new Word("dusty yellow", "ṭopiisә", R.drawable.color_dusty_yellow, | |
R.raw.color_dusty_yellow)); | |
words.add(new Word("green", "chokokki", R.drawable.color_green, R.raw.color_green)); | |
words.add(new Word("brown", "ṭakaakki", R.drawable.color_brown, R.raw.color_brown)); | |
words.add(new Word("gray", "ṭopoppi", R.drawable.color_gray, R.raw.color_gray)); | |
words.add(new Word("black", "kululli", R.drawable.color_black, R.raw.color_black)); | |
words.add(new Word("white", "kelelli", R.drawable.color_white, R.raw.color_white)); | |
// Create an {@link WordAdapter}, whose data source is a list of {@link Word}s. The | |
// adapter knows how to create list items for each item in the list. | |
WordAdapter adapter = new WordAdapter(this, words, R.color.category_colors); | |
// Find the {@link ListView} object in the view hierarchy of the {@link Activity}. | |
// There should be a {@link ListView} with the view ID called list, which is declared in the | |
// word_list.xml layout file. | |
ListView listView = (ListView) findViewById(R.id.list); | |
// Make the {@link ListView} use the {@link WordAdapter} we created above, so that the | |
// {@link ListView} will display list items for each {@link Word} in the list. | |
listView.setAdapter(adapter); | |
// Set a click listener to play the audio when the list item is clicked on | |
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
@Override | |
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { | |
// Release the media player if it currently exists because we are about to | |
// play a different sound file | |
releaseMediaPlayer(); | |
// Get the {@link Word} object at the given position the user clicked on | |
Word word = words.get(position); | |
// Request audio focus so in order to play the audio file. The app needs to play a | |
// short audio file, so we will request audio focus with a short amount of time | |
// with AUDIOFOCUS_GAIN_TRANSIENT. | |
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener, | |
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); | |
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { | |
// We have audio focus now. | |
// Create and setup the {@link MediaPlayer} for the audio resource associated | |
// with the current word | |
mMediaPlayer = MediaPlayer.create(ColorsActivity.this, word.getAudioResourceId()); | |
// Start the audio file | |
mMediaPlayer.start(); | |
// Setup a listener on the media player, so that we can stop and release the | |
// media player once the sound has finished playing. | |
mMediaPlayer.setOnCompletionListener(mCompletionListener); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
// When the activity is stopped, release the media player resources because we won't | |
// be playing any more sounds. | |
releaseMediaPlayer(); | |
} | |
/** | |
* Clean up the media player by releasing its resources. | |
*/ | |
private void releaseMediaPlayer() { | |
// If the media player is not null, then it may be currently playing a sound. | |
if (mMediaPlayer != null) { | |
// Regardless of the current state of the media player, release its resources | |
// because we no longer need it. | |
mMediaPlayer.release(); | |
// Set the media player back to null. For our code, we've decided that | |
// setting the media player to null is an easy way to tell that the media player | |
// is not configured to play an audio file at the moment. | |
mMediaPlayer = null; | |
// Regardless of whether or not we were granted audio focus, abandon it. This also | |
// unregisters the AudioFocusChangeListener so we don't get anymore callbacks. | |
mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Context; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.ListView; | |
import java.util.ArrayList; | |
public class FamilyActivity extends AppCompatActivity { | |
/** Handles playback of all the sound files */ | |
private MediaPlayer mMediaPlayer; | |
/** Handles audio focus when playing a sound file */ | |
private AudioManager mAudioManager; | |
/** | |
* This listener gets triggered when the {@link MediaPlayer} has completed | |
* playing the audio file. | |
*/ | |
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() { | |
@Override | |
public void onCompletion(MediaPlayer mediaPlayer) { | |
// Now that the sound file has finished playing, release the media player resources. | |
releaseMediaPlayer(); | |
} | |
}; | |
/** | |
* This listener gets triggered whenever the audio focus changes | |
* (i.e., we gain or lose audio focus because of another app or device). | |
*/ | |
private AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { | |
@Override | |
public void onAudioFocusChange(int focusChange) { | |
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || | |
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { | |
// The AUDIOFOCUS_LOSS_TRANSIENT case means that we've lost audio focus for a | |
// short amount of time. The AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK case means that | |
// our app is allowed to continue playing sound but at a lower volume. We'll treat | |
// both cases the same way because our app is playing short sound files. | |
// Pause playback and reset player to the start of the file. That way, we can | |
// play the word from the beginning when we resume playback. | |
mMediaPlayer.pause(); | |
mMediaPlayer.seekTo(0); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { | |
// The AUDIOFOCUS_GAIN case means we have regained focus and can resume playback. | |
mMediaPlayer.start(); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { | |
// The AUDIOFOCUS_LOSS case means we've lost audio focus and | |
// Stop playback and clean up resources | |
releaseMediaPlayer(); | |
} | |
} | |
}; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.word_list); | |
// Create and setup the {@link AudioManager} to request audio focus | |
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); | |
// Create a list of words | |
final ArrayList<Word> words = new ArrayList<Word>(); | |
words.add(new Word("father", "әpә", R.drawable.family_father, R.raw.family_father)); | |
words.add(new Word("mother", "әṭa", R.drawable.family_mother, R.raw.family_mother)); | |
words.add(new Word("son", "angsi", R.drawable.family_son, R.raw.family_son)); | |
words.add(new Word("daughter", "tune", R.drawable.family_daughter, R.raw.family_daughter)); | |
words.add(new Word("older brother", "taachi", R.drawable.family_older_brother, | |
R.raw.family_older_brother)); | |
words.add(new Word("younger brother", "chalitti", R.drawable.family_younger_brother, | |
R.raw.family_younger_brother)); | |
words.add(new Word("older sister", "teṭe", R.drawable.family_older_sister, | |
R.raw.family_older_sister)); | |
words.add(new Word("younger sister", "kolliti", R.drawable.family_younger_sister, | |
R.raw.family_younger_sister)); | |
words.add(new Word("grandmother ", "ama", R.drawable.family_grandmother, | |
R.raw.family_grandmother)); | |
words.add(new Word("grandfather", "paapa", R.drawable.family_grandfather, | |
R.raw.family_grandfather)); | |
// Create an {@link WordAdapter}, whose data source is a list of {@link Word}s. The | |
// adapter knows how to create list items for each item in the list. | |
WordAdapter adapter = new WordAdapter(this, words, R.color.category_family); | |
// Find the {@link ListView} object in the view hierarchy of the {@link Activity}. | |
// There should be a {@link ListView} with the view ID called list, which is declared in the | |
// word_list.xml layout file. | |
ListView listView = (ListView) findViewById(R.id.list); | |
// Make the {@link ListView} use the {@link WordAdapter} we created above, so that the | |
// {@link ListView} will display list items for each {@link Word} in the list. | |
listView.setAdapter(adapter); | |
// Set a click listener to play the audio when the list item is clicked on | |
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
@Override | |
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { | |
// Release the media player if it currently exists because we are about to | |
// play a different sound file | |
releaseMediaPlayer(); | |
// Get the {@link Word} object at the given position the user clicked on | |
Word word = words.get(position); | |
// Request audio focus so in order to play the audio file. The app needs to play a | |
// short audio file, so we will request audio focus with a short amount of time | |
// with AUDIOFOCUS_GAIN_TRANSIENT. | |
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener, | |
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); | |
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { | |
// We have audio focus now. | |
// Create and setup the {@link MediaPlayer} for the audio resource associated | |
// with the current word | |
mMediaPlayer = MediaPlayer.create(FamilyActivity.this, word.getAudioResourceId()); | |
// Start the audio file | |
mMediaPlayer.start(); | |
// Setup a listener on the media player, so that we can stop and release the | |
// media player once the sound has finished playing. | |
mMediaPlayer.setOnCompletionListener(mCompletionListener); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
// When the activity is stopped, release the media player resources because we won't | |
// be playing any more sounds. | |
releaseMediaPlayer(); | |
} | |
/** | |
* Clean up the media player by releasing its resources. | |
*/ | |
private void releaseMediaPlayer() { | |
// If the media player is not null, then it may be currently playing a sound. | |
if (mMediaPlayer != null) { | |
// Regardless of the current state of the media player, release its resources | |
// because we no longer need it. | |
mMediaPlayer.release(); | |
// Set the media player back to null. For our code, we've decided that | |
// setting the media player to null is an easy way to tell that the media player | |
// is not configured to play an audio file at the moment. | |
mMediaPlayer = null; | |
// Regardless of whether or not we were granted audio focus, abandon it. This also | |
// unregisters the AudioFocusChangeListener so we don't get anymore callbacks. | |
mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<!-- Copyright (C) 2016 The Android Open Source Project | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
--> | |
<!-- Layout for a single list item --> | |
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
xmlns:tools="http://schemas.android.com/tools" | |
android:layout_width="match_parent" | |
android:layout_height="wrap_content" | |
android:background="@color/tan_background" | |
android:minHeight="@dimen/list_item_height" | |
android:orientation="horizontal"> | |
<ImageView | |
android:id="@+id/image" | |
android:layout_width="@dimen/list_item_height" | |
android:layout_height="@dimen/list_item_height" /> | |
<LinearLayout | |
android:id="@+id/text_container" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" | |
android:orientation="vertical" | |
android:paddingLeft="16dp" | |
android:layout_alignParentRight="true" | |
android:layout_alignParentTop="true" | |
android:layout_alignParentBottom="true" | |
android:layout_toRightOf="@+id/image"> | |
<TextView | |
android:id="@+id/miwok_text_view" | |
android:layout_width="match_parent" | |
android:layout_height="0dp" | |
android:layout_weight="1" | |
android:gravity="bottom" | |
android:textAppearance="?android:textAppearanceMedium" | |
android:textColor="@android:color/white" | |
android:textStyle="bold" | |
tools:text="lutti" /> | |
<TextView | |
android:id="@+id/default_text_view" | |
android:layout_width="match_parent" | |
android:layout_height="0dp" | |
android:layout_weight="1" | |
android:gravity="top" | |
android:textAppearance="?android:textAppearanceMedium" | |
android:textColor="@android:color/white" | |
tools:text="one" /> | |
</LinearLayout> | |
<ImageView | |
android:id="@+id/image_icon" | |
android:layout_width="wrap_content" | |
android:layout_height="wrap_content" | |
android:src="@drawable/ic_play_arrow_white_24dp" | |
android:layout_centerVertical="true" | |
android:layout_alignParentRight="true" | |
android:layout_marginRight="16dp" | |
/> | |
</RelativeLayout> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Intent; | |
import android.os.Bundle; | |
import android.support.v7.app.AppCompatActivity; | |
import android.view.View; | |
import android.view.View.OnClickListener; | |
import android.widget.TextView; | |
public class MainActivity extends AppCompatActivity { | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
// Set the content of the activity to use the activity_main.xml layout file | |
setContentView(R.layout.activity_main); | |
// Find the View that shows the numbers category | |
TextView numbers = (TextView) findViewById(R.id.numbers); | |
// Set a click listener on that View | |
numbers.setOnClickListener(new OnClickListener() { | |
// The code in this method will be executed when the numbers category is clicked on. | |
@Override | |
public void onClick(View view) { | |
// Create a new intent to open the {@link NumbersActivity} | |
Intent numbersIntent = new Intent(MainActivity.this, NumbersActivity.class); | |
// Start the new activity | |
startActivity(numbersIntent); | |
} | |
}); | |
// Find the View that shows the family category | |
TextView family = (TextView) findViewById(R.id.family); | |
// Set a click listener on that View | |
family.setOnClickListener(new OnClickListener() { | |
// The code in this method will be executed when the family category is clicked on. | |
@Override | |
public void onClick(View view) { | |
// Create a new intent to open the {@link FamilyActivity} | |
Intent familyIntent = new Intent(MainActivity.this, FamilyActivity.class); | |
// Start the new activity | |
startActivity(familyIntent); | |
} | |
}); | |
// Find the View that shows the colors category | |
TextView colors = (TextView) findViewById(R.id.colors); | |
// Set a click listener on that View | |
colors.setOnClickListener(new OnClickListener() { | |
// The code in this method will be executed when the colors category is clicked on. | |
@Override | |
public void onClick(View view) { | |
// Create a new intent to open the {@link ColorsActivity} | |
Intent colorsIntent = new Intent(MainActivity.this, ColorsActivity.class); | |
// Start the new activity | |
startActivity(colorsIntent); | |
} | |
}); | |
// Find the View that shows the phrases category | |
TextView phrases = (TextView) findViewById(R.id.phrases); | |
// Set a click listener on that View | |
phrases.setOnClickListener(new OnClickListener() { | |
// The code in this method will be executed when the phrases category is clicked on. | |
@Override | |
public void onClick(View view) { | |
// Create a new intent to open the {@link PhrasesActivity} | |
Intent phrasesIntent = new Intent(MainActivity.this, PhrasesActivity.class); | |
// Start the new activity | |
startActivity(phrasesIntent); | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Context; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.os.Bundle; | |
import android.support.v7.app.AppCompatActivity; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.ListView; | |
import java.util.ArrayList; | |
public class NumbersActivity extends AppCompatActivity { | |
/** Handles playback of all the sound files */ | |
private MediaPlayer mMediaPlayer; | |
/** Handles audio focus when playing a sound file */ | |
private AudioManager mAudioManager; | |
/** | |
* This listener gets triggered whenever the audio focus changes | |
* (i.e., we gain or lose audio focus because of another app or device). | |
*/ | |
private AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { | |
@Override | |
public void onAudioFocusChange(int focusChange) { | |
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || | |
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { | |
// The AUDIOFOCUS_LOSS_TRANSIENT case means that we've lost audio focus for a | |
// short amount of time. The AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK case means that | |
// our app is allowed to continue playing sound but at a lower volume. We'll treat | |
// both cases the same way because our app is playing short sound files. | |
// Pause playback and reset player to the start of the file. That way, we can | |
// play the word from the beginning when we resume playback. | |
mMediaPlayer.pause(); | |
mMediaPlayer.seekTo(0); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { | |
// The AUDIOFOCUS_GAIN case means we have regained focus and can resume playback. | |
mMediaPlayer.start(); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { | |
// The AUDIOFOCUS_LOSS case means we've lost audio focus and | |
// Stop playback and clean up resources | |
releaseMediaPlayer(); | |
} | |
} | |
}; | |
/** | |
* This listener gets triggered when the {@link MediaPlayer} has completed | |
* playing the audio file. | |
*/ | |
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() { | |
@Override | |
public void onCompletion(MediaPlayer mediaPlayer) { | |
// Now that the sound file has finished playing, release the media player resources. | |
releaseMediaPlayer(); | |
} | |
}; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.word_list); | |
// Create and setup the {@link AudioManager} to request audio focus | |
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); | |
// Create a list of words | |
final ArrayList<Word> words = new ArrayList<Word>(); | |
words.add(new Word("one", "lutti", R.drawable.number_one, R.raw.number_one)); | |
words.add(new Word("two", "otiiko", R.drawable.number_two, R.raw.number_two)); | |
words.add(new Word("three", "tolookosu", R.drawable.number_three, R.raw.number_three)); | |
words.add(new Word("four", "oyyisa", R.drawable.number_four, R.raw.number_four)); | |
words.add(new Word("five", "massokka", R.drawable.number_five, R.raw.number_five)); | |
words.add(new Word("six", "temmokka", R.drawable.number_six, R.raw.number_six)); | |
words.add(new Word("seven", "kenekaku", R.drawable.number_seven, R.raw.number_seven)); | |
words.add(new Word("eight", "kawinta", R.drawable.number_eight, R.raw.number_eight)); | |
words.add(new Word("nine", "wo’e", R.drawable.number_nine, R.raw.number_nine)); | |
words.add(new Word("ten", "na’aacha", R.drawable.number_ten, R.raw.number_ten)); | |
// Create an {@link WordAdapter}, whose data source is a list of {@link Word}s. The | |
// adapter knows how to create list items for each item in the list. | |
WordAdapter adapter = new WordAdapter(this, words, R.color.category_numbers); | |
// Find the {@link ListView} object in the view hierarchy of the {@link Activity}. | |
// There should be a {@link ListView} with the view ID called list, which is declared in the | |
// word_list.xml layout file. | |
ListView listView = (ListView) findViewById(R.id.list); | |
// Make the {@link ListView} use the {@link WordAdapter} we created above, so that the | |
// {@link ListView} will display list items for each {@link Word} in the list. | |
listView.setAdapter(adapter); | |
// Set a click listener to play the audio when the list item is clicked on | |
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
@Override | |
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { | |
// Release the media player if it currently exists because we are about to | |
// play a different sound file | |
releaseMediaPlayer(); | |
// Get the {@link Word} object at the given position the user clicked on | |
Word word = words.get(position); | |
// Request audio focus so in order to play the audio file. The app needs to play a | |
// short audio file, so we will request audio focus with a short amount of time | |
// with AUDIOFOCUS_GAIN_TRANSIENT. | |
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener, | |
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); | |
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { | |
// We have audio focus now. | |
// Create and setup the {@link MediaPlayer} for the audio resource associated | |
// with the current word | |
mMediaPlayer = MediaPlayer.create(NumbersActivity.this, word.getAudioResourceId()); | |
// Start the audio file | |
mMediaPlayer.start(); | |
// Setup a listener on the media player, so that we can stop and release the | |
// media player once the sound has finished playing. | |
mMediaPlayer.setOnCompletionListener(mCompletionListener); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
// When the activity is stopped, release the media player resources because we won't | |
// be playing any more sounds. | |
releaseMediaPlayer(); | |
} | |
/** | |
* Clean up the media player by releasing its resources. | |
*/ | |
private void releaseMediaPlayer() { | |
// If the media player is not null, then it may be currently playing a sound. | |
if (mMediaPlayer != null) { | |
// Regardless of the current state of the media player, release its resources | |
// because we no longer need it. | |
mMediaPlayer.release(); | |
// Set the media player back to null. For our code, we've decided that | |
// setting the media player to null is an easy way to tell that the media player | |
// is not configured to play an audio file at the moment. | |
mMediaPlayer = null; | |
// Regardless of whether or not we were granted audio focus, abandon it. This also | |
// unregisters the AudioFocusChangeListener so we don't get anymore callbacks. | |
mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Context; | |
import android.media.AudioManager; | |
import android.media.MediaPlayer; | |
import android.support.v7.app.AppCompatActivity; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.widget.AdapterView; | |
import android.widget.ListView; | |
import java.util.ArrayList; | |
public class PhrasesActivity extends AppCompatActivity { | |
/** Handles playback of all the sound files */ | |
private MediaPlayer mMediaPlayer; | |
/** Handles audio focus when playing a sound file */ | |
private AudioManager mAudioManager; | |
/** | |
* This listener gets triggered when the {@link MediaPlayer} has completed | |
* playing the audio file. | |
*/ | |
private MediaPlayer.OnCompletionListener mCompletionListener = new MediaPlayer.OnCompletionListener() { | |
@Override | |
public void onCompletion(MediaPlayer mediaPlayer) { | |
// Now that the sound file has finished playing, release the media player resources. | |
releaseMediaPlayer(); | |
} | |
}; | |
/** | |
* This listener gets triggered whenever the audio focus changes | |
* (i.e., we gain or lose audio focus because of another app or device). | |
*/ | |
private AudioManager.OnAudioFocusChangeListener mOnAudioFocusChangeListener = new AudioManager.OnAudioFocusChangeListener() { | |
@Override | |
public void onAudioFocusChange(int focusChange) { | |
if (focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT || | |
focusChange == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) { | |
// The AUDIOFOCUS_LOSS_TRANSIENT case means that we've lost audio focus for a | |
// short amount of time. The AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK case means that | |
// our app is allowed to continue playing sound but at a lower volume. We'll treat | |
// both cases the same way because our app is playing short sound files. | |
// Pause playback and reset player to the start of the file. That way, we can | |
// play the word from the beginning when we resume playback. | |
mMediaPlayer.pause(); | |
mMediaPlayer.seekTo(0); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { | |
// The AUDIOFOCUS_GAIN case means we have regained focus and can resume playback. | |
mMediaPlayer.start(); | |
} else if (focusChange == AudioManager.AUDIOFOCUS_LOSS) { | |
// The AUDIOFOCUS_LOSS case means we've lost audio focus and | |
// Stop playback and clean up resources | |
releaseMediaPlayer(); | |
} | |
} | |
}; | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(R.layout.word_list); | |
// Create and setup the {@link AudioManager} to request audio focus | |
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); | |
// Create a list of words | |
final ArrayList<Word> words = new ArrayList<Word>(); | |
words.add(new Word("Where are you going?", "minto wuksus", | |
R.raw.phrase_where_are_you_going)); | |
words.add(new Word("What is your name?", "tinnә oyaase'nә", | |
R.raw.phrase_what_is_your_name)); | |
words.add(new Word("My name is...", "oyaaset...", R.raw.phrase_my_name_is)); | |
words.add(new Word("How are you feeling?", "michәksәs?", R.raw.phrase_how_are_you_feeling)); | |
words.add(new Word("I’m feeling good.", "kuchi achit", R.raw.phrase_im_feeling_good)); | |
words.add(new Word("Are you coming?", "әәnәs'aa?", R.raw.phrase_are_you_coming)); | |
words.add(new Word("Yes, I’m coming.", "hәә’ әәnәm", R.raw.phrase_yes_im_coming)); | |
words.add(new Word("I’m coming.", "әәnәm", R.raw.phrase_im_coming)); | |
words.add(new Word("Let’s go.", "yoowutis", R.raw.phrase_lets_go)); | |
words.add(new Word("Come here.", "әnni'nem", R.raw.phrase_come_here)); | |
// Create an {@link WordAdapter}, whose data source is a list of {@link Word}s. The | |
// adapter knows how to create list items for each item in the list. | |
WordAdapter adapter = new WordAdapter(this, words, R.color.category_phrases); | |
// Find the {@link ListView} object in the view hierarchy of the {@link Activity}. | |
// There should be a {@link ListView} with the view ID called list, which is declared in the | |
// word_list.xml layout file. | |
ListView listView = (ListView) findViewById(R.id.list); | |
// Make the {@link ListView} use the {@link WordAdapter} we created above, so that the | |
// {@link ListView} will display list items for each {@link Word} in the list. | |
listView.setAdapter(adapter); | |
// Set a click listener to play the audio when the list item is clicked on | |
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { | |
@Override | |
public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { | |
// Release the media player if it currently exists because we are about to | |
// play a different sound file | |
releaseMediaPlayer(); | |
// Get the {@link Word} object at the given position the user clicked on | |
Word word = words.get(position); | |
// Request audio focus so in order to play the audio file. The app needs to play a | |
// short audio file, so we will request audio focus with a short amount of time | |
// with AUDIOFOCUS_GAIN_TRANSIENT. | |
int result = mAudioManager.requestAudioFocus(mOnAudioFocusChangeListener, | |
AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN_TRANSIENT); | |
if (result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) { | |
// We have audio focus now. | |
// Create and setup the {@link MediaPlayer} for the audio resource associated | |
// with the current word | |
mMediaPlayer = MediaPlayer.create(PhrasesActivity.this, word.getAudioResourceId()); | |
// Start the audio file | |
mMediaPlayer.start(); | |
// Setup a listener on the media player, so that we can stop and release the | |
// media player once the sound has finished playing. | |
mMediaPlayer.setOnCompletionListener(mCompletionListener); | |
} | |
} | |
}); | |
} | |
@Override | |
protected void onStop() { | |
super.onStop(); | |
// When the activity is stopped, release the media player resources because we won't | |
// be playing any more sounds. | |
releaseMediaPlayer(); | |
} | |
/** | |
* Clean up the media player by releasing its resources. | |
*/ | |
private void releaseMediaPlayer() { | |
// If the media player is not null, then it may be currently playing a sound. | |
if (mMediaPlayer != null) { | |
// Regardless of the current state of the media player, release its resources | |
// because we no longer need it. | |
mMediaPlayer.release(); | |
// Set the media player back to null. For our code, we've decided that | |
// setting the media player to null is an easy way to tell that the media player | |
// is not configured to play an audio file at the moment. | |
mMediaPlayer = null; | |
// Regardless of whether or not we were granted audio focus, abandon it. This also | |
// unregisters the AudioFocusChangeListener so we don't get anymore callbacks. | |
mAudioManager.abandonAudioFocus(mOnAudioFocusChangeListener); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
/** | |
* {@link Word} represents a vocabulary word that the user wants to learn. | |
* It contains a default translation, a Miwok translation, and an image for that word. | |
*/ | |
public class Word { | |
/** Default translation for the word */ | |
private String mDefaultTranslation; | |
/** Miwok translation for the word */ | |
private String mMiwokTranslation; | |
/** Audio resource ID for the word */ | |
private int mAudioResourceId; | |
/** Image resource ID for the word */ | |
private int mImageResourceId = NO_IMAGE_PROVIDED; | |
/** Constant value that represents no image was provided for this word */ | |
private static final int NO_IMAGE_PROVIDED = -1; | |
/** | |
* Create a new Word object. | |
* | |
* @param defaultTranslation is the word in a language that the user is already familiar with | |
* (such as English) | |
* @param miwokTranslation is the word in the Miwok language | |
* @param audioResourceId is the resource ID for the audio file associated with this word | |
*/ | |
public Word(String defaultTranslation, String miwokTranslation, int audioResourceId) { | |
mDefaultTranslation = defaultTranslation; | |
mMiwokTranslation = miwokTranslation; | |
mAudioResourceId = audioResourceId; | |
} | |
/** | |
* Create a new Word object. | |
* | |
* @param defaultTranslation is the word in a language that the user is already familiar with | |
* (such as English) | |
* @param miwokTranslation is the word in the Miwok language | |
* @param imageResourceId is the drawable resource ID for the image associated with the word | |
* @param audioResourceId is the resource ID for the audio file associated with this word | |
*/ | |
public Word(String defaultTranslation, String miwokTranslation, int imageResourceId, | |
int audioResourceId) { | |
mDefaultTranslation = defaultTranslation; | |
mMiwokTranslation = miwokTranslation; | |
mImageResourceId = imageResourceId; | |
mAudioResourceId = audioResourceId; | |
} | |
/** | |
* Get the default translation of the word. | |
*/ | |
public String getDefaultTranslation() { | |
return mDefaultTranslation; | |
} | |
/** | |
* Get the Miwok translation of the word. | |
*/ | |
public String getMiwokTranslation() { | |
return mMiwokTranslation; | |
} | |
/** | |
* Return the image resource ID of the word. | |
*/ | |
public int getImageResourceId() { | |
return mImageResourceId; | |
} | |
/** | |
* Returns whether or not there is an image for this word. | |
*/ | |
public boolean hasImage() { | |
return mImageResourceId != NO_IMAGE_PROVIDED; | |
} | |
/** | |
* Return the audio resource ID of the word. | |
*/ | |
public int getAudioResourceId() { | |
return mAudioResourceId; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> | |
<!-- Copyright (C) 2016 The Android Open Source Project | |
Licensed under the Apache License, Version 2.0 (the "License"); | |
you may not use this file except in compliance with the License. | |
You may obtain a copy of the License at | |
http://www.apache.org/licenses/LICENSE-2.0 | |
Unless required by applicable law or agreed to in writing, software | |
distributed under the License is distributed on an "AS IS" BASIS, | |
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
See the License for the specific language governing permissions and | |
limitations under the License. | |
--> | |
<ListView xmlns:android="http://schemas.android.com/apk/res/android" | |
android:id="@+id/list" | |
android:orientation="vertical" | |
android:layout_width="match_parent" | |
android:layout_height="match_parent" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.android.miwok; | |
import android.content.Context; | |
import android.support.v4.content.ContextCompat; | |
import android.view.LayoutInflater; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.ArrayAdapter; | |
import android.widget.ImageView; | |
import android.widget.TextView; | |
import java.util.ArrayList; | |
/** | |
* {@link WordAdapter} is an {@link ArrayAdapter} that can provide the layout for each list item | |
* based on a data source, which is a list of {@link Word} objects. | |
*/ | |
public class WordAdapter extends ArrayAdapter<Word> { | |
/** Resource ID for the background color for this list of words */ | |
private int mColorResourceId; | |
/** | |
* Create a new {@link WordAdapter} object. | |
* | |
* @param context is the current context (i.e. Activity) that the adapter is being created in. | |
* @param words is the list of {@link Word}s to be displayed. | |
* @param colorResourceId is the resource ID for the background color for this list of words | |
*/ | |
public WordAdapter(Context context, ArrayList<Word> words, int colorResourceId) { | |
super(context, 0, words); | |
mColorResourceId = colorResourceId; | |
} | |
@Override | |
public View getView(int position, View convertView, ViewGroup parent) { | |
// Check if an existing view is being reused, otherwise inflate the view | |
View listItemView = convertView; | |
if (listItemView == null) { | |
listItemView = LayoutInflater.from(getContext()).inflate( | |
R.layout.list_item, parent, false); | |
} | |
// Get the {@link Word} object located at this position in the list | |
Word currentWord = getItem(position); | |
// Find the TextView in the list_item.xml layout with the ID miwok_text_view. | |
TextView miwokTextView = (TextView) listItemView.findViewById(R.id.miwok_text_view); | |
// Get the Miwok translation from the currentWord object and set this text on | |
// the Miwok TextView. | |
miwokTextView.setText(currentWord.getMiwokTranslation()); | |
// Find the TextView in the list_item.xml layout with the ID default_text_view. | |
TextView defaultTextView = (TextView) listItemView.findViewById(R.id.default_text_view); | |
// Get the default translation from the currentWord object and set this text on | |
// the default TextView. | |
defaultTextView.setText(currentWord.getDefaultTranslation()); | |
// Find the ImageView in the list_item.xml layout with the ID image. | |
ImageView imageView = (ImageView) listItemView.findViewById(R.id.image); | |
// Check if an image is provided for this word or not | |
if (currentWord.hasImage()) { | |
// If an image is available, display the provided image based on the resource ID | |
imageView.setImageResource(currentWord.getImageResourceId()); | |
// Make sure the view is visible | |
imageView.setVisibility(View.VISIBLE); | |
} else { | |
// Otherwise hide the ImageView (set visibility to GONE) | |
imageView.setVisibility(View.GONE); | |
} | |
// Set the theme color for the list item | |
View textContainer = listItemView.findViewById(R.id.text_container); | |
// Find the color that the resource ID maps to | |
int color = ContextCompat.getColor(getContext(), mColorResourceId); | |
// Set the background color of the text container View | |
textContainer.setBackgroundColor(color); | |
// Return the whole list item layout (containing 2 TextViews) so that it can be shown in | |
// the ListView. | |
return listItemView; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment