i have create a simple layout that has a button, a text view and a seekbar.
i have created an onclicklistener for the play_pause button. that when click it modifies the isPlaying boolean, and switches the image button background based on isPlaying boolean. i have created an on seekbarChangedListener that when the seek bar is adjusted by the user, the audio stream volume is adjusted with it. i have created the methods playSound, and stopSound. they are not yet implemented, but they will be used. i have added the river.mp3 to the res/raw dir and used MediaPlayer to play it though the speaker. i have set the stream to AudioManaer.STREAM_MUSIC and have added life cycle methods. i have added android:screenOrientation="portrait" . everything is test and working. i incremented the build number from 0.0.0 b0 to 0.0.1 b1 i created settings.xml and Settings.java to create an Settings shared_prefs activity. i created sounds.xml which contains an array list of sounds in WhiteNoise.java i added an options menu with only one entry call options. when the user selects options the Settings.java activity is started. settings activity is done now. it displays the current sound track preference as a summary when the activity loads and changes the the summary to what ever the user chooses. incremented the build number from 0.0.1 b1 to 0.0.2 b2 loads and plays sounds based on shared_prefs settings incremented the build number from 0.0.2 b2 to 0.0.3 b3 i added ads (we need to pick a name for the application and get an ad id, as im borrowing exalted dice's) i added a textview above the play_pause button to display the track's title, it is updated in onResume() i added a line in onCreate the save the Stream volume when the activity loads, so we can restore the stream volume levels back to what they were when we started in onDestroy() i set the install location to auto for froyo i added a textview under the play_pause_button and called it time_left. it will display how much time is left if timer is enabled i added a check box preference that enables exit on finish. when the timer finishes the application will exit if enabled. i have created the class Timer.java which will handle the timing for the shut off timer and updating the current time left. incremented the build number from 0.0.3 b3 to 0.0.4 b4 also note that the sound track mp3's need to be edited for more seamless looping i added a method called padSeconds in the internal class timer that pads the seconds output to be more formal. i created the class TimePickerPreference.java which will be a time picker Preference used in the Settings.java activity tested and working. incremented the build number from 0.0.4 b4 to 0.0.5 b5 note time picker preference still needs to be fixed (only loading initial values) in TimePickerPreference.java i fixed time picker bug where every time the settings activity was displayed, the timer was set to 5 minutes. i fixed it y removing the calls timepicker.setHour() and timepicker.setMinute in onCreateView() fixed bug mentioned in previous commit (previous fix worked on the emulator, but not an actual device) *************************************************************************************************** the above change log is from all the previous commits as of 7/31/2010 due to a committing error, i think due to the fact that i renamed the project and its folder, i am going to disconnect this project and recommit it under the new name when i hit commit, svn presented an error stating that WhiteNoiseFull was not up to date. i then proceeded to update the project and try to re commit. but after i updated, i noticed that this project had some how absorbed all the other projects in the Trunk, while leaving the original copies on the server untouched. the following changes were made before i made my commit. *************************************************************************************************** i renamed the application from WhiteNoise to SweetSoundsLite. I have left the name as Sweet Sounds in the strings.xml because there is no full version being released at this time. i added more comments to TimePickerPreference.java in SweetSounds.java i created the method stopPlaying() which replaced common code blocks though out the file, and fixed bug: when you press menu -> options the sound track would be stoped, but not the timer i have also edited the sounds... i have the original sounds backed up on my computer
8
SweetDreamsLite/.classpath
Normal 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>
|
||||||
33
SweetDreamsLite/.project
Normal 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>
|
||||||
24
SweetDreamsLite/AndroidManifest.xml
Normal 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>
|
||||||
72
SweetDreamsLite/ChangeLog
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
i have create a simple layout that has a button, a text view and a seekbar.
|
||||||
|
|
||||||
|
i have created an onclicklistener for the play_pause button. that when click it modifies the isPlaying boolean, and switches the image button background based on isPlaying boolean.
|
||||||
|
|
||||||
|
i have created an on seekbarChangedListener that when the seek bar is adjusted by the user, the audio stream volume is adjusted with it.
|
||||||
|
|
||||||
|
i have created the methods playSound, and stopSound. they are not yet implemented, but they will be used.
|
||||||
|
|
||||||
|
i have added the river.mp3 to the res/raw dir and used MediaPlayer to play it though the speaker. i have set the stream to AudioManaer.STREAM_MUSIC and have added life cycle methods.
|
||||||
|
i have added android:screenOrientation="portrait" . everything is test and working.
|
||||||
|
|
||||||
|
i incremented the build number from 0.0.0 b0 to 0.0.1 b1
|
||||||
|
|
||||||
|
i created settings.xml and Settings.java to create an Settings shared_prefs activity.
|
||||||
|
i created sounds.xml which contains an array list of sounds
|
||||||
|
in WhiteNoise.java i added an options menu with only one entry call options. when the user selects options the Settings.java activity is started.
|
||||||
|
|
||||||
|
settings activity is done now. it displays the current sound track preference as a summary when the activity loads and changes the the summary to what ever the user chooses.
|
||||||
|
|
||||||
|
incremented the build number from 0.0.1 b1 to 0.0.2 b2
|
||||||
|
|
||||||
|
loads and plays sounds based on shared_prefs settings
|
||||||
|
|
||||||
|
incremented the build number from 0.0.2 b2 to 0.0.3 b3
|
||||||
|
|
||||||
|
i added ads (we need to pick a name for the application and get an ad id, as im borrowing exalted dice's)
|
||||||
|
i added a textview above the play_pause button to display the track's title, it is updated in onResume()
|
||||||
|
i added a line in onCreate the save the Stream volume when the activity loads, so we can restore the stream volume levels back to what they were when we started in onDestroy()
|
||||||
|
i set the install location to auto for froyo
|
||||||
|
i added a textview under the play_pause_button and called it time_left. it will display how much time is left if timer is enabled
|
||||||
|
i added a check box preference that enables exit on finish. when the timer finishes the application will exit if enabled.
|
||||||
|
i have created the class Timer.java which will handle the timing for the shut off timer and updating the current time left.
|
||||||
|
|
||||||
|
incremented the build number from 0.0.3 b3 to 0.0.4 b4
|
||||||
|
|
||||||
|
also note that the sound track mp3's need to be edited for more seamless looping
|
||||||
|
|
||||||
|
i added a method called padSeconds in the internal class timer that pads the seconds output to be more formal.
|
||||||
|
|
||||||
|
i created the class TimePickerPreference.java which will be a time picker Preference used in the Settings.java activity
|
||||||
|
tested and working.
|
||||||
|
|
||||||
|
incremented the build number from 0.0.4 b4 to 0.0.5 b5
|
||||||
|
|
||||||
|
note time picker preference still needs to be fixed (only loading initial values)
|
||||||
|
|
||||||
|
in TimePickerPreference.java i fixed time picker bug where every time the settings activity was displayed,
|
||||||
|
the timer was set to 5 minutes. i fixed it y removing the calls timepicker.setHour() and timepicker.setMinute in onCreateView()
|
||||||
|
|
||||||
|
fixed bug mentioned in previous commit (previous fix worked on the emulator, but not an actual device)
|
||||||
|
|
||||||
|
***************************************************************************************************
|
||||||
|
the above change log is from all the previous commits as of 7/31/2010
|
||||||
|
|
||||||
|
due to a committing error, i think due to the fact that i renamed the project and its folder, i am going to disconnect this project and recommit it under the new name
|
||||||
|
|
||||||
|
when i hit commit, svn presented an error stating that WhiteNoiseFull was not up to date. i then proceeded to update the
|
||||||
|
project and try to re commit. but after i updated, i noticed that this project had some how absorbed all the other projects in the Trunk, while leaving the original copies on the server
|
||||||
|
untouched.
|
||||||
|
|
||||||
|
|
||||||
|
the following changes were made before i made my commit.
|
||||||
|
***************************************************************************************************
|
||||||
|
|
||||||
|
i renamed the application from WhiteNoise to SweetSoundsLite. I have left the name as Sweet Sounds in the strings.xml because there is no full version being released at this time.
|
||||||
|
|
||||||
|
i added more comments to TimePickerPreference.java
|
||||||
|
|
||||||
|
in SweetSounds.java i created the method stopPlaying() which replaced common code blocks though out the file, and fixed bug: when you press menu -> options the sound track
|
||||||
|
would be stoped, but not the timer
|
||||||
|
|
||||||
|
i have also edited the sounds... i have the original sounds backed up on my computer
|
||||||
11
SweetDreamsLite/default.properties
Normal 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
|
||||||
BIN
SweetDreamsLite/libs/admob-sdk-android.jar
Normal file
BIN
SweetDreamsLite/res/drawable/pasusenormal.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
8
SweetDreamsLite/res/drawable/pause_button.xml
Normal 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>
|
||||||
BIN
SweetDreamsLite/res/drawable/pausedisabled.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
SweetDreamsLite/res/drawable/pausehot.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
SweetDreamsLite/res/drawable/pausenormalred.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
SweetDreamsLite/res/drawable/pausepressed.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
8
SweetDreamsLite/res/drawable/play_button.xml
Normal 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>
|
||||||
BIN
SweetDreamsLite/res/drawable/playdisabled.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
SweetDreamsLite/res/drawable/playhot.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
SweetDreamsLite/res/drawable/playnormal.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
SweetDreamsLite/res/drawable/playpressed.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
75
SweetDreamsLite/res/layout/main.xml
Normal 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>
|
||||||
BIN
SweetDreamsLite/res/raw/ac.mp3
Normal file
BIN
SweetDreamsLite/res/raw/beach.mp3
Normal file
BIN
SweetDreamsLite/res/raw/crickets.mp3
Normal file
BIN
SweetDreamsLite/res/raw/falls.mp3
Normal file
BIN
SweetDreamsLite/res/raw/river.mp3
Normal file
10
SweetDreamsLite/res/values/attrs.xml
Normal 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>
|
||||||
10
SweetDreamsLite/res/values/sounds.xml
Normal 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>
|
||||||
5
SweetDreamsLite/res/values/strings.xml
Normal 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>
|
||||||
38
SweetDreamsLite/res/xml/settings.xml
Normal 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>
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,411 @@
|
|||||||
|
/**
|
||||||
|
* @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 {
|
||||||
|
int minutes;
|
||||||
|
int seconds;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
minutes = (int) (millisInFuture / 60000);
|
||||||
|
seconds = (int) (millisInFuture % 60000);
|
||||||
|
seconds = seconds / 1000;
|
||||||
|
timeLeft.setText(minutes +" : "+ padSeconds(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()");
|
||||||
|
minutes = (int) (millisUntilFinished / 60000);
|
||||||
|
seconds = (int) (millisUntilFinished % 60000);
|
||||||
|
seconds = seconds / 1000;
|
||||||
|
timeLeft.setText(minutes +" : "+ padSeconds(seconds));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* convince method for formating the seconds string
|
||||||
|
* @param seconds
|
||||||
|
* @return formated string
|
||||||
|
* @author ricky barrette
|
||||||
|
*/
|
||||||
|
private String padSeconds(int seconds){
|
||||||
|
if (seconds <= 9)
|
||||||
|
return "0"+ seconds;
|
||||||
|
return ""+ seconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,139 @@
|
|||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||