This commit is contained in:
warren powers
2010-11-12 20:51:57 +00:00
parent b0df41c52d
commit ef6cc1ab08
31 changed files with 1091 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="lib" path="libs/admob-sdk-android.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SweetSoundsLite</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="auto" android:versionCode="5" android:versionName="0.0.5" package="com.TwentyCodes.android.SweetSoundsLite">
<application android:label="@string/app_name" android:icon="@drawable/playdisabled">
<activity android:name=".SweetSounds"
android:label="@string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="Settings"></activity>
<meta-data android:value="a14bad63772f7d3" android:name="ADMOB_PUBLISHER_ID" />
</application>
<uses-sdk android:minSdkVersion="3" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
</manifest>

View File

View File

@@ -0,0 +1,11 @@
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system use,
# "build.properties", and override values to adapt the script to your
# project structure.
# Project target.
target=android-8

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/pausepressed" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="@drawable/pausehot" /> <!-- focused -->
<item android:drawable="@drawable/pausenormalred" /> <!-- default -->
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true"
android:drawable="@drawable/playpressed" /> <!-- pressed -->
<item android:state_focused="true"
android:drawable="@drawable/playhot" /> <!-- focused -->
<item android:drawable="@drawable/playnormal" /> <!-- default -->
</selector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:myapp="com.TwentyCodes.android.SweetSoundsLite"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff"
>
<TextView
android:id="@+id/track_title"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dip"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="20dip"
/>
<ImageButton
android:layout_marginTop="10dip"
android:layout_below="@id/track_title"
android:layout_centerHorizontal="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/play_pause_button"
android:background="@drawable/play_button"
/>
<TextView
android:id="@+id/time_left"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_below="@id/play_pause_button"
android:layout_centerHorizontal="true"
android:layout_marginTop="10dip"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="20dip"
/>
<com.admob.android.ads.AdView
android:id="@+id/ad"
android:layout_alignParentBottom="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
myapp:backgroundColor="#000000"
myapp:primaryTextColor="#FFFFFF"
myapp:secondaryTextColor="#CCCCCC"/>
<SeekBar
android:max="100"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_above="@id/ad"
android:layout_marginBottom="40dip"
android:layout_marginRight="20dip"
android:layout_marginLeft="20dip"
android:id="@+id/volume"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@id/volume"
android:layout_centerHorizontal="true"
android:text="Volume"
android:textColor="#000000"
android:textStyle="bold"
android:textSize="20dip"
/>
</RelativeLayout>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="com.admob.android.ads.AdView">
<attr name="backgroundColor" format="color" />
<attr name="primaryTextColor" format="color" />
<attr name="secondaryTextColor" format="color" />
<attr name="keywords" format="string" />
<attr name="refreshInterval" format="integer" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="sounds">
<item>Rainy River</item>
<item>Beach</item>
<item>Crickets</item>
<item>Water Falls</item>
<item>Air Conditioner</item>
</string-array>
</resources>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="hello">Hello World, WhiteNoise!</string>
<string name="app_name">Sweet Sounds</string>
</resources>

View File

@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="White Noise Options">
<ListPreference android:dialogTitle="Pick A Sound"
android:entryValues="@array/sounds"
android:entries="@array/sounds"
android:key="sounds"
android:title="Sounds"/>
</PreferenceCategory>
<PreferenceCategory
android:title="Timer Options">
<CheckBoxPreference
android:title="Enable"
android:summary="Enable Timer"
android:defaultValue="false"
android:key="timer_enabled"
/>
<com.TwentyCodes.android.SweetSoundsLite.TimePickerPreference
android:title="Timer"
android:dependency="timer_enabled"
android:key="timer_length"
/>
<CheckBoxPreference
android:title="Exit On Finish"
android:summary="Closes Application When Timer Finishes"
android:defaultValue="false"
android:key="timer_exit_on_finish"
android:dependency="timer_enabled"
/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -0,0 +1,215 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.SweetSoundsLite;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
/**
* dont forget the manifest tag
* <uses-permission android:name="android.permission.READ_LOGS" />
* @author ricky
*/
public class PostMortemReportExceptionHandler implements UncaughtExceptionHandler, Runnable {
public static final String ExceptionReportFilename = "postmortem.trace";
private static final String MSG_SUBJECT_TAG = "Exception Report"; //"app title + this tag" = email subject
private static final String MSG_SENDTO = "twentycodes@gmail.com"; //email will be sent to this account
//the following may be something you wish to consider localizing
private static final String MSG_BODY = "Just click send to help make this application better. "+
"No personal information is being sent (you can check by reading the rest of the email).";
private Thread.UncaughtExceptionHandler mDefaultUEH;
private Activity mApp = null;
public PostMortemReportExceptionHandler(Activity aApp) {
mDefaultUEH = Thread.getDefaultUncaughtExceptionHandler();
mApp = aApp;
}
public void uncaughtException(Thread t, Throwable e) {
submit(e);
//do not forget to pass this exception through up the chain
mDefaultUEH.uncaughtException(t,e);
}
public String getDebugReport(Throwable aException) {
// NumberFormat theFormatter = new DecimalFormat("#0.");
//stack trace
StackTraceElement[] theStackTrace = aException.getStackTrace();
StringBuffer report = new StringBuffer();
report.append("--------- Application ---------\n\n");
report.append(mApp.getPackageName()+" generated the following exception:\n\n");
report.append(aException.toString() + "\n\n");
report.append("-------------------------------\n\n");
report.append("--------- Stack trace ---------\n\n");
for (int i = 0; i < theStackTrace.length; i++) {
report.append(" " + theStackTrace[i].toString() + "\n");
}
report.append("-------------------------------\n\n");
//app environment
PackageManager pm = mApp.getPackageManager();
PackageInfo pi;
try {
pi = pm.getPackageInfo(mApp.getPackageName(), 0);
} catch (NameNotFoundException eNnf) {
//doubt this will ever run since we want info about our own package
pi = new PackageInfo();
pi.versionName = "unknown";
pi.versionCode = 69;
}
Date theDate = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MM.dd_HH.mm.ss_zzz");
report.append("-------- Environment --------\n");
report.append("Time\t="+sdf.format(theDate)+"\n");
report.append("Device\t="+Build.FINGERPRINT+"\n");
try {
Field theMfrField = Build.class.getField("MANUFACTURER");
report.append("Make\t="+theMfrField.get(null)+"\n");
} catch (SecurityException e) {
} catch (NoSuchFieldException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
}
report.append("Device: " + Build.DEVICE + "\n");
report.append("Brand: " + Build.BRAND + "\n");
report.append("Model: "+Build.MODEL+"\n");
report.append("Product: "+Build.PRODUCT+"\n");
report.append("App:\t "+mApp.getPackageName()+", version "+pi.versionName+" (build "+pi.versionCode+")\n");
report.append("Locale: "+mApp.getResources().getConfiguration().locale.getDisplayName()+"\n");
report.append("-----------------------------\n\n");
report.append("--------- Firmware ---------\n\n");
report.append("SDK: " + Build.VERSION.SDK + "\n");
report.append("Release: " + Build.VERSION.RELEASE + "\n");
report.append("Incremental: " + Build.VERSION.INCREMENTAL + "\n");
report.append("Build Id: " + Build.ID + "\n");
report.append("-------------------------------\n\n");
// If the exception was thrown in a background thread inside
// AsyncTask, then the actual exception can be found with getCause
report.append("--------- Cause ---------\n\n");
Throwable cause = aException.getCause();
if (cause != null) {
report.append(cause.toString() + "\n\n");
theStackTrace = cause.getStackTrace();
for (int i = 0; i < theStackTrace.length; i++) {
report.append(" " + theStackTrace[i].toString() + "\n");
}
}
report.append("-------------------------------\n\n");
report.append("--------- Complete Logcat ---------\n\n");
report.append(getLog().toString());
report.append("-------------------------------\n\n");
report.append("END REPORT");
return report.toString();
}
protected void saveDebugReport(String aReport) {
//save report to file
try {
FileOutputStream theFile = mApp.openFileOutput(ExceptionReportFilename, Context.MODE_PRIVATE);
theFile.write(aReport.getBytes());
theFile.close();
} catch(IOException ioe) {
//error during error report needs to be ignored, do not wish to start infinite loop
}
}
public void sendDebugReportToAuthor() {
String theLine = "";
StringBuffer theTrace = new StringBuffer();
try {
BufferedReader theReader = new BufferedReader(
new InputStreamReader(mApp.openFileInput(ExceptionReportFilename)));
while ((theLine = theReader.readLine())!=null) {
theTrace.append(theLine+"\n");
}
if (sendDebugReportToAuthor(theTrace.toString())) {
mApp.deleteFile(ExceptionReportFilename);
}
} catch (FileNotFoundException eFnf) {
// nothing to do
} catch(IOException eIo) {
// not going to report
}
}
public Boolean sendDebugReportToAuthor(String aReport) {
if (aReport!=null) {
Intent theIntent = new Intent(Intent.ACTION_SEND);
String theSubject = mApp.getTitle()+" "+MSG_SUBJECT_TAG;
String theBody = "\n"+MSG_BODY+"\n\n"+aReport+"\n\n";
theIntent.putExtra(Intent.EXTRA_EMAIL,new String[] {MSG_SENDTO});
theIntent.putExtra(Intent.EXTRA_TEXT, theBody);
theIntent.putExtra(Intent.EXTRA_SUBJECT, theSubject);
theIntent.setType("message/rfc822");
Boolean hasSendRecipients = (mApp.getPackageManager().queryIntentActivities(theIntent,0).size()>0);
if (hasSendRecipients) {
mApp.startActivity(theIntent);
return true;
} else {
return false;
}
} else {
return true;
}
}
public void run() {
sendDebugReportToAuthor();
}
public void submit(Throwable e) {
String theErrReport = getDebugReport(e);
saveDebugReport(theErrReport);
//try to send file contents via email (need to do so via the UI thread)
mApp.runOnUiThread(this);
}
protected StringBuilder getLog(){
final StringBuilder log = new StringBuilder();
try{
Process process = Runtime.getRuntime().exec("logcat -d");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = bufferedReader.readLine()) != null){
log.append(line);
log.append("\n");
}
}
catch (IOException e){
}
return log;
}
}

View File

@@ -0,0 +1,91 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.SweetSoundsLite;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.Preference.OnPreferenceChangeListener;
/**
* this is a settings activity for WhiteNoise. it handles user changeable settings and saves them
* @author ricky barrette
*/
public class Settings extends PreferenceActivity implements OnPreferenceChangeListener {
//shared_prefs file name
protected static final String SETTINGS = "settings";
//the following strings are for sound track selection
protected static final String SOUNDS = "sounds";
protected static final String SOUND_RIVER = "Rainy River";
protected static final String SOUND_BEACH = "Beach";
protected static final String SOUND_CRICKETS = "Crickets";
protected static final String SOUND_FALLS = "Water Falls";
protected static final String SOUND_AC = "Air Conditioner";
//the following strings are for saving volume level from the audiomanager.STREAM_MUSIC so we can restore them back when the app quits
protected static final String MUSIC_VOLUME = "music_volume";
//the following strings are for timer preference
protected static final String TIMER_ENABLED = "timer_enabled";
protected static final String TIMER_LENGTH = "timer_length";
protected static final String TIMER_EXIT_ON_FINISH = "timer_exit_on_finish";
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//set shared_prefs name
getPreferenceManager().setSharedPreferencesName(SETTINGS);
//load preferences xml
this.addPreferencesFromResource(R.xml.settings);
//get shared_prefs
SharedPreferences settings = getPreferenceManager().getSharedPreferences();
/*
* Initialize preference sound
* set OnPreferenceChangeListener
* and set summary to current settings
*/
Preference pSounds = findPreference(SOUNDS);
pSounds.setOnPreferenceChangeListener(this);
pSounds.setSummary(settings.getString(SOUNDS, SOUND_RIVER));
/*
* Initialize preference timerLength
* set OnPreferenceChangeListener
* and set summary to current settings
*/
Preference timerLength = findPreference(TIMER_LENGTH);
timerLength.setOnPreferenceChangeListener(this);
try {
timerLength.setSummary(settings.getInt(TIMER_LENGTH, 5));
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* called when a preference is changed
* @param preference
* @param newValue
* @return
* @author ricky barrette
*/
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
preference.setSummary(newValue.toString());
return true;
}
}

View File

@@ -0,0 +1,413 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.SweetSoundsLite;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.SeekBar.OnSeekBarChangeListener;
/**
* this class is responsible for setting up the ui and handling ui events
* @author ricky
*/
public class SweetSounds extends Activity implements OnClickListener, OnSeekBarChangeListener{
private boolean isPlaying;
private ImageButton play_pause;
private AudioManager mAudioManager;
private final int STREAM = AudioManager.STREAM_MUSIC;
protected static MediaPlayer mp;
private PostMortemReportExceptionHandler mDamageReport;
private final int SETTINGS = Menu.FIRST;
private final int QUIT = Menu.FIRST +1;
private SharedPreferences settings;
protected static final String TAG = "WhiteNoise";
private Timer timer;
protected static TextView timeLeft;
/**
* adjusts the provided Stream volume to the provided level
* @param stream
* @param level
* @author ricky barrette
*/
private void adjustVolume(int stream, int level) {
/*
* if the seek bar is set to a value that is higher than what the the stream value is set for
* then subtract the seek bar's value from the current volume of the stream, and then
* raise the stream by that many times
*/
if (level > mAudioManager.getStreamVolume(stream)) {
int adjust = level - mAudioManager.getStreamVolume(stream);
for (int i = 0; i < adjust; i++) {
mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_RAISE, stream, AudioManager.FLAG_VIBRATE);
}
}
/*
* if the seek bar is set to a value that is lower than what the the stream value is set for
* then subtract the current volume of the stream from the seek bar's value, and then
* lower the stream by that many times
*/
if (level < mAudioManager.getStreamVolume(stream)) {
int adjust = mAudioManager.getStreamVolume(stream) - level;
for (int i = 0; i < adjust; i++) {
mAudioManager.adjustSuggestedStreamVolume(AudioManager.ADJUST_LOWER, stream, AudioManager.FLAG_VIBRATE);
}
}
}
/**
* loads the sound from shared_prefs that the user wants, and set the mediaplayer to loop
* loads river sound track by default.
*
* @author ricky barrette
*/
private void loadSound(){
Log.i(TAG,"loadSound()");
try {
mp.reset();
} catch (Exception e) {
e.printStackTrace();
}
String sound = settings.getString("sounds", Settings.SOUND_RIVER);
Log.v(TAG,"sound = "+ sound);
if (sound != null){
if (sound.equals(Settings.SOUND_BEACH)){
mp = MediaPlayer.create(this, R.raw.beach);
mp.setLooping(true);
}
if (sound.equals(Settings.SOUND_AC)){
mp = MediaPlayer.create(this, R.raw.ac);
mp.setLooping(true);
}
if (sound.equals(Settings.SOUND_CRICKETS)){
mp = MediaPlayer.create(this, R.raw.crickets);
mp.setLooping(true);
}
if (sound.equals(Settings.SOUND_FALLS)){
mp = MediaPlayer.create(this, R.raw.falls);
mp.setLooping(true);
}
if (sound.equals(Settings.SOUND_RIVER)){
mp = MediaPlayer.create(this, R.raw.river);
mp.setLooping(true);
}
}
}
/**
* called when the user clicks on a view that has been registered with this onClickListener
* @author ricky barrette
*/
@Override
public void onClick(View v) {
/*
* if the sound track is no playing then
* change the button background from a play symbol to a pause symbol, set isPlaying to true, load the user preferred sound track, and play it
* else
* change the button background from a pause symbol to a play symbol, set isPlaying to false, and stop playing the sound track
*/
if (!isPlaying){
play_pause.setBackgroundDrawable(getResources().getDrawable(R.drawable.pause_button));
isPlaying = true;
loadSound();
mp.start();
if (settings.getBoolean(Settings.TIMER_ENABLED, false)){
Log.v(TAG,"Starting timer");
long time = settings.getInt("timer_length_hour", 0) * 3600000;
time = time + (settings.getInt("timer_length_minute", 5) * 60000);
Log.v(TAG,"time = " + time);
timer = new Timer(time);
timer.start();
}
} else {
stopPlaying();
}
}
/**
* called when the activity is first created
* (non-Javadoc)
* @see android.app.Activity#onCreate(android.os.Bundle)
* @param savedInstanceState
* @author ricky barrette
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG,"onCreate()");
// setup crash report handler
mDamageReport = new PostMortemReportExceptionHandler(this);
mDamageReport.run();
Thread.setDefaultUncaughtExceptionHandler(mDamageReport);
//initialize the play_pause button and set onClickListener
play_pause = (ImageButton) findViewById(R.id.play_pause_button);
play_pause.setOnClickListener(this);
//initialize audio manager so we can control stream volumes
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
//initialize the volume seekbar and set
SeekBar sbVolume = (SeekBar) findViewById(R.id.volume);
sbVolume.setOnSeekBarChangeListener(this);
sbVolume.setMax(mAudioManager.getStreamMaxVolume(STREAM));
sbVolume.setProgress(mAudioManager.getStreamVolume(STREAM));
//load shared_prefs
settings = getSharedPreferences(Settings.SETTINGS, 0);
loadSound();
saveStreamVolume(STREAM);
}
/**
* creates a menu
* @author ricky barrette 3-30-2010
*/
@Override
public boolean onCreateOptionsMenu (Menu menu) {
menu.add(1, SETTINGS, 0, "Options");
menu.add(1, QUIT, 0, "Quit");
return true;
}
/**
* here we set the Stream volume back to what ever it was when the activity started
* (non-Javadoc)
* @see android.app.Activity#onDestroy()
* @author ricky barrette
*/
@Override
public void onDestroy(){
adjustVolume(STREAM,settings.getInt(Settings.MUSIC_VOLUME, 0));
super.onDestroy();
}
/**
* handles menu selection
* @author ricky barrette 3-30-2010
*/
@Override
public boolean onOptionsItemSelected (MenuItem item) {
switch (item.getItemId()){
case SETTINGS:
Intent intent = new Intent().setClass(this, Settings.class);
startActivity(intent);
stopPlaying();
return true;
case QUIT:
stopPlaying();
finish();
return true;
}
return false;
}
@Override
public void onPause(){
super.onPause();
}
/**
* called when the seekbar progress is changed
* @param seekbar that was changed
* @param progress of the seekbar
* @param fromUser
*/
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
/*
* if the change was cause by the user then
* set the output stream the the desired level
*/
if(fromUser){
adjustVolume(STREAM, progress);
}
}
@Override
public void onRestart(){
super.onRestart();
}
/**
* we load the track title textview in onResume so it will update every time the activity loads
* (non-Javadoc)
* @see android.app.Activity#onResume()
* @author ricky barrette
*/
@Override
public void onResume(){
super.onResume();
TextView trackTitle = (TextView) findViewById(R.id.track_title);
trackTitle.setText(settings.getString(Settings.SOUNDS,"Rainy River"));
}
@Override
public void onStart(){
super.onStart();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
/*
* NOT YET IMPLEMENTED
* needed for OnSeekBarChangeListener
*/
}
/**
* we stop the music from playing and release the media player
* (non-Javadoc)
* @see android.app.Activity#onStop()
* @author ricky barrette
*/
@Override
public void onStop(){
stopPlaying();
try {
mp.release();
} catch (Exception e) {
e.printStackTrace();
}
super.onStop();
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
/*
* NOT YET IMPLEMENTED
* needed for OnSeekBarChangeListener
*/
}
/**
* saves the current volume levels for the supplied audio stream
* @param stream to be saved
* @return true id save was successful
* @author ricky barrette
*/
private boolean saveStreamVolume(int stream){
Editor edit = settings.edit();
edit.putInt(Settings.MUSIC_VOLUME, mAudioManager.getStreamVolume(stream));
return edit.commit();
}
/**
* stops music from playing, sets the pay_pause button background to a play symbol, and if the time is enabled, cancels the timer
*
* @author ricky barrette
*/
private void stopPlaying(){
play_pause.setBackgroundDrawable(getResources().getDrawable(R.drawable.play_button));
isPlaying = false;
try {
mp.stop();
} catch (IllegalStateException e) {
e.printStackTrace();
Log.e(TAG,"failed to stop media player");
}
if (timer != null) {
timer.cancel();
timer = null;
timeLeft.setText("");
}
}
/**
* this internal class will handle timing functions such as a timer that stops play back of a sound track & updates timeLeft textview every second
* @author ricky barrette
*/
class Timer extends CountDownTimer {
/**
* creates a new count down timer that stops play back of a sound track after specified time, and
* updates timeLeft textview every second
* @param millisInFuture
*/
public Timer(long millisInFuture) {
super(millisInFuture, 1000l);
Log.i(TAG,"Timer()");
Log.v(TAG,"millisInFuture = "+ millisInFuture);
timeLeft = (TextView) findViewById(R.id.time_left);
int hours = (int) (millisInFuture / 3600000);
millisInFuture = millisInFuture - (hours * 3600000);
int minutes = (int) ( millisInFuture / 60000);
int seconds = (int) (millisInFuture % 60000);
seconds = seconds / 1000;
timeLeft.setText(hours +" : "+ padTime(minutes) +" : "+ padTime(seconds));
}
/**
* stops the sound track being played by the media player
* (non-Javadoc)
* @see android.os.CountDownTimer#onFinish()
* @author ricky barrette
*/
@Override
public void onFinish() {
Log.i(TAG,"onFinish()");
timeLeft.setText("");
stopPlaying();
//if the user enables exit on finish, then kill the application
if(settings.getBoolean(Settings.TIMER_EXIT_ON_FINISH, false)){
Log.v(TAG,"exit on finish enabled, calling finish()");
finish();
}
}
/**
* updates the timeLeft textView to display the current time left till sound stops
* @see android.os.CountDownTimer#onTick(long)
* @param millisUntilFinished
* @author ricky barrette
*/
@Override
public void onTick(long millisUntilFinished) {
Log.i(TAG,"onTick()");
int hours = (int) (millisUntilFinished / 3600000);
millisUntilFinished = millisUntilFinished - (hours * 3600000);
int minutes = (int) ( millisUntilFinished / 60000);
int seconds = (int) (millisUntilFinished % 60000);
seconds = seconds / 1000;
timeLeft.setText(hours +" : "+ padTime(minutes) +" : "+ padTime(seconds));
}
/**
* convince method for formating the seconds string
* @param seconds
* @return formated string
* @author ricky barrette
*/
private String padTime(int seconds){
if (seconds <= 9)
return "0"+ seconds;
return ""+ seconds;
}
}
}

View File

@@ -0,0 +1,142 @@
/**
* @author Twenty Codes
* @author ricky barrette
*/
package com.TwentyCodes.android.SweetSoundsLite;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.TimePicker;
import android.widget.TimePicker.OnTimeChangedListener;
/**
* creates a time picker preference that saves the hour and minutes preferred as getKey()+"_hour" and getKey()+"_minute"
* NOTE: it might be better to save the combined hour and minutes saves as minutes (1 hour + 30 minutes would be saved as 90 minutes)
* @author ricky barrette
*/
public class TimePickerPreference extends Preference implements OnTimeChangedListener{
// private TimePicker timePicker;
private final String TAG = "TimePickerPreference";
private SharedPreferences settings;
/**
* creates a time picker preference that saves the hour and minutes preferred as getKey()+"_hour" and getKey()+"_minute"
* NOTE: it might be better to save the combined hour and minutes saves as minutes (1 hour + 30 minutes would be saved as 90 minutes)
* @param context
*/
public TimePickerPreference(Context context) {
super(context);
// timePicker = new TimePicker(getContext());
}
/**
* creates a time picker preference that saves the hour and minutes preferred as getKey()+"_hour" and getKey()+"_minute"
* NOTE: it might be better to save the combined hour and minutes saves as minutes (1 hour + 30 minutes would be saved as 90 minutes)
* @param context
* @param attrs
*/
public TimePickerPreference(Context context, AttributeSet attrs) {
super(context, attrs);
// timePicker = new TimePicker(getContext());
}
/**
* creates a time picker preference that saves the hour and minutes preferred as getKey()+"_hour" and getKey()+"_minute"
* NOTE: it might be better to save the combined hour and minutes saves as minutes (1 hour + 30 minutes would be saved as 90 minutes)
* @param context
* @param attrs
* @param defStyle
*/
public TimePickerPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// timePicker = new TimePicker(getContext());
}
/**
* saves the current time selected by the user into the shared_prefs keys of getKey()+"_hour" and getKey()+"_minute"
* NOTE: it might be better to save the combined hour and minutes saves as minutes (1 hour + 30 minutes would be saved as 90 minutes)
* (non-Javadoc)
* @see android.widget.TimePicker.OnTimeChangedListener#onTimeChanged(android.widget.TimePicker, int, int)
* @param view
* @param hourOfDay
* @param minute
* @author ricky barrette
*/
@Override
public void onTimeChanged(TimePicker view, int hourOfDay, int minute) {
Log.i(TAG,"onTimeChanged");
SharedPreferences.Editor editor = getEditor();
editor.putInt(getKey()+"_hour", hourOfDay);
editor.putInt(getKey()+"_minute", minute);
editor.commit();
}
/**
* creates a linear layout the contains only a textview (for title) and a time picker dialog for user input.
* (non-Javadoc)
* @see android.preference.Preference#onCreateView(android.view.ViewGroup)
* @param parent
* @return
* @author ricky barrette
*/
@Override
protected View onCreateView(ViewGroup parent){
Log.i(TAG, "onCreateView");
/*
* create a vertical linear layout that width and height that wraps content
*/
LinearLayout layout = new LinearLayout(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
layout.setPadding(15, 5, 10, 5);
layout.setOrientation(LinearLayout.VERTICAL);
layout.removeAllViews();
/*
* create a textview that will be used to display the title provided in xml
* and add it to the lay out
*/
TextView title = new TextView(getContext());
title.setText(getTitle());
title.setTextSize(18);
title.setTypeface(Typeface.SANS_SERIF, Typeface.BOLD);
title.setGravity(Gravity.LEFT);
title.setLayoutParams(params);
/*
* add the time picker to the layout
* set the time picker to be 24 hour style
* load saved time preference from shared_prefs, then set
* onTimeChangedListener
*/
TimePicker timePicker = new TimePicker(getContext());
timePicker.setLayoutParams(params);
timePicker.setIs24HourView(true);
settings = getSharedPreferences();
timePicker.setCurrentHour(settings.getInt(getKey() + "_hour", 0));
timePicker.setCurrentMinute(settings.getInt(getKey() + "_minute", 5));
timePicker.setOnTimeChangedListener(this);
/*
* add the title and the time picker views to the layout
*/
layout.addView(title);
layout.addView(timePicker);
layout.setId(android.R.id.widget_frame);
return layout;
}
}