diff --git a/Jpandroid/AndroidManifest.xml b/Jpandroid/AndroidManifest.xml new file mode 100644 index 0000000..d286041 --- /dev/null +++ b/Jpandroid/AndroidManifest.xml @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/Jpandroid/res/drawable/icon.png b/Jpandroid/res/drawable/icon.png new file mode 100644 index 0000000..a07c69f Binary files /dev/null and b/Jpandroid/res/drawable/icon.png differ diff --git a/Jpandroid/res/layout/main.xml b/Jpandroid/res/layout/main.xml new file mode 100644 index 0000000..3a5f117 --- /dev/null +++ b/Jpandroid/res/layout/main.xml @@ -0,0 +1,12 @@ + + + + diff --git a/Jpandroid/res/values/strings.xml b/Jpandroid/res/values/strings.xml new file mode 100644 index 0000000..f9ddbb8 --- /dev/null +++ b/Jpandroid/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World! + + diff --git a/Jpandroid/src/com/meditationtracker/persistence/helpers/ReflectionHelper.java b/Jpandroid/src/com/meditationtracker/persistence/helpers/ReflectionHelper.java new file mode 100644 index 0000000..61dbeaa --- /dev/null +++ b/Jpandroid/src/com/meditationtracker/persistence/helpers/ReflectionHelper.java @@ -0,0 +1,43 @@ +package com.meditationtracker.persistence.helpers; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.persistence.Column; +import javax.persistence.Id; + +import android.provider.BaseColumns; + +public class ReflectionHelper { + + public static Map getPersistenceColumnNamesForClass(Class clazz) { + Map result = new HashMap(); + for (Field f : getPersistenceColumnsForClass(clazz)) + { + Column columnAnn = f.getAnnotation(Column.class); + if (columnAnn != null) + result.put(columnAnn.name(), f); + else + if (f.getAnnotation(Id.class) != null) + result.put(BaseColumns._ID, f); + } + + return result; + } + + protected static List getPersistenceColumnsForClass(Class clazz) { + List result = new ArrayList(); + for (Field f : clazz.getFields()) { + if (f.getAnnotation(Column.class) != null || f.getAnnotation(Id.class) != null) + { + result.add(f); + } + } + + return result; + } + +} diff --git a/Jpandroid/src/com/meditationtracker/persistence/jpa/Entity.java b/Jpandroid/src/com/meditationtracker/persistence/jpa/Entity.java new file mode 100644 index 0000000..a10dabd --- /dev/null +++ b/Jpandroid/src/com/meditationtracker/persistence/jpa/Entity.java @@ -0,0 +1,80 @@ +package com.meditationtracker.persistence.jpa; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import com.meditationtracker.persistence.helpers.ReflectionHelper; +import doo.util.functional.Collection; +import doo.util.functional.Folder; + +public class Entity { + private String hash; + private Class clazz = null; + private Map columns; + + public Entity(Class clazz) { + this.clazz = clazz; + hash = buildHash(clazz); + } + + @SuppressWarnings("unchecked") + public T createInstance(ResultSet row) throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, SQLException { + if (clazz == null) + throw new IllegalArgumentException("Entity was initialized without a class, cannot create one."); + + return fillObject((T)clazz.getConstructor((Class[])null).newInstance(), row); + } + + private T fillObject(T obj, ResultSet row) throws SQLException, IllegalArgumentException, IllegalAccessException { + ResultSetMetaData metaData = row.getMetaData(); + for (int x=0; x columns = new ArrayList(); + + ResultSetMetaData rowMetaData = row.getMetaData(); + for(int x = 0; x clazz) { + columns = ReflectionHelper.getPersistenceColumnNamesForClass(clazz); + List colNames = new ArrayList(columns.keySet()); + + return sortAndJoinForHash(colNames); + } + + private static String sortAndJoinForHash(List list) { + Collections.sort(list); + return Collection.fold(list, "|", new Folder() { + public String fold(String accumulator, String current) { + return accumulator += current + "|"; + } + + }); + } + +} diff --git a/Jpandroid/src/com/meditationtracker/persistence/jpa/EntityManager.java b/Jpandroid/src/com/meditationtracker/persistence/jpa/EntityManager.java new file mode 100644 index 0000000..5e92e0b --- /dev/null +++ b/Jpandroid/src/com/meditationtracker/persistence/jpa/EntityManager.java @@ -0,0 +1,22 @@ +package com.meditationtracker.persistence.jpa; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; + + +public class EntityManager { + private static HashMap entities; + + public static void registerEntity(Class clazz) { + Entity entity = new Entity(clazz); + entities.put(entity.hashCode(), entity); + } + + public static Entity getEntityInfo(ResultSet row) throws SQLException { + return entities.get(Entity.buildHash(row)); + } + + + +} diff --git a/Jpandroid/src/com/meditationtracker/persistence/jpa/JpaHandler.java b/Jpandroid/src/com/meditationtracker/persistence/jpa/JpaHandler.java new file mode 100644 index 0000000..1b64a38 --- /dev/null +++ b/Jpandroid/src/com/meditationtracker/persistence/jpa/JpaHandler.java @@ -0,0 +1,28 @@ +package com.meditationtracker.persistence.jpa; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.apache.commons.dbutils.ResultSetHandler; + + +public class JpaHandler implements ResultSetHandler{ + + public T handle(ResultSet row) throws SQLException { + Entity info = EntityManager.getEntityInfo(row); + + T result; + try { + result = info.createInstance(row); + + return result; + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + + return null; + } + + } + +} diff --git a/MeditationTracker/AndroidManifest.xml b/MeditationTracker/AndroidManifest.xml new file mode 100644 index 0000000..c082756 --- /dev/null +++ b/MeditationTracker/AndroidManifest.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MeditationTracker/misc/189917.eps b/MeditationTracker/misc/189917.eps new file mode 100644 index 0000000..46ab7e5 Binary files /dev/null and b/MeditationTracker/misc/189917.eps differ diff --git a/MeditationTracker/misc/AlmazniyUm_print.pdf b/MeditationTracker/misc/AlmazniyUm_print.pdf new file mode 100644 index 0000000..980acfd Binary files /dev/null and b/MeditationTracker/misc/AlmazniyUm_print.pdf differ diff --git a/MeditationTracker/misc/Ngoendro_imgs.zip b/MeditationTracker/misc/Ngoendro_imgs.zip new file mode 100644 index 0000000..ea14d23 Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs.zip differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/1.jpg b/MeditationTracker/misc/Ngoendro_imgs/1.jpg new file mode 100644 index 0000000..376577b Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/1.jpg differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/2.jpg b/MeditationTracker/misc/Ngoendro_imgs/2.jpg new file mode 100644 index 0000000..ec1fe45 Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/2.jpg differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/3.jpg b/MeditationTracker/misc/Ngoendro_imgs/3.jpg new file mode 100644 index 0000000..778139e Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/3.jpg differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/4.jpg b/MeditationTracker/misc/Ngoendro_imgs/4.jpg new file mode 100644 index 0000000..46698d8 Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/4.jpg differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/AlmazniyUm_print.tif b/MeditationTracker/misc/Ngoendro_imgs/AlmazniyUm_print.tif new file mode 100644 index 0000000..f215c5c Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/AlmazniyUm_print.tif differ diff --git a/MeditationTracker/misc/Ngoendro_imgs/Prostiraniya_print.tif b/MeditationTracker/misc/Ngoendro_imgs/Prostiraniya_print.tif new file mode 100644 index 0000000..5e91f64 Binary files /dev/null and b/MeditationTracker/misc/Ngoendro_imgs/Prostiraniya_print.tif differ diff --git "a/MeditationTracker/misc/Ngoendro_imgs/\320\224\320\265\321\200\320\266\320\260\321\202\320\265\320\273\321\214 \320\220\320\273\320\274\320\260\320\267\320\260.jpg" "b/MeditationTracker/misc/Ngoendro_imgs/\320\224\320\265\321\200\320\266\320\260\321\202\320\265\320\273\321\214 \320\220\320\273\320\274\320\260\320\267\320\260.jpg" new file mode 100644 index 0000000..3054b0c Binary files /dev/null and "b/MeditationTracker/misc/Ngoendro_imgs/\320\224\320\265\321\200\320\266\320\260\321\202\320\265\320\273\321\214 \320\220\320\273\320\274\320\260\320\267\320\260.jpg" differ diff --git a/MeditationTracker/misc/Prostiraniya_2010_print.pdf b/MeditationTracker/misc/Prostiraniya_2010_print.pdf new file mode 100644 index 0000000..372ffb7 Binary files /dev/null and b/MeditationTracker/misc/Prostiraniya_2010_print.pdf differ diff --git a/MeditationTracker/misc/clean logo.png b/MeditationTracker/misc/clean logo.png new file mode 100644 index 0000000..a56dab0 Binary files /dev/null and b/MeditationTracker/misc/clean logo.png differ diff --git a/MeditationTracker/misc/clean logo.svg b/MeditationTracker/misc/clean logo.svg new file mode 100644 index 0000000..6881fe1 --- /dev/null +++ b/MeditationTracker/misc/clean logo.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/misc/icon.jpg b/MeditationTracker/misc/icon.jpg new file mode 100644 index 0000000..cc04938 Binary files /dev/null and b/MeditationTracker/misc/icon.jpg differ diff --git a/MeditationTracker/misc/icons.png b/MeditationTracker/misc/icons.png new file mode 100644 index 0000000..0e82ccf Binary files /dev/null and b/MeditationTracker/misc/icons.png differ diff --git a/MeditationTracker/misc/logo.svg b/MeditationTracker/misc/logo.svg new file mode 100644 index 0000000..367c2d4 --- /dev/null +++ b/MeditationTracker/misc/logo.svg @@ -0,0 +1,337 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 111.111 + + + + + diff --git a/MeditationTracker/misc/logo.xcf b/MeditationTracker/misc/logo.xcf new file mode 100644 index 0000000..86028cf Binary files /dev/null and b/MeditationTracker/misc/logo.xcf differ diff --git a/MeditationTracker/misc/logo_48.xcf b/MeditationTracker/misc/logo_48.xcf new file mode 100644 index 0000000..a50f2fa Binary files /dev/null and b/MeditationTracker/misc/logo_48.xcf differ diff --git a/MeditationTracker/misc/logo_512.png b/MeditationTracker/misc/logo_512.png new file mode 100644 index 0000000..6cdfdf5 Binary files /dev/null and b/MeditationTracker/misc/logo_512.png differ diff --git a/MeditationTracker/misc/logo_512.xcf b/MeditationTracker/misc/logo_512.xcf new file mode 100644 index 0000000..6fb66d7 Binary files /dev/null and b/MeditationTracker/misc/logo_512.xcf differ diff --git a/MeditationTracker/misc/logo_72.xcf b/MeditationTracker/misc/logo_72.xcf new file mode 100644 index 0000000..f57d7a0 Binary files /dev/null and b/MeditationTracker/misc/logo_72.xcf differ diff --git a/MeditationTracker/misc/orig/diamond_mind_big.jpg b/MeditationTracker/misc/orig/diamond_mind_big.jpg new file mode 100644 index 0000000..139a60d Binary files /dev/null and b/MeditationTracker/misc/orig/diamond_mind_big.jpg differ diff --git a/MeditationTracker/misc/orig/guru_yoga_big.png b/MeditationTracker/misc/orig/guru_yoga_big.png new file mode 100644 index 0000000..aef4530 Binary files /dev/null and b/MeditationTracker/misc/orig/guru_yoga_big.png differ diff --git a/MeditationTracker/misc/orig/icon.png b/MeditationTracker/misc/orig/icon.png new file mode 100644 index 0000000..a07c69f Binary files /dev/null and b/MeditationTracker/misc/orig/icon.png differ diff --git a/MeditationTracker/misc/orig/icon_diamond_mind.png b/MeditationTracker/misc/orig/icon_diamond_mind.png new file mode 100644 index 0000000..ad82e0b Binary files /dev/null and b/MeditationTracker/misc/orig/icon_diamond_mind.png differ diff --git a/MeditationTracker/misc/orig/icon_guru_yoga.png b/MeditationTracker/misc/orig/icon_guru_yoga.png new file mode 100644 index 0000000..c54f653 Binary files /dev/null and b/MeditationTracker/misc/orig/icon_guru_yoga.png differ diff --git a/MeditationTracker/misc/orig/icon_karmapa.png b/MeditationTracker/misc/orig/icon_karmapa.png new file mode 100644 index 0000000..ae0bc65 Binary files /dev/null and b/MeditationTracker/misc/orig/icon_karmapa.png differ diff --git a/MeditationTracker/misc/orig/icon_mandala_offering.png b/MeditationTracker/misc/orig/icon_mandala_offering.png new file mode 100644 index 0000000..ab7ba6b Binary files /dev/null and b/MeditationTracker/misc/orig/icon_mandala_offering.png differ diff --git a/MeditationTracker/misc/orig/icon_refuge.png b/MeditationTracker/misc/orig/icon_refuge.png new file mode 100644 index 0000000..b1b17d1 Binary files /dev/null and b/MeditationTracker/misc/orig/icon_refuge.png differ diff --git a/MeditationTracker/misc/orig/karmapa.png b/MeditationTracker/misc/orig/karmapa.png new file mode 100644 index 0000000..97a5ba3 Binary files /dev/null and b/MeditationTracker/misc/orig/karmapa.png differ diff --git a/MeditationTracker/misc/orig/launcher_48.png b/MeditationTracker/misc/orig/launcher_48.png new file mode 100644 index 0000000..403a6c1 Binary files /dev/null and b/MeditationTracker/misc/orig/launcher_48.png differ diff --git a/MeditationTracker/misc/orig/launcher_72.png b/MeditationTracker/misc/orig/launcher_72.png new file mode 100644 index 0000000..810895d Binary files /dev/null and b/MeditationTracker/misc/orig/launcher_72.png differ diff --git a/MeditationTracker/misc/orig/mandala_offering_big.png b/MeditationTracker/misc/orig/mandala_offering_big.png new file mode 100644 index 0000000..b7baebb Binary files /dev/null and b/MeditationTracker/misc/orig/mandala_offering_big.png differ diff --git a/MeditationTracker/misc/orig/more.png b/MeditationTracker/misc/orig/more.png new file mode 100644 index 0000000..1c6f7b0 Binary files /dev/null and b/MeditationTracker/misc/orig/more.png differ diff --git a/MeditationTracker/misc/orig/refuge.png b/MeditationTracker/misc/orig/refuge.png new file mode 100644 index 0000000..89b03a7 Binary files /dev/null and b/MeditationTracker/misc/orig/refuge.png differ diff --git a/MeditationTracker/misc/orig/refuge_big.jpg b/MeditationTracker/misc/orig/refuge_big.jpg new file mode 100644 index 0000000..694b472 Binary files /dev/null and b/MeditationTracker/misc/orig/refuge_big.jpg differ diff --git a/MeditationTracker/misc/orig/top_logo.png b/MeditationTracker/misc/orig/top_logo.png new file mode 100644 index 0000000..9505ed6 Binary files /dev/null and b/MeditationTracker/misc/orig/top_logo.png differ diff --git a/MeditationTracker/misc/orig/top_logo_bg.png b/MeditationTracker/misc/orig/top_logo_bg.png new file mode 100644 index 0000000..e2b8146 Binary files /dev/null and b/MeditationTracker/misc/orig/top_logo_bg.png differ diff --git a/MeditationTracker/misc/ormlite/ClickCounter.zip b/MeditationTracker/misc/ormlite/ClickCounter.zip new file mode 100644 index 0000000..04de103 Binary files /dev/null and b/MeditationTracker/misc/ormlite/ClickCounter.zip differ diff --git a/MeditationTracker/misc/ormlite/DatabaseHelper.java b/MeditationTracker/misc/ormlite/DatabaseHelper.java new file mode 100644 index 0000000..9cb2e18 --- /dev/null +++ b/MeditationTracker/misc/ormlite/DatabaseHelper.java @@ -0,0 +1,84 @@ +package com.example.helloandroid; + +import java.sql.SQLException; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.util.Log; + +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.dao.BaseDaoImpl; +import com.j256.ormlite.dao.Dao; +import com.j256.ormlite.support.ConnectionSource; +import com.j256.ormlite.table.TableUtils; + +/** + * Database helper class used to manage the creation and upgrading of your database. This class also usually provides + * the DAOs used by the other classes. + */ +public class DatabaseHelper extends OrmLiteSqliteOpenHelper { + + // name of the database file for your application -- change to something appropriate for your app + private static final String DATABASE_NAME = "helloAndroid.db"; + // any time you make changes to your database objects, you may have to increase the database version + private static final int DATABASE_VERSION = 2; + + // the DAO object we use to access the SimpleData table + private Dao simpleDao = null; + + public DatabaseHelper(Context context) { + super(context, DATABASE_NAME, null, DATABASE_VERSION); + } + + /** + * This is called when the database is first created. Usually you should call createTable statements here to create + * the tables that will store your data. + */ + @Override + public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) { + try { + Log.i(DatabaseHelper.class.getName(), "onCreate"); + TableUtils.createTable(connectionSource, SimpleData.class); + } catch (SQLException e) { + Log.e(DatabaseHelper.class.getName(), "Can't create database", e); + throw new RuntimeException(e); + } + } + + /** + * This is called when your application is upgraded and it has a higher version number. This allows you to adjust + * the various data to match the new version number. + */ + @Override + public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) { + try { + Log.i(DatabaseHelper.class.getName(), "onUpgrade"); + TableUtils.dropTable(connectionSource, SimpleData.class, true); + // after we drop the old databases, we create the new ones + onCreate(db); + } catch (SQLException e) { + Log.e(DatabaseHelper.class.getName(), "Can't drop databases", e); + throw new RuntimeException(e); + } + } + + /** + * Returns the Database Access Object (DAO) for our SimpleData class. It will create it or just give the cached + * value. + */ + public Dao getSimpleDataDao() throws SQLException { + if (simpleDao == null) { + simpleDao = BaseDaoImpl.createDao(getConnectionSource(), SimpleData.class); + } + return simpleDao; + } + + /** + * Close the database connections and clear any cached DAOs. + */ + @Override + public void close() { + super.close(); + simpleDao = null; + } +} diff --git a/MeditationTracker/misc/ormlite/HelloAndroid.java b/MeditationTracker/misc/ormlite/HelloAndroid.java new file mode 100644 index 0000000..fe0713a --- /dev/null +++ b/MeditationTracker/misc/ormlite/HelloAndroid.java @@ -0,0 +1,88 @@ +package com.example.helloandroid; + +import java.sql.SQLException; +import java.util.List; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.widget.TextView; + +import com.j256.ormlite.android.apptools.OpenHelperManager; +import com.j256.ormlite.android.apptools.OrmLiteBaseActivity; +import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper; +import com.j256.ormlite.android.apptools.OpenHelperManager.SqliteOpenHelperFactory; +import com.j256.ormlite.dao.Dao; + +/** + * Our Android UI activity which displays a text window when it is run. + */ +public class HelloAndroid extends OrmLiteBaseActivity { + + private final String LOG_TAG = getClass().getSimpleName(); + + static { + OpenHelperManager.setOpenHelperFactory(new SqliteOpenHelperFactory() { + public OrmLiteSqliteOpenHelper getHelper(Context context) { + return new DatabaseHelper(context); + } + }); + } + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.i(LOG_TAG, "creating " + getClass()); + TextView tv = new TextView(this); + doSampleDatabaseStuff("onCreate", tv); + setContentView(tv); + } + + /** + * Do our sample database stuff. + */ + private void doSampleDatabaseStuff(String action, TextView tv) { + try { + // get our dao + Dao simpleDao = getHelper().getSimpleDataDao(); + // query for all of the data objects in the database + List list = simpleDao.queryForAll(); + // our string builder for building the content-view + StringBuilder sb = new StringBuilder(); + sb.append("got ").append(list.size()).append(" entries in ").append(action).append("\n"); + + // if we already have items in the database + if (list.size() > 0) { + // output the first one + SimpleData simple = list.get(0); + sb.append("--------------------------------\n"); + sb.append("[0] = ").append(simple).append("\n"); + sb.append("--------------------------------\n"); + // delete it + int ret = simpleDao.delete(simple); + sb.append("deleted entry = ").append(ret).append("\n"); + Log.i(LOG_TAG, "deleting simple(" + simple.millis + ") returned " + ret); + } + + // create a new simple object + long millis = System.currentTimeMillis(); + SimpleData simple = new SimpleData(millis); + // store it in the database + int ret = simpleDao.create(simple); + Log.i(LOG_TAG, "creating simple(" + millis + ") returned " + ret); + + // output it + sb.append("created new entry = ").append(ret).append("\n"); + sb.append("--------------------------------\n"); + sb.append("new entry = ").append(simple).append("\n"); + sb.append("--------------------------------\n"); + tv.setText(sb.toString()); + } catch (SQLException e) { + Log.e(LOG_TAG, "Database exception", e); + return; + } + } +} \ No newline at end of file diff --git a/MeditationTracker/misc/ormlite/HelloAndroid.zip b/MeditationTracker/misc/ormlite/HelloAndroid.zip new file mode 100644 index 0000000..2a698ea Binary files /dev/null and b/MeditationTracker/misc/ormlite/HelloAndroid.zip differ diff --git a/MeditationTracker/misc/ormlite/NotifyService.zip b/MeditationTracker/misc/ormlite/NotifyService.zip new file mode 100644 index 0000000..6a0a029 Binary files /dev/null and b/MeditationTracker/misc/ormlite/NotifyService.zip differ diff --git a/MeditationTracker/misc/ormlite/SimpleData.java b/MeditationTracker/misc/ormlite/SimpleData.java new file mode 100644 index 0000000..8d51ec4 --- /dev/null +++ b/MeditationTracker/misc/ormlite/SimpleData.java @@ -0,0 +1,45 @@ +package com.example.helloandroid; + +import java.util.Date; + +import com.j256.ormlite.field.DatabaseField; + +/** + * A simple demonstration object we are creating and persisting to the database. + */ +public class SimpleData { + + // id is generated by the database and set on the object automagically + @DatabaseField(generatedId = true) + int id; + @DatabaseField + String string; + @DatabaseField + long millis; + @DatabaseField + Date date; + @DatabaseField + boolean even; + + SimpleData() { + // needed by ormlite + } + + public SimpleData(long millis) { + this.date = new Date(millis); + this.string = "millis = " + millis; + this.millis = millis; + this.even = ((millis % 2) == 0); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("id=").append(id); + sb.append(", ").append("string=").append(string); + sb.append(", ").append("millis=").append(millis); + sb.append(", ").append("date=").append(date); + sb.append(", ").append("even=").append(even); + return sb.toString(); + } +} diff --git a/MeditationTracker/misc/ormlite/ormlite-android-4.2.jar b/MeditationTracker/misc/ormlite/ormlite-android-4.2.jar new file mode 100644 index 0000000..afbbc6b Binary files /dev/null and b/MeditationTracker/misc/ormlite/ormlite-android-4.2.jar differ diff --git a/MeditationTracker/misc/ormlite/ormlite.pdf b/MeditationTracker/misc/ormlite/ormlite.pdf new file mode 100644 index 0000000..395a01e Binary files /dev/null and b/MeditationTracker/misc/ormlite/ormlite.pdf differ diff --git a/MeditationTracker/misc/qrcode.png b/MeditationTracker/misc/qrcode.png new file mode 100644 index 0000000..0c2dd54 Binary files /dev/null and b/MeditationTracker/misc/qrcode.png differ diff --git a/MeditationTracker/misc/sqlite/-column b/MeditationTracker/misc/sqlite/-column new file mode 100644 index 0000000..e69de29 diff --git a/MeditationTracker/misc/sqlite/MediTracker b/MeditationTracker/misc/sqlite/MediTracker new file mode 100644 index 0000000..a533716 Binary files /dev/null and b/MeditationTracker/misc/sqlite/MediTracker differ diff --git a/MeditationTracker/misc/sqlite/MediTracker15 b/MeditationTracker/misc/sqlite/MediTracker15 new file mode 100644 index 0000000..41c54c1 Binary files /dev/null and b/MeditationTracker/misc/sqlite/MediTracker15 differ diff --git a/MeditationTracker/misc/sqlite/MediTracker22 b/MeditationTracker/misc/sqlite/MediTracker22 new file mode 100644 index 0000000..dcec665 Binary files /dev/null and b/MeditationTracker/misc/sqlite/MediTracker22 differ diff --git a/MeditationTracker/misc/sqlite/create_tables.sql b/MeditationTracker/misc/sqlite/create_tables.sql new file mode 100644 index 0000000..62cbd55 --- /dev/null +++ b/MeditationTracker/misc/sqlite/create_tables.sql @@ -0,0 +1,3 @@ +CREATE TABLE Practices (_ID INTEGER PRIMARY KEY, ISNGONDRO BOOLEAN, SORT_ORDER INTEGER, RESOURCEIDICON INTEGER, RESOURCEIDTITLE INTEGER, TITLE TEXT, ICONURL TEXT, TOTALCOUNT INTEGER, SCHEDULEDCOMPLETION INTEGER); + +CREATE TABLE PracticeHistory (_ID INTEGER PRIMARY KEY, PRACTICE_ID INTEGER, PRACTICE_DATE DATETIME default CURRENT_TIMESTAMP, DONE_COUNT INTEGER); diff --git a/MeditationTracker/misc/sqlite/default_data.sql b/MeditationTracker/misc/sqlite/default_data.sql new file mode 100644 index 0000000..3245761 --- /dev/null +++ b/MeditationTracker/misc/sqlite/default_data.sql @@ -0,0 +1,26 @@ +INSERT INTO Practices ( + ISNGONDRO, + SORT_ORDER, + RESOURCEIDICON, + RESOURCEIDTITLE, + TOTALCOUNT, + SCHEDULEDCOMPLETION) values ( + 1, 0, 100, 500, 111111, 0 + ); + + +INSERT INTO Practices ( + ISNGONDRO, + SORT_ORDER, + ICONURL, + TITLE, + TOTALCOUNT, + SCHEDULEDCOMPLETION) values ( + 1, 1, 'file://icon.png', 'Dorje sempa', 111111, 0 + ); + +INSERT INTO PracticeHistory (PRACTICE_ID, DONE_COUNT) values (1, 108); +INSERT INTO PracticeHistory (PRACTICE_ID, DONE_COUNT) values (1, 114); +INSERT INTO PracticeHistory (PRACTICE_ID, DONE_COUNT) values (2, 124); +INSERT INTO PracticeHistory (PRACTICE_ID, DONE_COUNT) values (1, 120); + diff --git a/MeditationTracker/misc/sqlite/mediTrack.db b/MeditationTracker/misc/sqlite/mediTrack.db new file mode 100644 index 0000000..981b5ec Binary files /dev/null and b/MeditationTracker/misc/sqlite/mediTrack.db differ diff --git a/MeditationTracker/misc/sqlite/practices_status.sql b/MeditationTracker/misc/sqlite/practices_status.sql new file mode 100644 index 0000000..1c6d256 --- /dev/null +++ b/MeditationTracker/misc/sqlite/practices_status.sql @@ -0,0 +1,8 @@ +select ICONURL, THUMBURL, TITLE, TOTALCOUNT, SCHEDULEDCOMPLETION, +SUM(DONE_COUNT) as DONE, 100.0*SUM(DONE_COUNT)/TOTALCOUNT as DONE_PERC , +MAX(PRACTICE_DATE) AS LAST_PRACTICE + +from practices p join practiceHistory ph on p._ID = ph.PRACTICE_ID +WHERE ISNGONDRO = 1 +GROUP BY p._ID +ORDER BY SORT_ORDER; \ No newline at end of file diff --git a/MeditationTracker/misc/ss/1.png b/MeditationTracker/misc/ss/1.png new file mode 100644 index 0000000..4910efd Binary files /dev/null and b/MeditationTracker/misc/ss/1.png differ diff --git a/MeditationTracker/misc/ss/2.png b/MeditationTracker/misc/ss/2.png new file mode 100644 index 0000000..c939560 Binary files /dev/null and b/MeditationTracker/misc/ss/2.png differ diff --git a/MeditationTracker/misc/ss/3.png b/MeditationTracker/misc/ss/3.png new file mode 100644 index 0000000..cfdcfc0 Binary files /dev/null and b/MeditationTracker/misc/ss/3.png differ diff --git a/MeditationTracker/misc/ss/4.png b/MeditationTracker/misc/ss/4.png new file mode 100644 index 0000000..2ab1221 Binary files /dev/null and b/MeditationTracker/misc/ss/4.png differ diff --git a/MeditationTracker/misc/ss/5.png b/MeditationTracker/misc/ss/5.png new file mode 100644 index 0000000..cf391a2 Binary files /dev/null and b/MeditationTracker/misc/ss/5.png differ diff --git a/MeditationTracker/misc/ss/6.png b/MeditationTracker/misc/ss/6.png new file mode 100644 index 0000000..7b57da9 Binary files /dev/null and b/MeditationTracker/misc/ss/6.png differ diff --git a/MeditationTracker/misc/ss/all.png b/MeditationTracker/misc/ss/all.png new file mode 100644 index 0000000..d2571d0 Binary files /dev/null and b/MeditationTracker/misc/ss/all.png differ diff --git a/MeditationTracker/misc/ss/main.png b/MeditationTracker/misc/ss/main.png new file mode 100644 index 0000000..4910efd Binary files /dev/null and b/MeditationTracker/misc/ss/main.png differ diff --git a/MeditationTracker/misc/ss/refuge.png b/MeditationTracker/misc/ss/refuge.png new file mode 100644 index 0000000..2efae2d Binary files /dev/null and b/MeditationTracker/misc/ss/refuge.png differ diff --git a/MeditationTracker/misc/top_logo.xcf b/MeditationTracker/misc/top_logo.xcf new file mode 100644 index 0000000..c377cce Binary files /dev/null and b/MeditationTracker/misc/top_logo.xcf differ diff --git a/MeditationTracker/misc/tracker_all5.jpg b/MeditationTracker/misc/tracker_all5.jpg new file mode 100644 index 0000000..e57357d Binary files /dev/null and b/MeditationTracker/misc/tracker_all5.jpg differ diff --git a/MeditationTracker/release/1.0.0/MeditationTracker.apk b/MeditationTracker/release/1.0.0/MeditationTracker.apk new file mode 100644 index 0000000..3ab6213 Binary files /dev/null and b/MeditationTracker/release/1.0.0/MeditationTracker.apk differ diff --git a/MeditationTracker/release/1.0.1/MeditationTracker.apk b/MeditationTracker/release/1.0.1/MeditationTracker.apk new file mode 100644 index 0000000..0f1e7a9 Binary files /dev/null and b/MeditationTracker/release/1.0.1/MeditationTracker.apk differ diff --git a/MeditationTracker/res/drawable/diamond_mind_big.jpg b/MeditationTracker/res/drawable/diamond_mind_big.jpg new file mode 100644 index 0000000..139a60d Binary files /dev/null and b/MeditationTracker/res/drawable/diamond_mind_big.jpg differ diff --git a/MeditationTracker/res/drawable/guru_yoga_big.png b/MeditationTracker/res/drawable/guru_yoga_big.png new file mode 100644 index 0000000..db4d44b Binary files /dev/null and b/MeditationTracker/res/drawable/guru_yoga_big.png differ diff --git a/MeditationTracker/res/drawable/icon.png b/MeditationTracker/res/drawable/icon.png new file mode 100644 index 0000000..a07c69f Binary files /dev/null and b/MeditationTracker/res/drawable/icon.png differ diff --git a/MeditationTracker/res/drawable/icon_diamond_mind.png b/MeditationTracker/res/drawable/icon_diamond_mind.png new file mode 100644 index 0000000..0c2e97b Binary files /dev/null and b/MeditationTracker/res/drawable/icon_diamond_mind.png differ diff --git a/MeditationTracker/res/drawable/icon_guru_yoga.png b/MeditationTracker/res/drawable/icon_guru_yoga.png new file mode 100644 index 0000000..83d8ada Binary files /dev/null and b/MeditationTracker/res/drawable/icon_guru_yoga.png differ diff --git a/MeditationTracker/res/drawable/icon_karmapa.png b/MeditationTracker/res/drawable/icon_karmapa.png new file mode 100644 index 0000000..ae0bc65 Binary files /dev/null and b/MeditationTracker/res/drawable/icon_karmapa.png differ diff --git a/MeditationTracker/res/drawable/icon_mandala_offering.png b/MeditationTracker/res/drawable/icon_mandala_offering.png new file mode 100644 index 0000000..e03d0d2 Binary files /dev/null and b/MeditationTracker/res/drawable/icon_mandala_offering.png differ diff --git a/MeditationTracker/res/drawable/icon_refuge.png b/MeditationTracker/res/drawable/icon_refuge.png new file mode 100644 index 0000000..cb7120c Binary files /dev/null and b/MeditationTracker/res/drawable/icon_refuge.png differ diff --git a/MeditationTracker/res/drawable/karmapa.png b/MeditationTracker/res/drawable/karmapa.png new file mode 100644 index 0000000..97a5ba3 Binary files /dev/null and b/MeditationTracker/res/drawable/karmapa.png differ diff --git a/MeditationTracker/res/drawable/launcher_48.png b/MeditationTracker/res/drawable/launcher_48.png new file mode 100644 index 0000000..403a6c1 Binary files /dev/null and b/MeditationTracker/res/drawable/launcher_48.png differ diff --git a/MeditationTracker/res/drawable/launcher_72.png b/MeditationTracker/res/drawable/launcher_72.png new file mode 100644 index 0000000..810895d Binary files /dev/null and b/MeditationTracker/res/drawable/launcher_72.png differ diff --git a/MeditationTracker/res/drawable/mandala_offering_big.png b/MeditationTracker/res/drawable/mandala_offering_big.png new file mode 100644 index 0000000..b7baebb Binary files /dev/null and b/MeditationTracker/res/drawable/mandala_offering_big.png differ diff --git a/MeditationTracker/res/drawable/more.png b/MeditationTracker/res/drawable/more.png new file mode 100644 index 0000000..1c6f7b0 Binary files /dev/null and b/MeditationTracker/res/drawable/more.png differ diff --git a/MeditationTracker/res/drawable/refuge.png b/MeditationTracker/res/drawable/refuge.png new file mode 100644 index 0000000..89b03a7 Binary files /dev/null and b/MeditationTracker/res/drawable/refuge.png differ diff --git a/MeditationTracker/res/drawable/refuge_big.jpg b/MeditationTracker/res/drawable/refuge_big.jpg new file mode 100644 index 0000000..694b472 Binary files /dev/null and b/MeditationTracker/res/drawable/refuge_big.jpg differ diff --git a/MeditationTracker/res/drawable/top_logo.png b/MeditationTracker/res/drawable/top_logo.png new file mode 100644 index 0000000..9505ed6 Binary files /dev/null and b/MeditationTracker/res/drawable/top_logo.png differ diff --git a/MeditationTracker/res/drawable/top_logo_bg.png b/MeditationTracker/res/drawable/top_logo_bg.png new file mode 100644 index 0000000..e2b8146 Binary files /dev/null and b/MeditationTracker/res/drawable/top_logo_bg.png differ diff --git a/MeditationTracker/res/drawable/top_logo_no_text.png b/MeditationTracker/res/drawable/top_logo_no_text.png new file mode 100644 index 0000000..f24ea69 Binary files /dev/null and b/MeditationTracker/res/drawable/top_logo_no_text.png differ diff --git a/MeditationTracker/res/layout-land/session.xml b/MeditationTracker/res/layout-land/session.xml new file mode 100644 index 0000000..62a2dc5 --- /dev/null +++ b/MeditationTracker/res/layout-land/session.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/layout/about.xml b/MeditationTracker/res/layout/about.xml new file mode 100644 index 0000000..d1e697c --- /dev/null +++ b/MeditationTracker/res/layout/about.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/MeditationTracker/res/layout/main.xml b/MeditationTracker/res/layout/main.xml new file mode 100644 index 0000000..28b9bed --- /dev/null +++ b/MeditationTracker/res/layout/main.xml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/layout/menubar.xml b/MeditationTracker/res/layout/menubar.xml new file mode 100644 index 0000000..84c5036 --- /dev/null +++ b/MeditationTracker/res/layout/menubar.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/MeditationTracker/res/layout/new_meditation.xml b/MeditationTracker/res/layout/new_meditation.xml new file mode 100644 index 0000000..51136e9 --- /dev/null +++ b/MeditationTracker/res/layout/new_meditation.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MeditationTracker/res/layout/practice.xml b/MeditationTracker/res/layout/practice.xml new file mode 100644 index 0000000..4443ad2 --- /dev/null +++ b/MeditationTracker/res/layout/practice.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MeditationTracker/res/layout/practice_list_item.xml b/MeditationTracker/res/layout/practice_list_item.xml new file mode 100644 index 0000000..087bdcd --- /dev/null +++ b/MeditationTracker/res/layout/practice_list_item.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/layout/schedule.xml b/MeditationTracker/res/layout/schedule.xml new file mode 100644 index 0000000..0dedb21 --- /dev/null +++ b/MeditationTracker/res/layout/schedule.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/layout/session.xml b/MeditationTracker/res/layout/session.xml new file mode 100644 index 0000000..5fe9668 --- /dev/null +++ b/MeditationTracker/res/layout/session.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/menu/image_source.xml b/MeditationTracker/res/menu/image_source.xml new file mode 100644 index 0000000..0d610ef --- /dev/null +++ b/MeditationTracker/res/menu/image_source.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/MeditationTracker/res/menu/main_menu.xml b/MeditationTracker/res/menu/main_menu.xml new file mode 100644 index 0000000..abb2147 --- /dev/null +++ b/MeditationTracker/res/menu/main_menu.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/MeditationTracker/res/menu/practice_context_menu.xml b/MeditationTracker/res/menu/practice_context_menu.xml new file mode 100644 index 0000000..3598218 --- /dev/null +++ b/MeditationTracker/res/menu/practice_context_menu.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/MeditationTracker/res/menu/timer_menu.xml b/MeditationTracker/res/menu/timer_menu.xml new file mode 100644 index 0000000..98f7e42 --- /dev/null +++ b/MeditationTracker/res/menu/timer_menu.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/MeditationTracker/res/values-de/strings.xml b/MeditationTracker/res/values-de/strings.xml new file mode 100644 index 0000000..1f7ee03 --- /dev/null +++ b/MeditationTracker/res/values-de/strings.xml @@ -0,0 +1,57 @@ + + + Löschen + Öffnen + Fotografieren + Bild wählen + Klingelton + Vibrieren + Meditation hinzufügen + Countdown + Stopuhr + Stopuhr oder countdown? + + Ton + Session länge min. + Mala grösse + Mala grösse (leer für standarte) + Ngondro zeigen + + Einstellungen + + Meditation Tracker + Ngondro + Meine Meditationen + Guru Yoga + Zuflücht + Diamond Geist + #Mandala Offering + Übungs Name + Benötigte Menge + Abgeschlossene Menge + Speichern + Bild tippen für ändern + Bild Quelle + Starten + Zeitplan + Editiern + Geplannt für heute + Heute gemacht + Tag letztes Übung + Erwartete Abschlussdatum + Tägliche repetitionen + Abschlussdatum + Aktion wählen + Sie könenn den Ngondro nicht löschen. Wenn nicht gebraucht - kann man es im einstellungen ausschalten. + Fehler + Information + Möchten Sie wirklich dieses Übung löschen? + Bestätigen + Geplannt: + , fertig: + Wie viel zugeben? + Uhr stoppen + Uhr starten + Mala zugeben + Neues Zahl + diff --git a/MeditationTracker/res/values-ru/strings.xml b/MeditationTracker/res/values-ru/strings.xml new file mode 100644 index 0000000..1423c4d --- /dev/null +++ b/MeditationTracker/res/values-ru/strings.xml @@ -0,0 +1,57 @@ + + + Удалить + Открыть + Сфотографировать + Выбрать фото + Звук + Вибрация + Добавить медитацию + Обратный отсчёт + Секундомер + Секундомер или обратный отсчёт? + + Мелодия + Длинна сессии (мин). + Размер чёток + Размер чёток (оставьте пустым для стандартного) + Показывать нёндро + + Настройки + + Meditation Tracker + Нёндро + Мои медитации + Гуру йога + Прибежище + Алмазный ум + Дарение мандал + Название практики + Необходимое количество + Выполненое количество + Сохранить + Нажмите изображение, чтоб изменить + Источник изображения + Начать практику + Расписание + + Запланировано на сегодня + Выполнено сегодня + День прошлой практики + Ожидаемый день окончания + Ежедневных повторов + День окончания + Выберите действие + Нельзя удалить нёндро. Если оно не нужно - его можно скрыть в настройках. + Ошибка + Информация + Точно удалить практику? + Подтвердите + Запланировано: + , выполнено: + Сколько добавим? + Остановить таймер + Запустить таймер + Добавить + Задать число + diff --git a/MeditationTracker/res/values/attrs.xml b/MeditationTracker/res/values/attrs.xml new file mode 100644 index 0000000..9cb957f --- /dev/null +++ b/MeditationTracker/res/values/attrs.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/MeditationTracker/res/values/default_theme.xml b/MeditationTracker/res/values/default_theme.xml new file mode 100644 index 0000000..9f8c877 --- /dev/null +++ b/MeditationTracker/res/values/default_theme.xml @@ -0,0 +1,6 @@ + + + + diff --git a/MeditationTracker/res/values/dummy.xml b/MeditationTracker/res/values/dummy.xml new file mode 100644 index 0000000..583ca0e --- /dev/null +++ b/MeditationTracker/res/values/dummy.xml @@ -0,0 +1,8 @@ + + +1 +2 +3 +4 + + diff --git a/MeditationTracker/res/values/preference_keys.xml b/MeditationTracker/res/values/preference_keys.xml new file mode 100644 index 0000000..224e38c --- /dev/null +++ b/MeditationTracker/res/values/preference_keys.xml @@ -0,0 +1,13 @@ + + + prefTimerBuzz + Session end notification + prefTimerSound + prefUseStopWatch + prefBellSound + + prefSessionLength + prefMalaSize + prefShowNgondro +prefFirstRun + diff --git a/MeditationTracker/res/values/strings.xml b/MeditationTracker/res/values/strings.xml new file mode 100644 index 0000000..6025683 --- /dev/null +++ b/MeditationTracker/res/values/strings.xml @@ -0,0 +1,62 @@ + + + Delete + Open + Take photo + Pick picture + Sound + Buzz + Add meditation + Edit meditation + Countdown + Stopwatch + Stop watch or countdown? + + Play sound + Session length min. + Mala size + Mala size (leave empty for default) + Show Ngondro + + Settings + + Meditation Tracker + Ngondro + My meditations + Guru Yoga + Refuge + Diamond Mind + Mandala Offering + Practice name + Required repetitions + Completed repetitions + Save + Tap image to choose + Choose image source + Start practice + Schedule + Edit + Scheduled for today + Completed today + Last practice date + Scheduled completion date + Daily repetitions + Completion date + Choose action + You cannot delete Ngondro entries. If you\'re not interested in them - you can hide them in settings. + Error + Information + Are you sure you want to delete this practice? + Confirm deletion + Scheduled: + , completed: + How much shall we add this time? + Stop timer + Start timer + Add mala + Set count + + About... + Support/discussion + Go to app\'s blog + diff --git a/MeditationTracker/res/xml/preferences.xml b/MeditationTracker/res/xml/preferences.xml new file mode 100644 index 0000000..87e665a --- /dev/null +++ b/MeditationTracker/res/xml/preferences.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/MeditationTracker/src/com/meditationtracker/ActivityHistory.java b/MeditationTracker/src/com/meditationtracker/ActivityHistory.java new file mode 100644 index 0000000..7021236 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/ActivityHistory.java @@ -0,0 +1,43 @@ +package com.meditationtracker; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; + +import android.content.Intent; +import android.os.Bundle; +import android.text.format.DateFormat; + +public class ActivityHistory +{ + private static final int MAX_SIZE = 50; + private List history = new ArrayList(); + + + + public void logOnCreate(Bundle savedInstanceState, Intent intent) { + addEntry(String.format("OnCreate {%s %s}", savedInstanceState!=null ? savedInstanceState.toString() : "", intent != null ? intent.toString() : "")); + + } + + public void logOnActivityResult(int requestCode, int resultCode, Intent data) { + addEntry(String.format("OnActivityResult {%d %d %s}", requestCode, resultCode, data!=null ? data.toString() : "")); + } + + public String getLog() { + StringBuilder sb = new StringBuilder(); + for (String s : history) { + sb.append(s); + sb.append("\n"); + } + + return sb.toString(); + } + + private void addEntry(String entry) { + history.add(DateFormat.format("hh:mm:ss", Calendar.getInstance().getTime()) + ": " + entry); + if (history.size() > MAX_SIZE){ + history.remove(0); + } + } +} diff --git a/MeditationTracker/src/com/meditationtracker/DBActivity.java b/MeditationTracker/src/com/meditationtracker/DBActivity.java new file mode 100644 index 0000000..bcfc03a --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/DBActivity.java @@ -0,0 +1,22 @@ +package com.meditationtracker; + +import android.os.Bundle; + +public class DBActivity extends VerboseActivity +{ + protected static final int DONE_EDITING = 0; + protected PracticeDatabase db; + protected PracticeEntry practice; + protected long id; + + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + id = getIntent().getLongExtra(ExtraKeys.ID, -1); + + db = new PracticeDatabase(this); + if (id != -1){ + practice = db.getPractice(id); + } + } +} diff --git a/MeditationTracker/src/com/meditationtracker/ExtraKeys.java b/MeditationTracker/src/com/meditationtracker/ExtraKeys.java new file mode 100644 index 0000000..293da0b --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/ExtraKeys.java @@ -0,0 +1,14 @@ +package com.meditationtracker; + +public final class ExtraKeys +{ + public static final String ID = "id"; + public static final String CurrentCount = "currentCount"; + public static final String TotalCount = "totalCount"; + public static final String ImgURL = "imgUrl"; + public static final String ThumbURL = "thumbUrl"; + public static final String Title = "title"; + public static final String ScheduledCount = "scheduledCount"; + public static final String MalaCount = "malaCount"; + public static final String MalaSize = "malaSize"; +} diff --git a/MeditationTracker/src/com/meditationtracker/ImagePicker.java b/MeditationTracker/src/com/meditationtracker/ImagePicker.java new file mode 100644 index 0000000..8b212dc --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/ImagePicker.java @@ -0,0 +1,139 @@ +package com.meditationtracker; + +import java.io.File; + +import doo.util.Util; + +import android.app.Activity; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.DialogInterface.OnClickListener; +import android.net.Uri; +import android.os.Bundle; + +public class ImagePicker extends VerboseActivity +{ + private final String SDCARD_PATH = "/sdcard/"; //TODO: make it sdcard independent + private final String TEMP_PATH = SDCARD_PATH + "temp_picture.jpeg"; + public static final String TAKE_PICTURE = "take-picture"; + + private String cropFileName; + + private static final int SELECT_IMAGE = 0; + private static final int TAKE_PHOTO = 1; + private static final int REQUEST_CROP_PHOTO = 2; + + //private Uri imgCaptureUri; + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + if (getIntent().getBooleanExtra(TAKE_PICTURE, false)) + { + File tempFile = getTempFile(); + if (tempFile.exists()){ + tempFile.delete(); + } + startActivityForResult(new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE).putExtra(android.provider.MediaStore.EXTRA_OUTPUT, getTempUri()/*android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI*/), TAKE_PHOTO); + } + else + { + startActivityForResult(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI), SELECT_IMAGE); + } + } + + private Uri getTempUri() + { + return Uri.fromFile(getTempFile()); + } + + private File getTempFile() + { + return new File(TEMP_PATH); + } + + private void generateCropFileName(){ + cropFileName = Math.random() + ".jpg"; + } + + private File getCropFile() { + return new File(SDCARD_PATH + cropFileName); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + File cropFile = getCropFile(); + if (cropFile.exists()) + { + cropFile.delete(); + } + + if (resultCode != RESULT_OK) + { + setResult(Activity.RESULT_CANCELED); + finish(); + return; + } + + Uri uri = null; + switch (requestCode) { + case TAKE_PHOTO: + if ((data == null || (uri = data.getData()) == null) && getTempFile().exists()) { + uri = getTempUri(); + } + //cropImage(uri); + //break; + case SELECT_IMAGE: + generateCropFileName(); + cropImage(uri); + break; + case REQUEST_CROP_PHOTO: + setResult(Activity.RESULT_OK, new Intent(data)); + finish(); + break; + } + + } + + private void cropImage(Uri imgUri) + { + if (imgUri == null) { + setResult(Activity.RESULT_CANCELED); + Util.showWhateverError(this, "The image disappeared. Impermanence.", new OnClickListener() + { + public void onClick(DialogInterface dialog, int which) + { + ImagePicker.this.finish(); + } + }); + return; + } + + File cropFile = getCropFile(); + getTempFile().renameTo(cropFile); + + imgUri = Uri.fromFile(cropFile); + + Intent intent = new Intent("com.android.camera.action.CROP", imgUri); + intent.setDataAndType(imgUri, "image/*"); +/* if (myIntent.getStringExtra("mimeType") != null) { + intent.setDataAndType(myIntent.getData(), myIntent.getStringExtra("mimeType")); + }*/ + intent.putExtra("crop", true); + intent.putExtra("scale", true); + intent.putExtra("noFaceDetection", true); + intent.putExtra("return-data", true); + + intent.putExtra("aspectX", 150); + intent.putExtra("aspectY", 196); + intent.putExtra("outputX", 150); + intent.putExtra("outputY", 196); + startActivityForResult(intent, REQUEST_CROP_PHOTO); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/MainActivity.java b/MeditationTracker/src/com/meditationtracker/MainActivity.java new file mode 100644 index 0000000..1fa522b --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/MainActivity.java @@ -0,0 +1,267 @@ +package com.meditationtracker; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.DialogInterface.OnClickListener; +import android.os.Bundle; +import android.os.Environment; +import android.preference.PreferenceManager; +import android.util.Log; +import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewParent; +import android.view.ContextMenu.ContextMenuInfo; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; +import android.widget.Toast; +import android.widget.AdapterView.AdapterContextMenuInfo; +import android.widget.AdapterView.OnItemClickListener; + +public class MainActivity extends VerboseActivity +{ + protected static final int SETTINGS_DONE = 0; + protected static final int NEW_OR_EDIT_PRACTICE_DONE = 1; + protected static final int PRACTICE_DONE = 2; + private PracticeDatabase db; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main); + + db = new PracticeDatabase(this); + ensureNgondroDefaultsOnFirstRun(); + + UpdateUI(); + + String absolutePath = Environment.getExternalStorageDirectory().getAbsolutePath(); + Toast.makeText(this, absolutePath, Toast.LENGTH_LONG); + + } + + private void UpdateUI() + { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + + ListView lv = (ListView) findViewById(R.id.ngondroList); + + int ngondroVisible = preferences.getBoolean(getString(R.string.prefShowNgondro), true) ? View.VISIBLE + : View.GONE; + + lv.setVisibility(ngondroVisible); + findViewById(R.id.ngondroTitle).setVisibility(ngondroVisible); + findViewById(R.id.customPracticesTitle).setVisibility(ngondroVisible); + + SimpleCursorAdapter viewAdapter; + if (ngondroVisible != View.GONE) + { + viewAdapter = new SimpleCursorAdapter(this, R.layout.practice_list_item, db.getPracticesStatuses(true), + new String[] { PracticeDatabase.KEY_THUMBURL, PracticeDatabase.KEY_TITLE, PracticeDatabase.KEY_SCHEDULEDCOUNT, PracticeDatabase.KEY_DONE }, new int[] { + R.id.practiceImg, R.id.practiceTitle, R.id.scheduledText, R.id.completedText }); + viewAdapter.setViewBinder(new SmartViewBinder()); + + lv.setAdapter(viewAdapter); + registerForContextMenu(lv); + lv.setOnItemClickListener(practiceClick); + } + + lv = (ListView) findViewById(R.id.customList); + + viewAdapter = new SimpleCursorAdapter(this, R.layout.practice_list_item, db.getPracticesStatuses(false), + new String[] { PracticeDatabase.KEY_THUMBURL, PracticeDatabase.KEY_TITLE, PracticeDatabase.KEY_SCHEDULEDCOUNT, PracticeDatabase.KEY_DONE }, new int[] { + R.id.practiceImg, R.id.practiceTitle, R.id.scheduledText, R.id.completedText }); + viewAdapter.setViewBinder(new SmartViewBinder()); + + lv.setAdapter(viewAdapter); + registerForContextMenu(lv); + lv.setOnItemClickListener(practiceClick); + + //db.dumpNgondroStatus(); + } + + + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + // TODO Auto-generated method stub + super.onPostCreate(savedInstanceState); + } + + private void ensureNgondroDefaultsOnFirstRun() + { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + + if (preferences.getBoolean(getString(R.string.prefFirstRun), true) && !db.hasNgondroEntries(this)) + { + db.insertPractice(true, 0, getResources().getString(R.string.refuge), R.drawable.refuge, R.drawable.icon_refuge, 111111); + db.insertPractice(true, 1, getResources().getString(R.string.diamondMind), R.drawable.diamond_mind_big, R.drawable.icon_diamond_mind, + 111111); + db.insertPractice(true, 2, getResources().getString(R.string.mandalaOffering), + R.drawable.mandala_offering_big, R.drawable.icon_mandala_offering, 111111); + db.insertPractice(true, 3, getResources().getString(R.string.guruYoga), R.drawable.guru_yoga_big, R.drawable.icon_guru_yoga, 111111); + + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(getString(R.string.prefFirstRun), false); + editor.commit(); + } + } + + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main_menu, menu); + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.settingsMenuItem: + startActivityForResult(new Intent(this, SettingsActivity.class), SETTINGS_DONE); + + return true; + case R.id.addPracticeMenuItem: + editPractice(-1); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + switch (requestCode) + { + case SETTINGS_DONE: + break; + case NEW_OR_EDIT_PRACTICE_DONE: + if (resultCode == RESULT_OK) + { + + } + break; + case PRACTICE_DONE: + break; + default: + break; + } + + UpdateUI(); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) + { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.practice_context_menu, menu); + menu.setHeaderTitle(R.string.chooseAction); + } + + private void openPractice(long id) + { + startActivityForResult(new Intent(this, PracticeActivity.class).putExtra("id", id), PRACTICE_DONE); + } + + private void editPractice(long id) + { + startActivityForResult(new Intent(this, NewOrEditPracticeDBActivity.class).putExtra("id", id), + NEW_OR_EDIT_PRACTICE_DONE); + } + + private void deletePractice(long id) + { + db.deletePractice(id); + } + + private OnItemClickListener practiceClick = new OnItemClickListener() + { + + public void onItemClick(AdapterView parent, View view, int position, long id) + { + Log.d("MTRK", "selected: " + id); + openPractice(id); + } + }; + + @Override + public boolean onContextItemSelected(MenuItem item) + { + final AdapterContextMenuInfo menuInfo = (AdapterContextMenuInfo) item.getMenuInfo(); + + switch (item.getItemId()) + { + case R.id.openPractice: + openPractice(menuInfo.id); + break; + case R.id.editPractice: + // if (!isNgondroEditAction(menuInfo)) + editPractice(menuInfo.id); + break; + case R.id.deletePractice: + if (!isNgondroEditAction(menuInfo)) + { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.confirmDeletionMsg).setTitle(R.string.confirmDeletionTitle).setIcon( + android.R.drawable.ic_dialog_alert).setPositiveButton(android.R.string.yes, new OnClickListener() + { + public void onClick(DialogInterface dialog, int which) + { + deletePractice(menuInfo.id); + UpdateUI(); + } + }).setNegativeButton(android.R.string.no, null).show(); + + } + break; + } + return super.onContextItemSelected(item); + } + + private boolean isNgondroEditAction(AdapterContextMenuInfo info) + { + if (isChildOf(info.targetView, R.id.ngondroList)) + { + ShowNoEditNgondroMessage(); + return true; + } else + return false; + + } + + private void ShowNoEditNgondroMessage() + { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setMessage(R.string.msgNoEditNgondro).setTitle(R.string.info).setIcon( + android.R.drawable.ic_dialog_info).setPositiveButton(android.R.string.ok, null).show(); + + } + + private boolean isChildOf(View child, int parentId) + { + ViewParent cur = (ViewParent) child; + while (cur != null) + { + if (cur instanceof View) + if (((View) cur).getId() == parentId) + return true; + + cur = cur.getParent(); + } + + return false; + } +} \ No newline at end of file diff --git a/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeDBActivity.java b/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeDBActivity.java new file mode 100644 index 0000000..0b4996d --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeDBActivity.java @@ -0,0 +1,66 @@ +package com.meditationtracker; + +import doo.util.Pair; +import doo.util.Util; +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; + +public class NewOrEditPracticeDBActivity extends DBActivity +{ + private boolean isEdit; + + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + Intent screenIntent = new Intent(this, NewOrEditPracticeScreenActivity.class).putExtra(ExtraKeys.ID, id); + if (isEdit = (id != -1)){ + screenIntent.putExtra(ExtraKeys.Title, practice.getValues().getAsString(PracticeDatabase.KEY_TITLE)); + screenIntent.putExtra(ExtraKeys.ImgURL, practice.getValues().getAsString(PracticeDatabase.KEY_ICONURL)); + screenIntent.putExtra(ExtraKeys.ThumbURL, practice.getValues().getAsString(PracticeDatabase.KEY_THUMBURL)); + screenIntent.putExtra(ExtraKeys.TotalCount, practice.getValues().getAsInteger(PracticeDatabase.KEY_TOTALCOUNT)); + screenIntent.putExtra(ExtraKeys.CurrentCount, practice.getValues().getAsInteger(PracticeDatabase.KEY_DONE)); + screenIntent.putExtra(ExtraKeys.MalaSize, practice.getValues().getAsInteger(PracticeDatabase.KEY_MALASIZE)); + } + + startActivityForResult(screenIntent, DONE_EDITING); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + if (resultCode != Activity.RESULT_OK){ + setResult(Activity.RESULT_CANCELED); + } + else { + Bundle extras = data.getExtras(); + + String title = extras.getString(ExtraKeys.Title); + String imgUrl = extras.getString(ExtraKeys.ImgURL); + String thumbUrl = extras.getString(ExtraKeys.ThumbURL); + + Pair parsed = Util.tryParse(extras.getString(ExtraKeys.TotalCount)); + int totalCount = parsed._1 ? parsed._2.intValue() : 0; + + parsed = Util.tryParse(extras.getString(ExtraKeys.CurrentCount)); + int currentCount = parsed._1 ? parsed._2.intValue() : 0; + + parsed = Util.tryParse(extras.getString(ExtraKeys.MalaSize)); + int malaSize = parsed._1 ? parsed._2.intValue() : 0; + + if (isEdit) + db.updatePractice(new PracticeEntry((int)id, title, imgUrl, thumbUrl, totalCount, currentCount, malaSize)); + else + db.insertPractice(new PracticeEntry(title, imgUrl, thumbUrl, totalCount, currentCount, malaSize)); + + setResult(RESULT_OK); + } + + finish(); + } + + +} diff --git a/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeScreenActivity.java b/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeScreenActivity.java new file mode 100644 index 0000000..2062c34 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/NewOrEditPracticeScreenActivity.java @@ -0,0 +1,196 @@ +package com.meditationtracker; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; + +import com.meditationtracker.controls.MenuBar; + +import doo.util.Pair; +import doo.util.Util; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.net.Uri; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.MotionEvent; +import android.view.View; +import android.view.ContextMenu.ContextMenuInfo; +import android.view.View.OnClickListener; +import android.view.View.OnTouchListener; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +public class NewOrEditPracticeScreenActivity extends VerboseActivity +{ + private static final String THUMBNAIL_PREFIX = "th_"; + + private static final int SELECT_IMAGE = 0; + + private String imgUrl; + private String thumbUrl; + + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setResult(RESULT_CANCELED); + + setContentView(R.layout.new_meditation); + + Toast.makeText(this, getString(R.string.tapImgToChoose), Toast.LENGTH_SHORT).show(); + + View v = findViewById(R.id.practiceImage); + v.setOnTouchListener(imgTouchListener); + registerForContextMenu(v); + + String title = this.getString(R.string.newPractice); + + Bundle extras = getIntent().getExtras(); + if (extras.containsKey(ExtraKeys.ID) && extras.getLong(ExtraKeys.ID) != -1){ + + title = this.getString(R.string.editPractice); + + thumbUrl = extras.getString(ExtraKeys.ThumbURL); + imgUrl = extras.getString(ExtraKeys.ImgURL); + + Pair parsed = Util.tryParse(imgUrl); + if (parsed._1) + ((ImageView)v).setImageResource(parsed._2.intValue()); + else + if (imgUrl != null) + ((ImageView)v).setImageURI(Uri.parse(imgUrl)); + + ((TextView)findViewById(R.id.textPracticeName)).setText(extras.getString(ExtraKeys.Title)); + ((TextView)findViewById(R.id.textRepetitionCount)).setText(String.valueOf(extras.getInt(ExtraKeys.TotalCount))); + ((TextView)findViewById(R.id.textCompletedRepetitions)).setText(String.valueOf(extras.getInt(ExtraKeys.CurrentCount))); + + int malaSize = extras.getInt(ExtraKeys.MalaSize); + if (malaSize != 0) + { + ((TextView)findViewById(R.id.textMalaSize)).setText(String.valueOf(malaSize)); + } + } + + findViewById(R.id.saveButton).setOnClickListener(saveClicked); + ((MenuBar)findViewById(R.id.menuBar)).setText(title); + } + + private OnTouchListener imgTouchListener = new OnTouchListener() + { + public boolean onTouch(View v, MotionEvent event) + { + if (event.getAction() == MotionEvent.ACTION_UP){ + + /*startActivityForResult(Intent.createChooser( + new Intent(Intent.ACTION_GET_CONTENT). + addCategory(Intent.CATEGORY_OPENABLE). + setType("image/*"), getString(R.string.imageSourceTitle)), SELECT_IMAGE);*/ + openContextMenu(v); + } + return true; + } + }; + + @Override + public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) + { + super.onCreateContextMenu(menu, v, menuInfo); + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.image_source, menu); + menu.setHeaderTitle(R.string.imageSourceTitle); + } + + @Override + public boolean onContextItemSelected(MenuItem item) + { + switch (item.getItemId()) { + case R.id.browseImage: + startActivityForResult(new Intent(this, ImagePicker.class).putExtra(ImagePicker.TAKE_PICTURE, false), SELECT_IMAGE); + return true; + case R.id.takePhoto: + startActivityForResult(new Intent(this, ImagePicker.class).putExtra(ImagePicker.TAKE_PICTURE, true), SELECT_IMAGE); + return true; + } + + return super.onContextItemSelected(item); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + if (resultCode != RESULT_OK) + return; + + ImageView v = (ImageView)findViewById(R.id.practiceImage); + if (requestCode == SELECT_IMAGE) { + final Bundle extras = data.getExtras(); + if (extras != null) { + Bitmap photo = extras.getParcelable("data"); + if (photo != null) { + FileOutputStream fos; + try + { + File mainImageFile = File.createTempFile("img", ".png", getFilesDir()); + String practiceImageName = mainImageFile.getName(); + + fos = openFileOutput(practiceImageName, Context.MODE_PRIVATE); + photo.compress(Bitmap.CompressFormat.PNG, 95, fos); + fos.close(); + + fos = openFileOutput(THUMBNAIL_PREFIX + practiceImageName, Context.MODE_PRIVATE); + Bitmap.createScaledBitmap(photo, 35, 46, false).compress(Bitmap.CompressFormat.JPEG, 95, fos); + fos.close(); + + imgUrl = PracticeImageProvider.URI_PREFIX + File.separator + practiceImageName; + thumbUrl = PracticeImageProvider.URI_PREFIX + File.separator + THUMBNAIL_PREFIX + practiceImageName; + v.setImageURI(Uri.parse(imgUrl)); + + updateResult(); + } catch (FileNotFoundException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + } + } + + private OnClickListener saveClicked = new OnClickListener() + { + public void onClick(View v) + { + updateResult(); + finish(); + } + }; + + + private void updateResult() + { + setResult(Activity.RESULT_OK, + new Intent(). + putExtra(ExtraKeys.ImgURL, imgUrl == null ? String.valueOf(R.drawable.karmapa) : imgUrl). + putExtra(ExtraKeys.ThumbURL, thumbUrl == null ? String.valueOf(R.drawable.icon_karmapa) : thumbUrl). + putExtra(ExtraKeys.Title, ((TextView)findViewById(R.id.textPracticeName)).getText().toString()). + putExtra(ExtraKeys.TotalCount, ((TextView)findViewById(R.id.textRepetitionCount)).getText().toString()). + putExtra(ExtraKeys.CurrentCount, ((TextView)findViewById(R.id.textCompletedRepetitions)).getText().toString()). + putExtra(ExtraKeys.MalaSize, ((TextView)findViewById(R.id.textMalaSize)).getText().toString())); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/NoScrollListView.java b/MeditationTracker/src/com/meditationtracker/NoScrollListView.java new file mode 100644 index 0000000..2d7dc5e --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/NoScrollListView.java @@ -0,0 +1,49 @@ +package com.meditationtracker; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.widget.ListView; + +public class NoScrollListView extends ListView +{ + + public NoScrollListView(Context context) + { + super(context, null); + } + + public NoScrollListView(Context context, AttributeSet attrs) + { + super(context, attrs); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) + { + super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0) /*heightMeasureSpec*/); + + int childHeight = getMeasuredHeight() - (getListPaddingTop() + getListPaddingBottom() + getVerticalFadingEdgeLength() * 2); + + // on a first run let's have a space for at least one child so it'll trigger remeasurement + int fullHeight = getListPaddingTop() + getListPaddingBottom() + /*getVerticalFadingEdgeLength() * 2*/ + childHeight*(getCount()); + + int newChildHeight = 0; + for (int x = 0; x parsed = Util.tryParse(imgUrl); + if (parsed._1) + ((ImageView) findViewById(R.id.imgPractice)).setImageResource(parsed._2.intValue()); + else if (imgUrl != null) + ((ImageView) findViewById(R.id.imgPractice)).setImageURI(Uri.parse(imgUrl)); + + } else + { + //TODO: do an error here, we cannot go into non-existent practice + } + } + + private void calculateScheduledEnd() + { + Pair scheduledCountParsed = Util.tryParse(scheduledCount); + + if (scheduledCountParsed._1 && scheduledCountParsed._2 != 0) { + Pair totalCountParsed = Util.tryParse(totalCount); + Pair currentCountParsed = Util.tryParse(currentCount); + + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, (int) ((totalCountParsed._2-currentCountParsed._2)/scheduledCountParsed._2) + 1); + + ((TextView) findViewById(R.id.textScheduledEndDate)).setText(Util.formatCalendar(cal, this)); + } + else + ((TextView) findViewById(R.id.textScheduledEndDate)).setText("-"); + } + + private String setText(int fieldId, String dbKey, PracticeEntry practice) + { + String result; + ((TextView) findViewById(fieldId)).setText(result = practice.getValues().getAsString(dbKey)); + + return result; + } + + private OnClickListener scheduleClicked = new OnClickListener() + { + public void onClick(View v) + { + startActivityForResult(new Intent(PracticeActivity.this, ScheduleActivity.class).putExtra( + ExtraKeys.ScheduledCount, scheduledCount).putExtra(ExtraKeys.TotalCount, totalCount).putExtra( + ExtraKeys.CurrentCount, currentCount), SCHEDULE_CHANGED); + } + }; + + private OnClickListener editClicked = new OnClickListener() + { + public void onClick(View v) + { + startActivityForResult(new Intent(PracticeActivity.this, NewOrEditPracticeDBActivity.class).putExtra( + ExtraKeys.ID, id), PRACTICE_CHANGED); + } + }; + + private OnClickListener startClicked = new OnClickListener() + { + public void onClick(View v) + { + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(PracticeActivity.this); + + long malaSize = 108; + + if (customMalaSize > 0) + { + malaSize = customMalaSize; + } + else + { + Pair parsed = Util.tryParse(preferences.getString(getString(R.string.prefMalaSize), "108")); + if (parsed._1){ + malaSize = parsed._2.intValue(); + } + } + + startActivityForResult( + new Intent(PracticeActivity.this, SessionActivity.class). + putExtra(ExtraKeys.ImgURL, imgUrl). + putExtra(ExtraKeys.MalaSize, malaSize). + putExtra(ExtraKeys.Title, title), + SESSION_DONE); + } + + + }; + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + super.onActivityResult(requestCode, resultCode, data); + + if (resultCode != RESULT_OK) + return; + + switch (requestCode) + { + case SCHEDULE_CHANGED: + if (data.hasExtra(ExtraKeys.ScheduledCount)) + { + practice.getValues().put(PracticeDatabase.KEY_SCHEDULEDCOUNT, + data.getLongExtra(ExtraKeys.ScheduledCount, 0)); + db.updatePractice(practice); + } + break; + case PRACTICE_CHANGED: + break; + case SESSION_DONE: + /*SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + int malaSize = 108; + Pair parsed = Util.tryParse(preferences.getString(getString(R.string.prefMalaSize), "108")); + if (parsed._1){ + malaSize = parsed._2.intValue(); + }*/ + + int addCount = data.getExtras().getInt(ExtraKeys.MalaCount); + if (addCount != 0) { + db.insertSession((int) id, addCount); + } + } + + updateView(); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/PracticeDatabase.java b/MeditationTracker/src/com/meditationtracker/PracticeDatabase.java new file mode 100644 index 0000000..406799f --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/PracticeDatabase.java @@ -0,0 +1,395 @@ +package com.meditationtracker; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.Map.Entry; + +import android.content.ContentValues; +import android.content.Context; +import android.database.Cursor; +import android.database.SQLException; +import android.database.sqlite.SQLiteDatabase; +import android.database.sqlite.SQLiteOpenHelper; +import android.database.sqlite.SQLiteStatement; +import android.provider.BaseColumns; +import android.util.Log; + +public class PracticeDatabase +{ + private static final String MTRK_LOG_KEY = "MTRK"; + private static final String DBNAME = "MediTracker"; + private static final int DBVERSION = 1; + + private static final String PRACTICE_TABLE_NAME = "Practices"; + private static final String PRACTICE_HISTORY_TABLE_NAME = "PracticeHistory"; + private static final String DONE_TODAY_VIEW_NAME = "DONE_TODAY"; + + public static final String KEY_ISNGONDRO = "ISNGONDRO"; + public static final String KEY_ORDER = "SORT_ORDER"; + public static final String KEY_TITLE = "TITLE"; + public static final String KEY_TOTALCOUNT = "TOTALCOUNT"; + public static final String KEY_SCHEDULEDCOMPLETION = "SCHEDULEDCOMPLETION"; + public static final String KEY_SCHEDULEDCOUNT = "SCHEDULEDCOUNT"; + public static final String KEY_ICONURL = "ICONURL"; + public static final String KEY_THUMBURL = "THUMBURL"; + public static final String KEY_MALASIZE = "MALASIZE"; + + public static final String KEY_DONE = "DONE"; + public static final String KEY_DONE_PERC = "DONE_PERC"; + public static final String KEY_DONE_TODAY = "DONE_TODAY"; + public static final String KEY_LAST_PRACTICE = "LAST_PRACTICE"; + + public static final String KEY_PRACTICE_ID = "PRACTICE_ID"; + public static final String KEY_DATE = "PRACTICE_DATE"; + public static final String KEY_COUNT = "DONE_COUNT"; + + private static final String PRACTICE_TABLE_CREATE = "CREATE TABLE " + PRACTICE_TABLE_NAME + " (" + + BaseColumns._ID + " INTEGER PRIMARY KEY, " + + KEY_ISNGONDRO + " BOOLEAN NOT NULL DEFAULT 0, " + + KEY_ORDER + " INTEGER NOT NULL, " + + KEY_TITLE + " TEXT NOT NULL, " + + KEY_ICONURL + " TEXT NOT NULL, " + + KEY_THUMBURL + " TEXT NOT NULL, " + + KEY_TOTALCOUNT + " INTEGER NOT NULL DEFAULT 111111, " + + KEY_SCHEDULEDCOUNT + " INTEGER NOT NULL DEFAULT 0, " + + KEY_MALASIZE + " INTEGER NOT NULL DEFAULT 0) "; + //KEY_SCHEDULEDCOMPLETION + " TEXT NOT NULL DEFAULT 0)"; + + private static final String PRACTICE_HISTORY_TABLE_CREATE = "CREATE TABLE " + PRACTICE_HISTORY_TABLE_NAME + " (" + + BaseColumns._ID + " INTEGER PRIMARY KEY, " + + KEY_PRACTICE_ID + " INTEGER NOT NULL, " + + KEY_DATE + " TEXT default CURRENT_DATE, " + + KEY_COUNT + " INTEGER NOT NULL) "; + + private static final String DONE_TODAY_VIEW_CREATE = String.format( + "CREATE VIEW '%s' AS SELECT %s, SUM(%s) AS %s " + + "FROM %s WHERE %s = CURRENT_DATE GROUP BY %s", + DONE_TODAY_VIEW_NAME, KEY_PRACTICE_ID, KEY_COUNT, KEY_DONE_TODAY, + PRACTICE_HISTORY_TABLE_NAME, KEY_DATE, KEY_PRACTICE_ID); + + + + private static final String INSERT_PRACTICE_QUERY = "INSERT INTO " + PRACTICE_TABLE_NAME + " (" + + KEY_ISNGONDRO + ", " + + KEY_ORDER + ", " + + KEY_TITLE + ", " + + KEY_ICONURL + ", " + + KEY_THUMBURL + ", " + + KEY_TOTALCOUNT + ") " + + "VALUES (?, ?, ?, ?, ?, ?)"; + + private static final String INSERT_SESSION_QUERY = "INSERT INTO " + PRACTICE_HISTORY_TABLE_NAME + " (" + + KEY_PRACTICE_ID + ", " + KEY_DATE + ", " + KEY_COUNT + ") " + " VALUES (?, ?, ?)"; + + private static final String INSERT_TODAY_SESSION_QUERY = "INSERT INTO " + PRACTICE_HISTORY_TABLE_NAME + " (" + + KEY_PRACTICE_ID + ", " + KEY_COUNT + ") " + " VALUES (?, ?)"; + + private static final String NGONDRO_CHEK_QUERY = "SELECT COUNT(" + BaseColumns._ID + ") FROM " + PRACTICE_TABLE_NAME + + " WHERE " + KEY_ISNGONDRO + " = 1"; + + private static final String PRACTICES_STATUS_PREFIX = String.format("SELECT p.%s AS %s, %s, %s, %s, %s, %s, %s, " + + "IFNULL(SUM(%s), 0) as %s, IFNULL(100.0*SUM(%s)/%s, 0) as %s, IFNULL(MAX(%s), 0) AS %s, " + + "IFNULL (dt.%s, 0) AS %s " + + "FROM %s p LEFT JOIN %s ph ON p.%s = ph.%s " + + "LEFT JOIN %s dt ON dt.%s = p.%s ", + + BaseColumns._ID, BaseColumns._ID, KEY_ICONURL, KEY_THUMBURL, KEY_TITLE, KEY_TOTALCOUNT, KEY_SCHEDULEDCOUNT, KEY_MALASIZE, + KEY_COUNT, KEY_DONE, KEY_COUNT, KEY_TOTALCOUNT, KEY_DONE_PERC, KEY_DATE, KEY_LAST_PRACTICE, + KEY_DONE_TODAY, KEY_DONE_TODAY, + PRACTICE_TABLE_NAME, PRACTICE_HISTORY_TABLE_NAME, BaseColumns._ID, KEY_PRACTICE_ID, + DONE_TODAY_VIEW_NAME, KEY_PRACTICE_ID, BaseColumns._ID); + + private static final String PRACTICES_STATUS_SUFFIX = String.format("GROUP BY p.%s ORDER BY %s", BaseColumns._ID, KEY_ORDER); + + private static final String PRACTICES_STATUS = String.format( + PRACTICES_STATUS_PREFIX + "WHERE %s = ? " + PRACTICES_STATUS_SUFFIX, KEY_ISNGONDRO); + + private static final String SINGLE_PRACTICE_STATUS = String.format( + PRACTICES_STATUS_PREFIX + "WHERE p.%s = ? " + PRACTICES_STATUS_SUFFIX, BaseColumns._ID); + + + /*private static final String TODAY_DONE = String.format( + "SELECT %s, SUM(%s) as %s " + + "FROM %s WHERE %s=CURRENT_DATE GROUP BY %s", + KEY_PRACTICE_ID, KEY_DONE, KEY_DONE_TODAY, + PRACTICE_HISTORY_TABLE_NAME, KEY_DATE, KEY_PRACTICE_ID);*/ + + + + private static final String PRACTICE_DONE_COUNT = "SELECT SUM(" + KEY_COUNT + ") FROM " + PRACTICE_HISTORY_TABLE_NAME + " WHERE " + KEY_PRACTICE_ID + " = ?"; + private static final String NEXT_SORT_ORDER = "SELECT MAX(" + KEY_ORDER + ")+1 as " + KEY_ORDER + " FROM " + PRACTICE_TABLE_NAME; + + private static SQLiteDatabase db; + + private SQLiteStatement insertQueryPractice; + private SQLiteStatement insertQuerySession; + private SQLiteStatement insertTodayQuerySession; + private SQLiteStatement queryNgondroPresence; + private SQLiteStatement queryNextSortOrder; + + private static HashMap> tableColumns; + + public PracticeDatabase(Context ctx) + { + if (db == null) + { + MySQLiteOpenHelper helper = new MySQLiteOpenHelper(ctx); + db = helper.getWritableDatabase(); + } + + insertQueryPractice = db.compileStatement(INSERT_PRACTICE_QUERY); + queryNgondroPresence = db.compileStatement(NGONDRO_CHEK_QUERY); + insertQuerySession = db.compileStatement(INSERT_SESSION_QUERY); + insertTodayQuerySession = db.compileStatement(INSERT_TODAY_SESSION_QUERY); + queryNextSortOrder = db.compileStatement(NEXT_SORT_ORDER); + + if (tableColumns == null){ + tableColumns = new HashMap>(); + + getTableColumnsNames(PRACTICE_TABLE_NAME); + getTableColumnsNames(PRACTICE_HISTORY_TABLE_NAME); + } + } + + private void getTableColumnsNames(String tableName) + { + Cursor c = db.rawQuery("SELECT * FROM " + tableName, null); + HashSet columns = new HashSet(); + for (String col : c.getColumnNames()){ + columns.add(col); + } + tableColumns.put(tableName, columns); + c.close(); + } + + public void insertPractice(boolean isNgondro, int order, String title, int iconId, int thumbId, int totalCount) + { + insertPractice(isNgondro, order, title, String.valueOf(iconId), String.valueOf(thumbId), totalCount); + } + + public void insertPractice(boolean isNgondro, int order, String title, String iconUrl, String thumbUrl, int totalCount) + { + insertQueryPractice.clearBindings(); + insertQueryPractice.bindLong(1, isNgondro ? 1l : 0l); + insertQueryPractice.bindLong(2, order); + insertQueryPractice.bindString(3, title); + insertQueryPractice.bindString(4, iconUrl); + insertQueryPractice.bindString(5, thumbUrl); + insertQueryPractice.bindLong(6, totalCount); + + insertQueryPractice.executeInsert(); + } + + public boolean hasNgondroEntries(Context ctx) + { + return queryNgondroPresence.simpleQueryForLong() != 0; + } + + /* + * public List getPractices(boolean ngondro){ Cursor q = + * db.rawQuery(PRACTICES_STATUS, new String [] {ngondro ? "1" : "0"}); + * List result = new ArrayList(); + * + * if (q.moveToFirst()) do{ result.add(new PracticeEntry(q)); } while + * (q.moveToNext()); + * + * return result; } + */ + + public PracticeEntry getPractice(long id) + { + /*Cursor c = db.query(PRACTICE_TABLE_NAME, new String[] { "*" }, BaseColumns._ID + " = ?", new String[] { String + .valueOf(id) }, null, null, null);*/ + + Cursor c = db.rawQuery(SINGLE_PRACTICE_STATUS.replaceFirst("\\?", String.valueOf(id)), /* new String[] { String.valueOf(id) }*/null); + + PracticeEntry entry = new PracticeEntry(c); + c.close(); + return entry; + } + + public void updatePractice(PracticeEntry entry) + { + int affected; + + // sanitize input so we insert only valid data + ContentValues values = sanitizeColumns(entry); + + if ((affected = db.update(PRACTICE_TABLE_NAME, values, BaseColumns._ID + " = ?", new String[] { String + .valueOf(entry.getId()) })) != 1) + { + throw new SQLException(String.format("Affected %d rows instead just one during update.", affected)); + } + + + long currentCount = getDoneCount(entry); + if (currentCount != entry.getCurrentCount()) { + db.delete(PRACTICE_HISTORY_TABLE_NAME, KEY_PRACTICE_ID + " = ? AND " + KEY_DATE + "=0", new String[] { String.valueOf(entry.getId()) }); + + currentCount = getDoneCount(entry); + + insertSession(entry.getId(), "0", (int) (entry.getCurrentCount() - currentCount)); + } + } + + private ContentValues sanitizeColumns(PracticeEntry entry) + { + ContentValues originals = entry.getValues(); + ContentValues values = new ContentValues(originals); + for (Entry e : originals.valueSet()) + { + if (!tableColumns.get(PRACTICE_TABLE_NAME).contains(e.getKey())){ + values.remove(e.getKey()); + } + + } + return values; + } + + private long getDoneCount(PracticeEntry entry) + { + long result; + Cursor c = db.rawQuery(PRACTICE_DONE_COUNT, new String[] { String.valueOf(entry.getId()) }); + c.moveToFirst(); + result = c.getLong(0); + c.close(); + + return result; + } + + public void insertSession(int practiceId, int count) { + insertTodayQuerySession.clearBindings(); + insertTodayQuerySession.bindLong(1, practiceId); + insertTodayQuerySession.bindLong(2, count); + + insertTodayQuerySession.executeInsert(); + } + + public void insertSession(int practiceId, String date, int count) { + insertQuerySession.clearBindings(); + insertQuerySession.bindLong(1, practiceId); + insertQuerySession.bindString(2, date); + insertQuerySession.bindLong(3, count); + + insertQuerySession.executeInsert(); + } + + public void insertPractice(PracticeEntry entry) + { + //ContentValues entryValues = entry.getValues(); + patchMissingDefaults(entry); + ContentValues entryValues = sanitizeColumns(entry); + long columnId; + if ((columnId = db.insert(PRACTICE_TABLE_NAME, null, entryValues)) == -1) + { + throw new SQLException("There was an error inserting new row."); + } + + entry.getValues().put(BaseColumns._ID, columnId); + + updatePractice(entry); + } + + private void patchMissingDefaults(PracticeEntry entry) + { + if (!entry.getValues().containsKey(KEY_ISNGONDRO)){ + entry.getValues().put(KEY_ISNGONDRO, false); + } + + if (!entry.getValues().containsKey(KEY_ORDER)){ + entry.getValues().put(KEY_ORDER, queryNextSortOrder.simpleQueryForLong()); + } + + /*if (!values.containsKey(KEY_SCHEDULEDCOMPLETION)){ + + values.put(KEY_SCHEDULEDCOMPLETION, 0); + }*/ + } + + public void deletePractice(long id) + { + int affected; + + db.delete(PRACTICE_HISTORY_TABLE_NAME, BaseColumns._ID + " = ?", new String[] { String.valueOf(id) }); + if ((affected = db.delete(PRACTICE_TABLE_NAME, BaseColumns._ID + " = ?", new String[] { String.valueOf(id) })) != 1) + { + throw new SQLException(String.format("Affected %d rows instead just one during deletion.", affected)); + } + } + + public Cursor getPracticesStatuses(boolean ngondroGroup) + { + return db.rawQuery(PRACTICES_STATUS.replaceFirst("\\?", ngondroGroup ? "1" : "0"), /* + * new + * String + * [ + * ] + * { + * "1" + * } + */null); + } + + //TODO: remove me + public Cursor dumpNgondroStatus() + { + Cursor q = db.rawQuery(PRACTICES_STATUS.replaceFirst("\\?", "1"), /* + * new + * String + * [] + * {"1"} + */null); + + if (q != null && q.moveToFirst()) + { + String row = ""; + + for (String s : q.getColumnNames()) + row += s + " |\t"; + + Log.d(MTRK_LOG_KEY, row); + do + { + // result.add(new PracticeEntry(q)); + + row = ""; + for (int x = 0; x < q.getColumnCount(); x++) + { + row += q.getString(x) + " |\t"; + } + + Log.d(MTRK_LOG_KEY, row); + + } while (q.moveToNext()); + } else + Log.d(MTRK_LOG_KEY, "no data returned from query"); + + q.requery(); + + return q; + } + + private static class MySQLiteOpenHelper extends SQLiteOpenHelper + { + public MySQLiteOpenHelper(Context context) + { + super(context, DBNAME, null, DBVERSION); + } + + @Override + public void onCreate(SQLiteDatabase db) + { + db.execSQL(PRACTICE_TABLE_CREATE); + db.execSQL(PRACTICE_HISTORY_TABLE_CREATE); + db.execSQL(DONE_TODAY_VIEW_CREATE); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) + { + // TODO Auto-generated method stub + + } + } +} \ No newline at end of file diff --git a/MeditationTracker/src/com/meditationtracker/PracticeEntry.java b/MeditationTracker/src/com/meditationtracker/PracticeEntry.java new file mode 100644 index 0000000..1fbcdf6 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/PracticeEntry.java @@ -0,0 +1,68 @@ +package com.meditationtracker; + +import android.content.ContentValues; +import android.database.Cursor; +import android.provider.BaseColumns; + +public class PracticeEntry +{ + /* + * private int resourceIdIcon; private int resourceIdTitle; private int + * totalCount; + * + * private long scheduledCompletion; private long lastPracticed; + */ + + private ContentValues values; + + public PracticeEntry(Cursor q) + { + int columnCount = q.getColumnCount(); + values = new ContentValues(columnCount); + if (q.moveToFirst()) + { + for (int x = 0; x parsed = Util.tryParse(val); + if (parsed._1){ + totalCount = parsed._2; + } + else + { + //TODO: error and exit + } + + ((TextView)findViewById(R.id.textCompletedRepetitions)).setText(val = extras.getString(ExtraKeys.CurrentCount)); + parsed = Util.tryParse(val); + if (parsed._1){ + currentCount = parsed._2; + } + else + { + //TODO: error and exit + } + + + scheduleCountText = (EditText)findViewById(R.id.textScheduledForToday); + scheduleCountText.setText(extras.getString(ExtraKeys.ScheduledCount)); + scheduleCountText.addTextChangedListener(textChangedListener); + //scheduleCountText.setOnKeyListener(keyPressListener); + } + + DatePicker dp = (DatePicker)findViewById(R.id.pickerScheduledEndDate); + dp.init(2010, 01, 01, onDateChangedListener); + + updatePicker(); + } + + private boolean softUpdate; + + protected void updatePicker() + { + if (softUpdate) + return; + + softUpdate = true; + + try { + DatePicker dp = (DatePicker)findViewById(R.id.pickerScheduledEndDate); + + String scheduledString = ((TextView)findViewById(R.id.textScheduledForToday)).getText().toString(); + Pair parsed = Util.tryParse(scheduledString); + if (parsed._1 && parsed._2 != 0){ + long remainingDays = (totalCount - currentCount) / parsed._2 + 1; + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, (int)remainingDays); + + dp.updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); + + setResult(RESULT_OK, new Intent().putExtra(ExtraKeys.ScheduledCount, parsed._2)); + } + } + catch(Exception ignore) {} // depending on theme min/max values for date picker vary and thus can throw + + softUpdate = false; + + } + + protected void updateCount(int year, int monthOfYear, int dayOfMonth) + { + if (softUpdate) + return; + + softUpdate = true; + + try { + Calendar now = Calendar.getInstance(); + now.add(Calendar.DAY_OF_YEAR, 1); + + Calendar then = Calendar.getInstance(); + then.set(year, monthOfYear, dayOfMonth); + + if (then.after(now)) { + long days = (then.getTimeInMillis() - now.getTimeInMillis()) / (1000*60*60*24) + 1; + + long newCount = Math.round(((double)(totalCount - currentCount % totalCount)) / days); + scheduleCountText.setText(String.valueOf(newCount < 1 ? 1 : newCount)); + + setResult(RESULT_OK, new Intent().putExtra(ExtraKeys.ScheduledCount, newCount)); + } + } + catch(Exception ignore) {} + + softUpdate = false; + } + + + private TextWatcher textChangedListener = new TextWatcher() + { + public void onTextChanged(CharSequence s, int start, int before, int count) + { + updatePicker(); + } + + public void beforeTextChanged(CharSequence s, int start, int count, int after) + { + // TODO Auto-generated method stub + + } + + public void afterTextChanged(Editable s) + { + // TODO Auto-generated method stub + + } + }; + + private OnDateChangedListener onDateChangedListener = new OnDateChangedListener() + { + public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) + { + updateCount(year, monthOfYear, dayOfMonth); + } + }; +} diff --git a/MeditationTracker/src/com/meditationtracker/SessionActivity.java b/MeditationTracker/src/com/meditationtracker/SessionActivity.java new file mode 100644 index 0000000..341a2b9 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/SessionActivity.java @@ -0,0 +1,298 @@ +package com.meditationtracker; + +import com.meditationtracker.controls.MenuBar; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.SharedPreferences; +import android.media.MediaPlayer; +import android.net.Uri; +import android.os.Bundle; +import android.os.CountDownTimer; +import android.os.Vibrator; +import android.preference.PreferenceManager; +import android.text.InputType; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.EditText; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.TextView.SavedState; +import doo.util.Pair; +import doo.util.Util; + +public class SessionActivity extends VerboseActivity +{ + private static final String CURRENT_COUNT = "CURRENT_COUNT"; + + protected static final int DIALOG_CHANGE_MALA_COUNT = 0; + + protected int malaCount; + + protected int sessionLength; + protected long malaSize; + protected boolean doStopwatch; + protected boolean doSessionEndSound; + protected String sessionEndSoundUrl; + protected boolean doSessionEndBuzz; + + protected static CountDownTimer timer; + protected static TextView timerView; + + + @Override + public void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + setContentView(R.layout.session); + + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + updateUI(); + } + + private void updateUI() + { + Bundle extras = getIntent().getExtras(); + if (extras != null) { + String imgUrl = extras.getString(ExtraKeys.ImgURL); + Pair parsed = Util.tryParse(imgUrl); + if (parsed._1) + ((ImageView)findViewById(R.id.imgPractice)).setImageResource(parsed._2.intValue()); + else + ((ImageView)findViewById(R.id.imgPractice)).setImageURI(Uri.parse(imgUrl)); + + malaSize = extras.getLong(ExtraKeys.MalaSize); + + String practiceTitle = extras.getString(ExtraKeys.Title); + ((MenuBar)findViewById(R.id.menuBar)).setText(practiceTitle); + //((TextView) findViewById(R.id.textPracticeName)).setText(practiceTitle); + } + + Button btnAdd = (Button)findViewById(R.id.addMalaButton); + btnAdd.setOnClickListener(addMalaClick); + btnAdd.setText(String.format("%s (%d)", getString(R.string.addMala), malaSize)); + + //findViewById(R.id.textMalaCount).setOnKeyListener(malaCountChanged); + + ((Button)findViewById(R.id.editMalaButton)).setOnClickListener(editMalaClick); + + SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this); + + doStopwatch = preferences.getBoolean(getString(R.string.prefUseStopWatch), true); + + Pair parsed = Util.tryParse(preferences.getString(getString(R.string.prefSessionLength), "10")); + sessionLength = 10 * 60; + if (parsed._1) + sessionLength = parsed._2.intValue()*60; + + doSessionEndSound = preferences.getBoolean(getString(R.string.prefTimerSound), false); + sessionEndSoundUrl = preferences.getString(getString(R.string.prefBellSound), ""); + doSessionEndBuzz = preferences.getBoolean(getString(R.string.prefTimerBuzz), false); + + timerView = (TextView) findViewById(R.id.textTimer); + + updateTimer(sessionLength*1000); + } + + + + @Override + protected void onRestoreInstanceState(Bundle savedInstanceState) { + super.onRestoreInstanceState(savedInstanceState); + + malaCount = savedInstanceState.getInt(CURRENT_COUNT); + updateResult(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + + outState.putInt(CURRENT_COUNT, malaCount); + } + + private void updateTimer(long time) + { + long h = time / 3600000; + long m = (time - h * 3600000) / 60000; + long s = (time / 1000) % 60; + if (timer != null) + { + timerView.setVisibility(View.VISIBLE); + timerView.setText(String.format("%02d:%02d:%02d", h, m, s)); + } + } + + private void updateResult() + { + setResult(RESULT_OK, new Intent().putExtra(ExtraKeys.MalaCount, malaCount)); + ((TextView)findViewById(R.id.textViewMalaCount)).setText(String.valueOf(malaCount)); + } + + private void startTimer() { + stopTimer(); + + timer = new CountDownTimer(sessionLength * 1000, 1000) + { + + @Override + public void onFinish() + { + updateTimer(0); + + if (doSessionEndBuzz) + { + vibrate(1000); + } + + if (doSessionEndSound) + { + MediaPlayer mp = new MediaPlayer(); + try + { + mp.setDataSource(sessionEndSoundUrl); + mp.prepare(); + mp.start(); + } catch (Exception e) + { + e.printStackTrace(); + } + } + + } + + @Override + public void onTick(long millisUntilFinished) + { + long time = millisUntilFinished; + if (doStopwatch) + time = sessionLength * 1000 - millisUntilFinished; + + updateTimer(time); + + } + + }.start(); + } + + private void stopTimer() { + if (timer != null) { + timer.cancel(); + timer = null; + } + updateTimer(sessionLength*1000); + timerView.setVisibility(View.GONE); + } + + public boolean onCreateOptionsMenu(Menu menu) + { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.timer_menu, menu); + return true; + } + + public boolean onOptionsItemSelected(MenuItem item) + { + switch (item.getItemId()) + { + case R.id.startTimerMenuItem: + startTimer(); + return true; + case R.id.stopTimerMenuItem: + stopTimer(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + + private OnClickListener addMalaClick = new OnClickListener() + { + public void onClick(View v) + { + malaCount+=malaSize; + updateResult(); + + vibrate(50); + } + }; + + private OnClickListener editMalaClick = new OnClickListener() { + @Override + public void onClick(View v) { + SessionActivity.this.showDialog(DIALOG_CHANGE_MALA_COUNT); + } + }; + + private EditText editTextMalaCount; + + @Override + protected Dialog onCreateDialog(int id) { + editTextMalaCount = new EditText(this); + editTextMalaCount.setInputType(InputType.TYPE_CLASS_NUMBER); + editTextMalaCount.setText(String.valueOf(malaCount)); + + return new AlertDialog.Builder(SessionActivity.this) + .setPositiveButton(android.R.string.ok, onEditMalaOkClick) + .setNegativeButton(android.R.string.cancel, null) + .setView(editTextMalaCount) + .setTitle(R.string.setMalaCount).create(); + } + + private android.content.DialogInterface.OnClickListener onEditMalaOkClick = new android.content.DialogInterface.OnClickListener() { + + @Override + public void onClick(DialogInterface dialog, int which) { + updateMalaCount(editTextMalaCount.getText().toString()); + } + }; + + private void updateMalaCount(CharSequence s) { + Pair parsed = Util.tryParse(s.toString()); + if (parsed._1){ + malaCount = parsed._2.intValue(); + } + else { + malaCount = 0; + } + + updateResult(); + } + + /*private TextWatcher textChangedWatcher = new TextWatcher() + { + + public void onTextChanged(CharSequence s, int start, int before, int count) + { + if (s == null) + return; + + updateMalaCount(s); + } + + + public void beforeTextChanged(CharSequence s, int start, int count, int after) + { + } + + public void afterTextChanged(Editable s) + { + } + };*/ + + protected void vibrate(int duration) + { + Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE); + vibrator.vibrate(duration); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/SettingsActivity.java b/MeditationTracker/src/com/meditationtracker/SettingsActivity.java new file mode 100644 index 0000000..56df427 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/SettingsActivity.java @@ -0,0 +1,17 @@ +package com.meditationtracker; + +import android.preference.PreferenceActivity; +import android.os.Bundle; + +public class SettingsActivity extends PreferenceActivity +{ + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + addPreferencesFromResource(R.xml.preferences); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/SmartViewBinder.java b/MeditationTracker/src/com/meditationtracker/SmartViewBinder.java new file mode 100644 index 0000000..bf96c52 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/SmartViewBinder.java @@ -0,0 +1,44 @@ +package com.meditationtracker; + +import doo.util.Pair; +import doo.util.Util; + +import android.database.Cursor; +import android.net.Uri; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.SimpleCursorAdapter.ViewBinder; + +public class SmartViewBinder implements ViewBinder +{ + + public boolean setViewValue(View view, Cursor cursor, int columnIndex) + { + String textToBind = cursor.getString(columnIndex); + if (textToBind == null) + return false; + + if (view instanceof ImageView) { + ImageView imgView = (ImageView)view; + + Pair parsed = Util.tryParse(textToBind); + if (parsed._1){ + imgView.setImageResource(parsed._2.intValue()); + } + else { + // it's an url + imgView.setImageURI(Uri.parse(textToBind)); + } + } + else if (view instanceof TextView) { + ((TextView)view).setText(textToBind); + } + else + return false; + + + return true; + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/SupportActor.java b/MeditationTracker/src/com/meditationtracker/SupportActor.java new file mode 100644 index 0000000..9d8a8d0 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/SupportActor.java @@ -0,0 +1,16 @@ +package com.meditationtracker; + +import android.content.Intent; +import android.net.Uri; +import android.preference.Preference; + +import com.meditationtracker.preferences.ActionPreference; + +public class SupportActor implements ActionPreference.IActor { + + @Override + public void act(Preference preference, String param) { + preference.getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(param))); + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/VerboseActivity.java b/MeditationTracker/src/com/meditationtracker/VerboseActivity.java new file mode 100644 index 0000000..85dd5b7 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/VerboseActivity.java @@ -0,0 +1,66 @@ +package com.meditationtracker; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.Writer; +import java.lang.Thread.UncaughtExceptionHandler; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.os.Environment; + +public class VerboseActivity extends Activity +{ + private static UncaughtExceptionHandler defaultUncaughtExceptionHandler; + private static ActivityHistory activityHistory; + + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) + { + if (defaultUncaughtExceptionHandler == null) { + defaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler(); + Thread.setDefaultUncaughtExceptionHandler(loggingExceptionHandler); + + activityHistory = new ActivityHistory(); + } + + activityHistory.logOnCreate(savedInstanceState, getIntent()); + + super.onCreate(savedInstanceState); + } + + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent data) + { + activityHistory.logOnActivityResult(requestCode, resultCode, data); + super.onActivityResult(requestCode, resultCode, data); + } + + private UncaughtExceptionHandler loggingExceptionHandler = new UncaughtExceptionHandler() + { + public void uncaughtException(Thread thread, Throwable ex) + { + try { + final Writer result = new StringWriter(); + final PrintWriter printWriter = new PrintWriter(result); + ex.printStackTrace(printWriter); + String stacktrace = result.toString(); + printWriter.close(); + + BufferedWriter bos = new BufferedWriter(new FileWriter(Environment.getExternalStorageDirectory().getAbsolutePath() + "/meditracker.crash.log")); + bos.write(ex.toString() + "\n\n" + stacktrace + "\n\n" + activityHistory.getLog()); + bos.flush(); + bos.close(); + + } catch(Exception e) { + + } + + defaultUncaughtExceptionHandler.uncaughtException(thread, ex); + } + }; +} diff --git a/MeditationTracker/src/com/meditationtracker/controls/MenuBar.java b/MeditationTracker/src/com/meditationtracker/controls/MenuBar.java new file mode 100644 index 0000000..3a92fc6 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/controls/MenuBar.java @@ -0,0 +1,34 @@ +package com.meditationtracker.controls; + +import com.meditationtracker.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.view.View; +import android.widget.LinearLayout; +import android.widget.TextView; + +public class MenuBar extends LinearLayout { + private View view; + + public MenuBar(Context context, AttributeSet attrs) { + super(context, attrs); + + view = View.inflate(context, R.layout.menubar, null); + + // XXX: WTF?! + view.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT)); + + addView(view); + + TypedArray a=getContext().obtainStyledAttributes(attrs,R.styleable.MenuBar); + setText(a.getString(R.styleable.MenuBar_text)); + } + + public void setText(String text) { + ((TextView)view.findViewById(R.id.textWindowTitle)).setText(text); + } + + +} diff --git a/MeditationTracker/src/com/meditationtracker/persistence/Practice.java b/MeditationTracker/src/com/meditationtracker/persistence/Practice.java new file mode 100644 index 0000000..1a6af9c --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/persistence/Practice.java @@ -0,0 +1,121 @@ +package com.meditationtracker.persistence; + +import java.util.Collection; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; + +@Entity(name = "Practices") +public class Practice { + @Id + @GeneratedValue + private int id; + + @Column(name="ISNGONDRO", nullable = false, columnDefinition = "default false") + private Boolean isNgondro; + + @Column(name="SORT_ORDER", nullable = false) + private int sortOrder; + + @Column(name="TITLE", nullable = false) + private String title; + + @Column(name="ICONURL", nullable = false) + private String iconURL; + + @Column(name="THUMBURL", nullable = false) + private String thumbURL; + + @Column(name="TOTALCOUNT", nullable = false, columnDefinition = "default 111111") + private int totalCount; + +// @Column(name="SCHEDULEDCOMPLETION") + @Column(name="SCHEDULEDCOUNT", nullable = false) + private int scheduleCount; + + @Column(name="MALASIZE", nullable = false, columnDefinition = "default 0") + private int malaSize; + + @OneToMany + @JoinColumn(name="PRACTICE_ID") + private Collection history; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public Boolean getIsNgondro() { + return isNgondro; + } + + public void setIsNgondro(Boolean isNgondro) { + this.isNgondro = isNgondro; + } + + public int getSortOrder() { + return sortOrder; + } + + public void setSortOrder(int sortOrder) { + this.sortOrder = sortOrder; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getIconURL() { + return iconURL; + } + + public void setIconURL(String iconURL) { + this.iconURL = iconURL; + } + + public String getThumbURL() { + return thumbURL; + } + + public void setThumbURL(String thumbURL) { + this.thumbURL = thumbURL; + } + + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getScheduleCount() { + return scheduleCount; + } + + public void setScheduleCount(int scheduleCount) { + this.scheduleCount = scheduleCount; + } + + public int getMalaSize() { + return malaSize; + } + + public void setMalaSize(int malaSize) { + this.malaSize = malaSize; + } + + + +} diff --git a/MeditationTracker/src/com/meditationtracker/persistence/PracticeHistory.java b/MeditationTracker/src/com/meditationtracker/persistence/PracticeHistory.java new file mode 100644 index 0000000..3a42c0b --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/persistence/PracticeHistory.java @@ -0,0 +1,56 @@ +package com.meditationtracker.persistence; + +import java.util.Date; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity(name = "PracticeHistory") +public class PracticeHistory { + @Id + @GeneratedValue + int id; + + @Column(name="PRACTICE_ID", nullable = false) + private int practiceId; + + @Column(name="PRACTICE_DATE", nullable = false, columnDefinition = "default CURRENT_DATE") + private Date practiceDate; + + @Column(name="DONE_COUNT", nullable = false) + private int doneCount; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getPracticeId() { + return practiceId; + } + + public void setPracticeId(int practiceId) { + this.practiceId = practiceId; + } + + public Date getPracticeDate() { + return practiceDate; + } + + public void setPracticeDate(Date practiceDate) { + this.practiceDate = practiceDate; + } + + public int getDoneCount() { + return doneCount; + } + + public void setDoneCount(int doneCount) { + this.doneCount = doneCount; + } +} diff --git a/MeditationTracker/src/com/meditationtracker/preferences/ActionPreference.java b/MeditationTracker/src/com/meditationtracker/preferences/ActionPreference.java new file mode 100644 index 0000000..a542d7e --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/preferences/ActionPreference.java @@ -0,0 +1,39 @@ +package com.meditationtracker.preferences; + +import com.meditationtracker.R; + +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.Preference; +import android.util.AttributeSet; +import android.widget.Toast; + +public class ActionPreference extends Preference { + public interface IActor { + void act(Preference preference, String param); + } + + private String actorClass; + private String actionParam; + + public ActionPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a=getContext().obtainStyledAttributes(attrs,R.styleable.ActionPreference); + actorClass = a.getString(R.styleable.ActionPreference_actor); + actionParam = a.getString(R.styleable.ActionPreference_param); + } + + @Override + protected void onClick() { + try { + Class actor = Class.forName(actorClass); + Object newInstance = actor.getConstructor((Class[])null).newInstance((Object[])null); + + ((IActor)newInstance).act(this, actionParam); + } catch (Exception e) { + Toast.makeText(getContext(), "Failed acting with class " + actorClass + "\n"+e, Toast.LENGTH_LONG).show(); + } } + + +} diff --git a/MeditationTracker/src/com/meditationtracker/preferences/ChattyEditTextPreference.java b/MeditationTracker/src/com/meditationtracker/preferences/ChattyEditTextPreference.java new file mode 100644 index 0000000..c9fde14 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/preferences/ChattyEditTextPreference.java @@ -0,0 +1,44 @@ +package com.meditationtracker.preferences; + +import android.content.Context; +import android.preference.EditTextPreference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public abstract class ChattyEditTextPreference extends EditTextPreference { + + public ChattyEditTextPreference(Context context) { + this(context, null); + } + + public ChattyEditTextPreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /*@Override + protected void onBindView(View view) { + super.onBindView(view); + + updateChattySummary(); + }*/ + + @Override + protected View onCreateView(ViewGroup parent) + { + updateChattySummary(); + return super.onCreateView(parent); + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + super.onDialogClosed(positiveResult); + updateChattySummary(); + } + + protected void updateChattySummary() { + setSummary(getChattySummary()); + } + + protected abstract CharSequence getChattySummary(); +} diff --git a/MeditationTracker/src/com/meditationtracker/preferences/ChattyIntPreference.java b/MeditationTracker/src/com/meditationtracker/preferences/ChattyIntPreference.java new file mode 100644 index 0000000..d7685fc --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/preferences/ChattyIntPreference.java @@ -0,0 +1,24 @@ +package com.meditationtracker.preferences; + +import android.content.Context; +import android.text.InputType; +import android.util.AttributeSet; + +public class ChattyIntPreference extends ChattyEditTextPreference { + public ChattyIntPreference(Context context) { + this(context, null); + } + + public ChattyIntPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + getEditText().setInputType(InputType.TYPE_CLASS_NUMBER); + } + + @Override + protected CharSequence getChattySummary() { + String text = getText(); + return text; + } + +} diff --git a/MeditationTracker/src/com/meditationtracker/preferences/ChattyRingtonePreference.java b/MeditationTracker/src/com/meditationtracker/preferences/ChattyRingtonePreference.java new file mode 100644 index 0000000..1967851 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/preferences/ChattyRingtonePreference.java @@ -0,0 +1,43 @@ +package com.meditationtracker.preferences; + +import android.content.Context; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.preference.RingtonePreference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class ChattyRingtonePreference extends RingtonePreference { + public ChattyRingtonePreference(Context context) { + this(context, null); + } + + public ChattyRingtonePreference(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected View onCreateView(ViewGroup parent) + { + updateChattySummary(onRestoreRingtone()); + return super.onCreateView(parent); + } + + @Override + protected void onSaveRingtone(Uri ringtoneUri) + { + super.onSaveRingtone(ringtoneUri); + updateChattySummary(ringtoneUri); + + } + + protected void updateChattySummary(Uri ringtoneUri) { + Ringtone ringtone = RingtoneManager.getRingtone(this.getContext(), ringtoneUri); + if (ringtone != null) + { + setSummary(ringtone.getTitle(this.getContext())); + } + } +} diff --git a/MeditationTracker/src/com/meditationtracker/preferences/ShowDialogPreference.java b/MeditationTracker/src/com/meditationtracker/preferences/ShowDialogPreference.java new file mode 100644 index 0000000..b100d75 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/preferences/ShowDialogPreference.java @@ -0,0 +1,37 @@ +package com.meditationtracker.preferences; + +import com.meditationtracker.R; + +import android.app.Dialog; +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.DialogPreference; +import android.util.AttributeSet; +import android.view.View; + +public class ShowDialogPreference extends DialogPreference { + + private int layoutId; + + public ShowDialogPreference(Context context, AttributeSet attrs) { + super(context, attrs); + + TypedArray a=getContext().obtainStyledAttributes(attrs,R.styleable.ShowDialogPreferece); + layoutId = a.getResourceId(R.styleable.ShowDialogPreferece_layout, -1); + + this.setDialogTitle(getTitle()); + } + + @Override + protected void onClick() { + this.showDialog(null); + } + + @Override + protected View onCreateDialogView() { + new View(getContext()); + return View.inflate(getContext(), layoutId, null); + } + + +} diff --git a/MeditationTracker/src/com/meditationtracker/util/Pair.java b/MeditationTracker/src/com/meditationtracker/util/Pair.java new file mode 100644 index 0000000..450af65 --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/util/Pair.java @@ -0,0 +1,15 @@ +package com.meditationtracker.util; + +public class Pair +{ + public T _1; + public U _2; + + public Pair() {} + + public Pair(T _1, U _2) + { + this._1 = _1; + this._2 = _2; + } +} diff --git a/MeditationTracker/src/com/meditationtracker/util/Util.java b/MeditationTracker/src/com/meditationtracker/util/Util.java new file mode 100644 index 0000000..27b65fc --- /dev/null +++ b/MeditationTracker/src/com/meditationtracker/util/Util.java @@ -0,0 +1,120 @@ +package com.meditationtracker.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Calendar; +import java.util.Date; + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface.OnClickListener; +import android.text.format.DateFormat; +import android.util.Log; + +public final class Util +{ + public static void showWhateverError(Context ctx, String message, OnClickListener okClick){ + AlertDialog.Builder builder = new AlertDialog.Builder(ctx); + builder.setMessage(message).setTitle(android.R.string.dialog_alert_title).setIcon( + android.R.drawable.ic_dialog_alert).setPositiveButton(android.R.string.ok, okClick).show(); + + } + + public static Calendar parseSqliteDate(String date) { + Calendar cal = Calendar.getInstance(); + + String[] parts = date.split("-"); + if (parts.length != 3) + return cal; + + //int[] partPositions = new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}; + int[] ymd = new int[3]; + + for (int x=0; x<3; x++) { + Pair parsed = Util.tryParse(parts[x]); + //cal.set(partPositions[x], parsed._2.intValue()); + ymd[x] = parsed._2.intValue(); + } + + cal.set(ymd[0], ymd[1]-1, ymd[2]); + + + return cal; + } + + public static String formatCalendar(Calendar cal, Context ctx) { + Date time = cal.getTime(); + + return DateFormat.getDateFormat(ctx).format(time); + } + + public static Pair tryParse(String value) { + Pair result = new Pair(); + try { + result._2 = Long.parseLong(value); + result._1 = true; + } catch(Exception e) { + result._1 = false; + } + + return result; + } + + public static class Reflection + { + + public static void dumpDeclareds(Object on) + { + dumpDeclareds(on.getClass()); + } + + public static void dumpDeclareds(Class onClass) + { + if (onClass == null) + return; + + Log.d("MTRK", "Methods for class: " + onClass.getSimpleName()); + for (Method m : onClass.getDeclaredMethods()) + { + Log.d("MTRK", m.getName()); + } + + dumpDeclareds(onClass.getSuperclass()); + } + + public static Object invokePrivateMethod(Class declaringClass, Object on, String methodName, + Class[] paramTypes, Object... args) + { + try + { + Method m = declaringClass.getDeclaredMethod(methodName, (Class[]) paramTypes); + m.setAccessible(true); + return m.invoke(on, args); + } catch (SecurityException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + Util.Reflection.dumpDeclareds(on); + } catch (IllegalArgumentException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; + } + } + +} diff --git a/dootil/AndroidManifest.xml b/dootil/AndroidManifest.xml new file mode 100644 index 0000000..f7fa0d7 --- /dev/null +++ b/dootil/AndroidManifest.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/dootil/res/drawable/icon.png b/dootil/res/drawable/icon.png new file mode 100644 index 0000000..a07c69f Binary files /dev/null and b/dootil/res/drawable/icon.png differ diff --git a/dootil/res/layout/main.xml b/dootil/res/layout/main.xml new file mode 100644 index 0000000..3a5f117 --- /dev/null +++ b/dootil/res/layout/main.xml @@ -0,0 +1,12 @@ + + + + diff --git a/dootil/res/layout/timepicker.xml b/dootil/res/layout/timepicker.xml new file mode 100644 index 0000000..b5eb6d6 --- /dev/null +++ b/dootil/res/layout/timepicker.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/dootil/res/values/strings.xml b/dootil/res/values/strings.xml new file mode 100644 index 0000000..4c77b6e --- /dev/null +++ b/dootil/res/values/strings.xml @@ -0,0 +1,5 @@ + + + Hello World! + dootil + diff --git a/dootil/src/doo/alarm/AlarmHelper.java b/dootil/src/doo/alarm/AlarmHelper.java new file mode 100644 index 0000000..87c6c21 --- /dev/null +++ b/dootil/src/doo/alarm/AlarmHelper.java @@ -0,0 +1,89 @@ +package doo.alarm; + +import java.util.Calendar; + +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.widget.Toast; + +public class AlarmHelper +{ + + private static final Intent ACTION_ALARM_CHANGED = new Intent("android.intent.action.ALARM_CHANGED"); + + + public static void updateAlarmState(Context ctx, Boolean enabled, + int alarmTime, int alarmId, Class alarmReceiverClass, Class notificaionActionClass) + { + updateAlarm(ctx, enabled, alarmTime, alarmId, alarmReceiverClass); + //updateNotification(ctx, enabled, alarmTime, alarmId, notificaionActionClass); + } + + protected static void updateAlarm(Context ctx, Boolean enabled, + int alarmTime, int alarmId, Class alarmReceiverClass) + { + AlarmOperator operator = new AlarmOperator(ctx); + + operator.removeAlarm(alarmReceiverClass, Integer.toString(alarmId)); + + if (enabled) + { + Calendar calNow = Calendar.getInstance(); + calNow.setTimeInMillis(System.currentTimeMillis()); + Calendar futureTime = Calendar.getInstance(); + + futureTime.set(1, 1, 1, alarmTime / 60, alarmTime % 60); + + long millisecondsAfter = AlarmOperator.GetMillisecondsAfter(calNow, + futureTime); + operator.setAlarm(alarmReceiverClass, millisecondsAfter, Integer + .toString(alarmId)); + + int dueInHours = (int) (millisecondsAfter / (60 * 60 * 1000)); + long dueInMinutes = (millisecondsAfter / (60 * 1000)) % 60; + Toast.makeText( + ctx, + "Alarm is set due in about " + + (dueInHours != 0 ? dueInHours + " hours and " + : "") + dueInMinutes + " minute" + + (dueInMinutes != 1 ? "s" : ""), + Toast.LENGTH_SHORT).show(); + + } + updateStatusBarIcon(ctx, enabled); + } + + protected static void updateStatusBarIcon(Context context, boolean enabled) { + Intent alarmChanged = new Intent(ACTION_ALARM_CHANGED); + alarmChanged.putExtra("alarmSet", enabled); + context.sendBroadcast(alarmChanged); + } + + + protected static void updateNotification(Context ctx, Boolean enabled, int alarmTime, int alarmId, Class notificaionActionClass) + { + NotificationManager nm = (NotificationManager)ctx.getSystemService(Context.NOTIFICATION_SERVICE); + + if (!enabled || notificaionActionClass == null) + { + nm.cancelAll(); + } + else + { + Notification notification = new Notification(android.R.drawable.ic_lock_idle_alarm, null, System.currentTimeMillis()); + Intent dummyIntent = new Intent(ctx, notificaionActionClass); + PendingIntent dummyPending = PendingIntent.getActivity(ctx, 0, dummyIntent, 0/*PendingIntent.FLAG_NO_CREATE*/); + int hours = alarmTime / 60; + int minutes = alarmTime % 60; + notification.setLatestEventInfo(ctx, "Alarm is on", "It will fire at " + hours + ":" + (minutes<10 ? "0"+minutes : minutes), dummyPending); + + notification.flags |= Notification.FLAG_NO_CLEAR | Notification.FLAG_ONGOING_EVENT; + nm.notify(alarmId, notification); + } + } + +} diff --git a/dootil/src/doo/alarm/AlarmOperator.java b/dootil/src/doo/alarm/AlarmOperator.java new file mode 100644 index 0000000..22856f3 --- /dev/null +++ b/dootil/src/doo/alarm/AlarmOperator.java @@ -0,0 +1,72 @@ +package doo.alarm; + +import java.util.Calendar; + +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public class AlarmOperator +{ + private static final int REQUEST_CODE = 0; + private Context context; + + public AlarmOperator(Context ctx) + { + this.context = ctx; + } + + public void setAlarm(Class alarmClass, long millisecondsAfterNow, String alarmMessage) + { + setAlarm(alarmClass, millisecondsAfterNow, 24 * 60 * 60 * 1000, alarmMessage); + } + + public void setAlarm(Class alarmClass, long millisecondsAfterNow, long millisecondsInterval, String alarmMessage) + { + PendingIntent pendingIntent = generateIntent(alarmClass, alarmMessage); + + AlarmManager manager = getNotificationManager(); + + manager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + millisecondsAfterNow, millisecondsInterval, pendingIntent); + } + + private PendingIntent generateIntent(Class alarmClass, String alarmMessage) + { + Intent intent = new Intent(context, alarmClass); + intent.setAction(alarmMessage); + + PendingIntent pendingIntent = PendingIntent.getBroadcast(context, REQUEST_CODE, intent, 0); + return pendingIntent; + } + + public void removeAlarm(Class alarmClass, String alarmMessage) + { + PendingIntent pendingIntent = generateIntent(alarmClass, alarmMessage); + + AlarmManager manager = getNotificationManager(); + manager.cancel(pendingIntent); + } + + /** + * @param futureTime, only time as HH:MM:00 will be taken in account + * @param pastTime, start point for calculation, normally "now" + * @return milliseconds between pastTime and nearest future at futureTime + */ + public static long GetMillisecondsAfter(Calendar pastTime, Calendar futureTime) + { + Calendar future = Calendar.getInstance(); + future.set(pastTime.get(Calendar.YEAR), pastTime.get(Calendar.MONTH), pastTime.get(Calendar.DAY_OF_MONTH), futureTime.get(Calendar.HOUR_OF_DAY), futureTime.get(Calendar.MINUTE), 0); + future.set(Calendar.MILLISECOND, pastTime.get(Calendar.MILLISECOND)); + + long result = future.getTimeInMillis() - pastTime.getTimeInMillis(); + + return result <= 0 ? result + (24 * 60 * 60 * 1000) : result; + } + + private AlarmManager getNotificationManager() + { + return (AlarmManager)context.getSystemService(Context.ALARM_SERVICE); + } +} diff --git a/dootil/src/doo/android/BroadcastActivityStarter.java b/dootil/src/doo/android/BroadcastActivityStarter.java new file mode 100644 index 0000000..53b615a --- /dev/null +++ b/dootil/src/doo/android/BroadcastActivityStarter.java @@ -0,0 +1,33 @@ +package doo.android; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; + +public abstract class BroadcastActivityStarter extends BroadcastReceiver { + + @Override + public void onReceive(Context context, Intent intent) { + Intent activityIntent = new Intent(); + activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + activityIntent.setClass(context, getActivityClass()); + activityIntent.putExtras(intent.getExtras()); + + try + { + Integer.parseInt(intent.getAction()); + + activityIntent.setAction(intent.getAction()); + } catch (NumberFormatException e) + { + e.printStackTrace(); + + activityIntent.setAction("WEIRD|" + intent.getAction()); + } + + context.startActivity(activityIntent); + } + + protected abstract Class getActivityClass(); + +} diff --git a/dootil/src/doo/android/Locker.java b/dootil/src/doo/android/Locker.java new file mode 100644 index 0000000..960fc46 --- /dev/null +++ b/dootil/src/doo/android/Locker.java @@ -0,0 +1,44 @@ +package doo.android; + +import android.app.KeyguardManager; +import android.app.KeyguardManager.KeyguardLock; +import android.content.Context; +import android.os.PowerManager; +import android.os.PowerManager.WakeLock; + +public class Locker { + + public static WakeLock wakeThePhone(Context ctx) + { + return wakeThePhone(ctx, ctx.getClass().getName()); + } + + public static WakeLock wakeThePhone(Context ctx, String tag) + { + return getWakeLock(ctx, tag, PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP); + } + + public static WakeLock getWakeLock(Context ctx, String tag, int flags) + { + final PowerManager powerManager = (PowerManager) ctx.getSystemService(Context.POWER_SERVICE); + WakeLock wakeLock = powerManager.newWakeLock(flags, tag); + wakeLock.acquire(); + + return wakeLock; + } + + public static KeyguardLock disableKeyGuard(Context ctx) + { + return disableKeyGuard(ctx, ctx.getClass().getName()); + } + + public static KeyguardLock disableKeyGuard(Context ctx, String tag) + { + KeyguardManager keyguardManager = (KeyguardManager) ctx.getSystemService(Context.KEYGUARD_SERVICE); + KeyguardLock keyLock = keyguardManager.newKeyguardLock(tag); + keyLock.disableKeyguard(); + + return keyLock; + } + +} diff --git a/dootil/src/doo/file/FileHelper.java b/dootil/src/doo/file/FileHelper.java new file mode 100644 index 0000000..e949e65 --- /dev/null +++ b/dootil/src/doo/file/FileHelper.java @@ -0,0 +1,39 @@ +package doo.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import android.os.Environment; + +public class FileHelper { + public static void copy(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dst); + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + in.close(); + out.flush(); + out.close(); + } + + public static void quickWriteToFile(File name, String text) throws IOException{ + FileWriter out = new FileWriter(name); + out.write(text); + + out.flush(); + out.close(); + } + + public static void quickWriteToSDRoot(String fileName, String text) throws IOException { + quickWriteToFile(new File(Environment.getExternalStorageDirectory() + File.separator + fileName), text); + } +} diff --git a/dootil/src/doo/persistence/XmlPersistor.java b/dootil/src/doo/persistence/XmlPersistor.java new file mode 100644 index 0000000..f2e1bc4 --- /dev/null +++ b/dootil/src/doo/persistence/XmlPersistor.java @@ -0,0 +1,30 @@ +package doo.persistence; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import org.simpleframework.xml.core.Persister; + +public class XmlPersistor { + public static T loadFrom(Class clazz, String fileName) throws Exception { + InputStream is = new FileInputStream(fileName); + return loadFrom(clazz, is); + } + + public static T loadFrom(Class clazz, InputStream openFileInput) throws Exception { + Persister ser = new Persister(); + return ser.read(clazz, openFileInput); + } + + public static void saveTo(T instance, String fileName) throws Exception { + OutputStream os = new FileOutputStream(fileName); + saveTo(instance, os); + } + + public static void saveTo(T instance, OutputStream os) throws Exception { + Persister ser = new Persister(); + ser.write(instance, os); + } +} diff --git a/dootil/src/doo/settings/ButtonPreference.java b/dootil/src/doo/settings/ButtonPreference.java new file mode 100644 index 0000000..1dbb67e --- /dev/null +++ b/dootil/src/doo/settings/ButtonPreference.java @@ -0,0 +1,23 @@ +package doo.settings; + +import android.content.Context; +import android.preference.Preference; +import android.util.AttributeSet; + +public class ButtonPreference extends Preference +{ + public ButtonPreference(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + } + + public ButtonPreference(Context context, AttributeSet attrs) + { + super(context, attrs, 0); + } + + public ButtonPreference(Context context) + { + super(context, null); + } +} diff --git a/dootil/src/doo/settings/TimePreference.java b/dootil/src/doo/settings/TimePreference.java new file mode 100644 index 0000000..c7c6235 --- /dev/null +++ b/dootil/src/doo/settings/TimePreference.java @@ -0,0 +1,119 @@ +package doo.settings; + +import android.content.Context; +import android.os.Parcelable; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TimePicker; +import android.widget.TimePicker.OnTimeChangedListener; +import doo.util.root.R; + +public class TimePreference extends Preference implements OnTimeChangedListener +{ + private TimePicker timePicker; + + public TimePreference(Context context, AttributeSet attrs, int defStyle) + { + super(context, attrs, defStyle); + } + + public TimePreference(Context context, AttributeSet attrs) + { + super(context, attrs); + } + + public TimePreference(Context context) + { + super(context); + } + + public int getTimeInMinutes() + { + return getPersistedInt(0); + } + + @Override + protected View onCreateView(ViewGroup parent) + { + if (timePicker == null) + { + this.setLayoutResource(R.layout.timepicker); + + View view = super.onCreateView(parent); + TimePicker timePicker = (TimePicker) view + .findViewById(R.id.prefTimePicker); + timePicker.setIs24HourView(true); //TODO: for some reason it's not automatically read from system settings, so do it manually here + timePicker.setOnTimeChangedListener(this); + return view; + } + + return (View) timePicker.getParent(); + } + + @Override + protected void onBindView(View view) + { + super.onBindView(view); + + TimePicker tp = (TimePicker) view.findViewById(R.id.prefTimePicker); + + Integer allTime = getPersistedInt(tp.getCurrentHour() * 60 + tp.getCurrentMinute()); + + tp.setCurrentHour(allTime / 60); + tp.setCurrentMinute(allTime % 60); + } + + @Override + protected void onPrepareForRemoval() + { + // TODO Auto-generated method stub + super.onPrepareForRemoval(); + } + + @Override + protected void onRestoreInstanceState(Parcelable state) + { + // TODO Auto-generated method stub + super.onRestoreInstanceState(state); + } + + @Override + protected Parcelable onSaveInstanceState() + { + // TODO Auto-generated method stub + return super.onSaveInstanceState(); + } + + public void onTimeChanged(TimePicker view, final int hourOfDay, + final int minute) + { + setNewTime(hourOfDay, minute); + } + + private void setNewTime(final int hourOfDay, final int minute) + { + setNewTime(timeToInt(hourOfDay, minute)); + } + + private void setNewTime(final int compressedTime) + { + if (!callChangeListener(compressedTime)) { + return; + } + + this.persistInt(compressedTime); + + notifyDependencyChange(shouldDisableDependents()); + + notifyChanged(); + + } + + private int timeToInt(final int hourOfDay, final int minute) + { + return hourOfDay * 60 + minute; + } + +} diff --git a/dootil/src/doo/settings/VerboseRingtonePreference.java b/dootil/src/doo/settings/VerboseRingtonePreference.java new file mode 100644 index 0000000..9d7cab4 --- /dev/null +++ b/dootil/src/doo/settings/VerboseRingtonePreference.java @@ -0,0 +1,55 @@ +package doo.settings; + +import android.content.Context; +import android.media.Ringtone; +import android.media.RingtoneManager; +import android.net.Uri; +import android.preference.RingtonePreference; +import android.util.AttributeSet; +import android.view.View; +import android.view.ViewGroup; + +public class VerboseRingtonePreference extends RingtonePreference +{ + + public VerboseRingtonePreference(Context context, AttributeSet attrs, + int defStyle) + { + super(context, attrs, defStyle); + } + + public VerboseRingtonePreference(Context context, AttributeSet attrs) + { + super(context, attrs); + } + + public VerboseRingtonePreference(Context context) + { + super(context); + } + + @Override + protected View onCreateView(ViewGroup parent) + { + updateSummary(onRestoreRingtone()); + return super.onCreateView(parent); + } + + @Override + protected void onSaveRingtone(Uri ringtoneUri) + { + super.onSaveRingtone(ringtoneUri); + + updateSummary(ringtoneUri); + + } + + private void updateSummary(Uri ringtoneUri) + { + Ringtone ringtone = RingtoneManager.getRingtone(this.getContext(), ringtoneUri); + if (ringtone != null) + { + setSummary(ringtone.getTitle(this.getContext())); + } + } +} diff --git a/dootil/src/doo/util/Pair.java b/dootil/src/doo/util/Pair.java new file mode 100644 index 0000000..52ff99f --- /dev/null +++ b/dootil/src/doo/util/Pair.java @@ -0,0 +1,15 @@ +package doo.util; + +public class Pair +{ + public T _1; + public U _2; + + public Pair() {} + + public Pair(T _1, U _2) + { + this._1 = _1; + this._2 = _2; + } +} diff --git a/dootil/src/doo/util/Util.java b/dootil/src/doo/util/Util.java new file mode 100644 index 0000000..ab4fd0b --- /dev/null +++ b/dootil/src/doo/util/Util.java @@ -0,0 +1,120 @@ +package doo.util; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Calendar; +import java.util.Date; + + +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface.OnClickListener; +import android.text.format.DateFormat; +import android.util.Log; + +public final class Util +{ + public static void showWhateverError(Context ctx, String message, OnClickListener okClick){ + AlertDialog.Builder builder = new AlertDialog.Builder(ctx); + builder.setMessage(message).setTitle(android.R.string.dialog_alert_title).setIcon( + android.R.drawable.ic_dialog_alert).setPositiveButton(android.R.string.ok, okClick).show(); + + } + + public static Calendar parseSqliteDate(String date) { + Calendar cal = Calendar.getInstance(); + + String[] parts = date.split("-"); + if (parts.length != 3) + return cal; + + //int[] partPositions = new int[] {Calendar.YEAR, Calendar.MONTH, Calendar.DAY_OF_MONTH}; + int[] ymd = new int[3]; + + for (int x=0; x<3; x++) { + Pair parsed = Util.tryParse(parts[x]); + //cal.set(partPositions[x], parsed._2.intValue()); + ymd[x] = parsed._2.intValue(); + } + + cal.set(ymd[0], ymd[1]-1, ymd[2]); + + + return cal; + } + + public static String formatCalendar(Calendar cal, Context ctx) { + Date time = cal.getTime(); + + return DateFormat.getDateFormat(ctx).format(time); + } + + public static Pair tryParse(String value) { + Pair result = new Pair(); + try { + result._2 = Long.parseLong(value); + result._1 = true; + } catch(Exception e) { + result._1 = false; + } + + return result; + } + + public static class Reflection + { + + public static void dumpDeclareds(Object on) + { + dumpDeclareds(on.getClass()); + } + + public static void dumpDeclareds(Class onClass) + { + if (onClass == null) + return; + + Log.d("MTRK", "Methods for class: " + onClass.getSimpleName()); + for (Method m : onClass.getDeclaredMethods()) + { + Log.d("MTRK", m.getName()); + } + + dumpDeclareds(onClass.getSuperclass()); + } + + public static Object invokePrivateMethod(Class declaringClass, Object on, String methodName, + Class[] paramTypes, Object... args) + { + try + { + Method m = declaringClass.getDeclaredMethod(methodName, (Class[]) paramTypes); + m.setAccessible(true); + return m.invoke(on, args); + } catch (SecurityException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (NoSuchMethodException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + Util.Reflection.dumpDeclareds(on); + } catch (IllegalArgumentException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IllegalAccessException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (InvocationTargetException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + return null; + } + } +} diff --git a/dootil/src/doo/util/functional/Collection.java b/dootil/src/doo/util/functional/Collection.java new file mode 100644 index 0000000..97845a2 --- /dev/null +++ b/dootil/src/doo/util/functional/Collection.java @@ -0,0 +1,14 @@ +package doo.util.functional; + +import java.util.List; + +public class Collection { + public static TResult fold(List list, TResult initial, Folder folderOp) { + for (TSource val : list){ + initial = folderOp.fold(initial, val); + } + + return initial; + } + +} diff --git a/dootil/src/doo/util/functional/Folder.java b/dootil/src/doo/util/functional/Folder.java new file mode 100644 index 0000000..3eb16b2 --- /dev/null +++ b/dootil/src/doo/util/functional/Folder.java @@ -0,0 +1,5 @@ +package doo.util.functional; + +public interface Folder { + TResult fold(TResult accumulator, TSource current); +} \ No newline at end of file diff --git a/dootil/src/doo/wifi/WifiScanner.java b/dootil/src/doo/wifi/WifiScanner.java new file mode 100644 index 0000000..35127eb --- /dev/null +++ b/dootil/src/doo/wifi/WifiScanner.java @@ -0,0 +1,121 @@ +package doo.wifi; + +import java.util.List; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.ScanResult; +import android.net.wifi.WifiManager; +import android.util.Log; + +public class WifiScanner +{ + public interface OnScanResults + { + public void onResults(List results); + } + + private WifiManager wifiMan; + private OnScanResults resultReceiver; + private boolean running; + private boolean preScanState; + + public WifiScanner() + { + } + + public Boolean initiateScan(Context ctx) + { + if (wifiMan == null) + { + acquireWifiManager(ctx); + ctx.registerReceiver(receiverWifi, new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); + + Log.d("cmw", "wifistate is: " + wifiMan.getWifiState()); + preScanState = isWifiEnabled(); + if (!preScanState) //TODO: move this to separate thread, ja? + { + try + { + int cnt = 0; + while (++cnt < 5 && !(running = isWifiEnabled())) + { + wifiMan.setWifiEnabled(true); + Log.d("cmw", "wifistate is: " + wifiMan.getWifiState()); + Log.d("cmw", "waiting for wifi ... " + cnt); + Thread.sleep(400); //TODO: make sure 4*400ms is enough for slow devices. + } + } catch (InterruptedException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + + return running = wifiMan.startScan(); + } + + private void acquireWifiManager(Context ctx) { + wifiMan = (WifiManager) ctx.getSystemService(Context.WIFI_SERVICE); + } + + // wifi manager's isWifiEnabled is not trustworthy, doing its job + private boolean isWifiEnabled() { + return wifiMan.getWifiState() >= WifiManager.WIFI_STATE_ENABLED; + }; + + public void setResultReceiver(OnScanResults receiver) + { + resultReceiver = receiver; + } + + public OnScanResults getResultReceiver() + { + return resultReceiver; + } + + public void releaseScanner(Context ctx) + { + if (wifiMan != null) + { + wifiMan.setWifiEnabled(preScanState); + // ctx.unregisterReceiver(receiverWifi); + + running = false; + // keep the instance so there would no be concurrent later + // "oh i've got a message and the receiver even though unregistered is gone" + wifiMan = null; + try + { + ctx.unregisterReceiver(receiverWifi); + } catch (IllegalArgumentException e) + { + + // TODO: fook it, we don't care if it's not registered, even + // though it's a bug since we deregister it twice... + } + } + + } + + public boolean isRunning() + { + return running; + } + + private BroadcastReceiver receiverWifi = new BroadcastReceiver() + { + + @Override + public void onReceive(Context context, Intent intent) + { + if (running && resultReceiver != null) + { + resultReceiver.onResults(wifiMan.getScanResults()); + } + } + }; +}