diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/ExerciseActivity.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/ExerciseActivity.java index 5467072..7d8105d 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/ExerciseActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/ExerciseActivity.java @@ -42,7 +42,9 @@ import org.secuso.privacyfriendlypausinghealthily.dialog.ExerciseDialog; import org.secuso.privacyfriendlypausinghealthily.exercises.ExerciseLocale; import org.secuso.privacyfriendlypausinghealthily.service.TimerService; +import java.util.List; import java.util.Locale; +import java.util.Random; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; import static android.view.Gravity.CENTER_HORIZONTAL; @@ -88,6 +90,7 @@ public class ExerciseActivity extends AppCompatActivity implements android.suppo private boolean showBigTimer = false; private boolean showControlButtons = true; private boolean keepScreenOn = true; + private boolean scheduledExercise = false; // exerciseSet info private long exerciseSetId; @@ -125,16 +128,26 @@ public class ExerciseActivity extends AppCompatActivity implements android.suppo exerciseSetId = pref.getLong(FirstLaunchManager.DEFAULT_EXERCISE_SET, 0L); pauseDuration = pref.getLong(FirstLaunchManager.PAUSE_TIME, 5 * 60 * 1000); repeatStatus = pref.getBoolean(FirstLaunchManager.REPEAT_STATUS, false); + keepScreenOn = pref.getBoolean(FirstLaunchManager.KEEP_SCREEN_ON_DURING_EXERCISE, true); continuousStatus = pref.getBoolean(FirstLaunchManager.REPEAT_EXERCISES, false); try { exerciseTime = Long.parseLong(pref.getString(FirstLaunchManager.EXERCISE_DURATION, "30")) * 1000; } catch (NumberFormatException e) { exerciseTime = 30L * 1000; } - keepScreenOn = pref.getBoolean(FirstLaunchManager.KEEP_SCREEN_ON_DURING_EXERCISE, true); initResources(); + // this must be called after init resources because the database is needed + // TODO: this call should probably not be done on the UI thread + boolean randomScheduleExercise = pref.getBoolean(FirstLaunchManager.PREF_SCHEDULE_RANDOM_EXERCISE, false); + scheduledExercise = getIntent().getBooleanExtra("SCHEDULED", false); + + if(scheduledExercise && randomScheduleExercise) { + List set = dbHelper.getExerciseSets(pref.getBoolean(FirstLaunchManager.PREF_HIDE_DEFAULT_SETS, false)); + exerciseSetId = set.get((new Random()).nextInt(set.size())).getId(); // random from available sets + } + ActionBar ab = getSupportActionBar(); if (ab != null) { ab.setDisplayHomeAsUpEnabled(true); @@ -229,6 +242,7 @@ public class ExerciseActivity extends AppCompatActivity implements android.suppo if(pref.getBoolean(FirstLaunchManager.PREF_EXERCISE_CONTINUOUS, false)) { Intent timerServiceIntent = new Intent(this.getApplicationContext(), TimerService.class); timerServiceIntent.setAction(TimerService.ACTION_START_TIMER); + timerServiceIntent.putExtra("SCHEDULE", scheduledExercise); startService(timerServiceIntent); } diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/TimerActivity.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/TimerActivity.java index 88fda7d..0e9fb55 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/TimerActivity.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/TimerActivity.java @@ -1,7 +1,5 @@ package org.secuso.privacyfriendlypausinghealthily.activities; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -76,9 +74,12 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap private boolean isActivityVisible = false; // animation - private int mShortAnimationDuration; private boolean currentStatusIsPickerVisible = false; + private ExerciseSet currentExerciseSet; + private ConstraintSet constraintSetPicker; + private ConstraintSet constraintSetRunning; + // Service private TimerService mTimerService = null; @@ -96,7 +97,6 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap mTimerService = null; } }; - private ExerciseSet currentExerciseSet; private void onServiceConnected() { updateUI(); @@ -126,9 +126,28 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap setContentView(R.layout.activity_timer); initResources(); + initAnimations(); getSupportLoaderManager().initLoader(0, null, this); } + /** + * Must be called after {@link #initResources()} + */ + private void initAnimations() { + constraintSetPicker = new ConstraintSet(); + constraintSetPicker.clone(mainContent); + + constraintSetRunning = new ConstraintSet(); + constraintSetRunning.clone(mainContent); + int[] chainViews = {R.id.button_reset, R.id.button_playPause}; + float[] chainWeights = {0.5f, 0.5f}; + constraintSetRunning.createHorizontalChain(0, ConstraintSet.LEFT, 0, ConstraintSet.RIGHT, chainViews, chainWeights, ConstraintSet.CHAIN_PACKED); + constraintSetRunning.setVisibility(R.id.button_reset, View.VISIBLE); + constraintSetRunning.setVisibility(R.id.picker_layout, View.INVISIBLE); + constraintSetRunning.setVisibility(R.id.progressBar, View.VISIBLE); + constraintSetRunning.setVisibility(R.id.timerText, View.VISIBLE); + } + @Override protected int getNavigationDrawerID() { return R.id.nav_timer; @@ -188,8 +207,6 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap private void initResources() { final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); - - mShortAnimationDuration = getResources().getInteger(android.R.integer.config_shortAnimTime); exerciseSetAdapter = new ExerciseSetSpinnerAdapter(this, R.layout.layout_exercise_set, new LinkedList()); mainContent = findViewById(R.id.main_content); @@ -391,25 +408,8 @@ public class TimerActivity extends BaseActivity implements android.support.v4.ap private synchronized void showPicker(final boolean showPicker) { if(showPicker != currentStatusIsPickerVisible) { - ConstraintSet constraintSet1 = new ConstraintSet(); - constraintSet1.clone(mainContent); - constraintSet1.setHorizontalBias(R.id.button_playPause, 0.5f); - constraintSet1.setVisibility(R.id.button_reset, View.INVISIBLE); - constraintSet1.setVisibility(R.id.picker_layout, View.VISIBLE); - constraintSet1.setVisibility(R.id.progressBar, View.INVISIBLE); - constraintSet1.setVisibility(R.id.timerText, View.INVISIBLE); - - - ConstraintSet constraintSet2 = new ConstraintSet(); - constraintSet2.clone(mainContent); - constraintSet2.setHorizontalBias(R.id.button_playPause, 0.66f); - constraintSet2.setVisibility(R.id.button_reset, View.VISIBLE); - constraintSet2.setVisibility(R.id.picker_layout, View.INVISIBLE); - constraintSet2.setVisibility(R.id.progressBar, View.VISIBLE); - constraintSet2.setVisibility(R.id.timerText, View.VISIBLE); - TransitionManager.beginDelayedTransition(mainContent); - ConstraintSet constraint = showPicker ? constraintSet1 : constraintSet2; + ConstraintSet constraint = showPicker ? constraintSetPicker : constraintSetRunning; constraint.applyTo(mainContent); //pickerLayout.clearAnimation(); diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/tutorial/FirstLaunchManager.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/tutorial/FirstLaunchManager.java index 49650eb..6056aa5 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/tutorial/FirstLaunchManager.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/activities/tutorial/FirstLaunchManager.java @@ -44,6 +44,7 @@ public class FirstLaunchManager { public static final String PREF_EXERCISE_CONTINUOUS = "pref_exercise_continuous"; public static final String PREF_HIDE_DEFAULT_SETS = "pref_hide_default_exercise_sets"; public static final String WORK_TIME = "WORK_TIME"; + public static final String PREF_SCHEDULE_RANDOM_EXERCISE= "pref_schedule_random_exercise"; private final SQLiteHelper dbHandler; private Context context; @@ -85,6 +86,7 @@ public class FirstLaunchManager { .putLong(PREF_SCHEDULE_EXERCISE_TIME, 32400000L) .putBoolean(KEEP_SCREEN_ON_DURING_EXERCISE, true) .putBoolean(PREF_EXERCISE_CONTINUOUS, false) + .putBoolean(PREF_SCHEDULE_RANDOM_EXERCISE, false) .putStringSet(PREF_SCHEDULE_EXERCISE_DAYS, new HashSet(Arrays.asList("Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"))) .apply(); @@ -108,6 +110,7 @@ public class FirstLaunchManager { // channels NotificationChannel timerRunningChannel = new NotificationChannel("timer_running", "Timer Running Notification", NotificationManager.IMPORTANCE_DEFAULT); timerRunningChannel.setVibrationPattern(new long[] { 0 }); + timerRunningChannel.setSound(null, null); timerRunningChannel.setGroup(groupId); NotificationChannel timerDoneChannel = new NotificationChannel("timer_done", "Timer Done Notification", NotificationManager.IMPORTANCE_HIGH); diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/database/SQLiteHelper.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/database/SQLiteHelper.java index 945a712..550477d 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/database/SQLiteHelper.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/database/SQLiteHelper.java @@ -181,6 +181,29 @@ public class SQLiteHelper extends SQLiteAssetHelper { return result; } + public synchronized List getExerciseSets(boolean hideDefaults) { + Cursor c = getExerciseSetsCursor(); + + List result = new ArrayList<>(); + + if(c != null) { + + c.moveToFirst(); + + while(!c.isAfterLast()) { + ExerciseSet set = ExerciseSetColumns.fromCursor(c); + if(!hideDefaults || !set.isDefaultSet()) { + result.add(set); + } + c.moveToNext(); + } + + c.close(); + } + + return result; + } + private List buildExerciseList(Cursor c) { List result = new ArrayList<>(); diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/exercises/ExerciseLocale.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/exercises/ExerciseLocale.java index 24febed..bb9a1be 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/exercises/ExerciseLocale.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/exercises/ExerciseLocale.java @@ -21,7 +21,7 @@ public final class ExerciseLocale { "en", "de" ) ); - }; + } /** * @return the available language. If the default language of the device is not available. {@code "en"} will be returned. diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/NotificationCancelReceiver.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/NotificationCancelReceiver.java index e318517..6070871 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/NotificationCancelReceiver.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/NotificationCancelReceiver.java @@ -25,4 +25,4 @@ public class NotificationCancelReceiver extends BroadcastReceiver { manager.cancel(TimerService.NOTIFICATION_ID); } } -}; +} diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/TimerSchedulerReceiver.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/TimerSchedulerReceiver.java index 85d1c15..bcda4ac 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/TimerSchedulerReceiver.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/receivers/TimerSchedulerReceiver.java @@ -60,7 +60,7 @@ public class TimerSchedulerReceiver extends WakefulBroadcastReceiver { } private void startTimer() { - mTimerService.startTimer(mPref.getLong(WORK_TIME, 1000L * 60L * 60L)); + mTimerService.startTimer(mPref.getLong(WORK_TIME, 1000L * 60L * 60L), true); } public static void scheduleNextAlarm(@NonNull Context context) { diff --git a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/service/TimerService.java b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/service/TimerService.java index c469dea..bccd388 100644 --- a/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/service/TimerService.java +++ b/app/src/main/java/org/secuso/privacyfriendlypausinghealthily/service/TimerService.java @@ -92,6 +92,7 @@ public class TimerService extends Service { }; private BroadcastReceiver notificationDeletedReceiver = new NotificationDeletedReceiver(); private BroadcastReceiver notificationPreferenceChangedReceiver = new NotificationCancelReceiver(); + private boolean scheduled = false; private void onTimerDone() { @@ -101,7 +102,10 @@ public class TimerService extends Service { Intent snoozeIntent = new Intent(this, TimerService.class); snoozeIntent.setAction(ACTION_SNOOZE_TIMER); - PendingIntent startExercises = PendingIntent.getActivity(this, 0, new Intent(this, ExerciseActivity.class), FLAG_CANCEL_CURRENT); + Intent exerciseIntent = new Intent(this, ExerciseActivity.class); + exerciseIntent.putExtra("SCHEDULED", scheduled); + + PendingIntent startExercises = PendingIntent.getActivity(this, 0, exerciseIntent, FLAG_CANCEL_CURRENT); PendingIntent snoozeExercise = PendingIntent.getService(this, 0, snoozeIntent, FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "timer_done"); @@ -149,7 +153,17 @@ public class TimerService extends Service { unregisterReceiver(notificationPreferenceChangedReceiver); } - public synchronized void startTimer(final long duration) { + public void startTimer(final long duration, boolean scheduled) { + this.scheduled = scheduled; + startTimerInternal(duration); + } + + public void startTimer(final long duration) { + this.scheduled = false; + startTimerInternal(duration); + } + + private synchronized void startTimerInternal(final long duration) { if(!isRunning) { initialDuration = duration; @@ -262,7 +276,7 @@ public class TimerService extends Service { final String action = intent.getAction(); - if (ACTION_START_TIMER.equals(action)) handleRestartTimer(); + if (ACTION_START_TIMER.equals(action)) handleRestartTimer(intent); else if (ACTION_PAUSE_TIMER.equals(action)) pauseTimer(); else if (ACTION_RESUME_TIMER.equals(action)) resumeTimer(); else if (ACTION_STOP_TIMER.equals(action)) stopAndResetTimer(); @@ -282,12 +296,19 @@ public class TimerService extends Service { startTimer(snoozeTime); } + private void handleRestartTimer(Intent intent) { + if(intent != null) { + scheduled = intent.getBooleanExtra("SCHEDULE", false); + } + handleRestartTimer(); + } + private void handleRestartTimer() { SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this); if(pref.getBoolean(PREF_EXERCISE_CONTINUOUS, false)) { long duration = pref.getLong(WORK_TIME, 1000 * 60 * 60); - startTimer(duration); + startTimerInternal(duration); } } @@ -304,11 +325,15 @@ public class TimerService extends Service { String time = String.format(Locale.US, "%02d:%02d:%02d", hours, minutes, seconds); - PendingIntent startExercises = PendingIntent.getActivity(this, 0, new Intent(this, ExerciseActivity.class), FLAG_CANCEL_CURRENT); + Intent exerciseIntent = new Intent(this, ExerciseActivity.class); + exerciseIntent.putExtra("SCHEDULED", scheduled); + PendingIntent startExercises = PendingIntent.getActivity(this, 0, exerciseIntent, FLAG_CANCEL_CURRENT); builder.setContentText(time); builder.setColor(ContextCompat.getColor(this, R.color.colorAccent)); builder.setPriority(NotificationCompat.PRIORITY_DEFAULT); + builder.setOnlyAlertOnce(true); + builder.setSound(null); builder.setWhen(0); builder.setProgress((int) initialDuration, (int) (initialDuration - remainingDuration), false); builder.setSmallIcon(R.mipmap.ic_notification); diff --git a/app/src/main/res/layout/activity_timer.xml b/app/src/main/res/layout/activity_timer.xml index 8299b21..1bbaf7e 100644 --- a/app/src/main/res/layout/activity_timer.xml +++ b/app/src/main/res/layout/activity_timer.xml @@ -291,9 +291,7 @@ android:tint="@color/darkblue" android:visibility="invisible" app:layout_constraintBottom_toBottomOf="parent" - app:layout_constraintHorizontal_bias="0.33" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintHorizontal_bias="0.5" app:srcCompat="@drawable/ic_replay_black_48dp" /> diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 424ee05..e1586b0 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -163,5 +163,6 @@ Die ausgewählte Übungszeit ist zu kurz, um das gewählte Übungsset abzuschließen. Die Übungszeit wird automatisch angepasst. Möchten Sie den Timer starten? Achtung Die gewählte Übungszeit ist nicht ausreichend, um das gewählte Übungsset abzuschließen. Die Zeit wurde automatisch angepasst. + Verwende zufällige Übungssets \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b8e7be2..05bd7fe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -156,6 +156,7 @@ The chosen exercise time is too short to finish the selected exercise set. The time will automatically be adjusted. Are you sure you want to start the timer? Warning The currently selected exercise time is not sufficient to complete the chosen exercise set. The time has been adjusted. + Use random exercise sets diff --git a/app/src/main/res/xml/pref_scheduler.xml b/app/src/main/res/xml/pref_scheduler.xml index 9c446ce..9cf4d7a 100644 --- a/app/src/main/res/xml/pref_scheduler.xml +++ b/app/src/main/res/xml/pref_scheduler.xml @@ -35,6 +35,12 @@ android:title="@string/pref_schedule_exercise_days" android:key="pref_schedule_exercise_days"/> + + \ No newline at end of file