reorg
8
Projects/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
Projects/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
Projects/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>
|
||||||
0
Projects/SweetDreamsLite/ChangeLog
Normal file
11
Projects/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
Projects/SweetDreamsLite/libs/admob-sdk-android.jar
Normal file
BIN
Projects/SweetDreamsLite/res/drawable/pasusenormal.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
8
Projects/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
Projects/SweetDreamsLite/res/drawable/pausedisabled.png
Normal file
|
After Width: | Height: | Size: 8.6 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/pausehot.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/pausenormalred.png
Normal file
|
After Width: | Height: | Size: 9.4 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/pausepressed.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
8
Projects/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
Projects/SweetDreamsLite/res/drawable/playdisabled.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/playhot.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/playnormal.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Projects/SweetDreamsLite/res/drawable/playpressed.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
75
Projects/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
Projects/SweetDreamsLite/res/raw/ac.mp3
Normal file
BIN
Projects/SweetDreamsLite/res/raw/beach.mp3
Normal file
BIN
Projects/SweetDreamsLite/res/raw/crickets.mp3
Normal file
BIN
Projects/SweetDreamsLite/res/raw/falls.mp3
Normal file
BIN
Projects/SweetDreamsLite/res/raw/river.mp3
Normal file
10
Projects/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
Projects/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
Projects/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
Projects/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,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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||