arrayAdapter3;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- arrayAdapter3 = ArrayAdapter.createFromResource(this, R.array.themeOptions_all,
- android.R.layout.simple_spinner_item);
+ arrayAdapter3 = ArrayAdapter.createFromResource(this, R.array.themeOptions_all, android.R.layout.simple_spinner_item);
} else {
- arrayAdapter3 = ArrayAdapter.createFromResource(this, R.array.themeOptions_noSystem,
- android.R.layout.simple_spinner_item);
+ arrayAdapter3 = ArrayAdapter.createFromResource(this, R.array.themeOptions_noSystem, android.R.layout.simple_spinner_item);
}
arrayAdapter3.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
themeSpinner.setAdapter(arrayAdapter3);
- themeSpinner.setSelection(sharedPreferences
- .getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, ConstantsAndStatics.THEME_SYSTEM));
- themeSpinner.setSelection(sharedPreferences
- .getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, defaultTheme));
+ themeSpinner.setSelection(sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, ConstantsAndStatics.THEME_SYSTEM));
+ themeSpinner.setSelection(sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, defaultTheme));
themeSpinner.setOnItemSelectedListener(this);
///////////////////////////////////////////////////////////
// Initialise expandable layout for snooze options:
//////////////////////////////////////////////////////////
- snoozeOptionsExpandableLayout = findViewById(R.id.expandable_layout);
+ snoozeOptionsExpandableLayout = findViewById(R.id.snoozeOptionsExpandableLayout);
if (savedInstanceState == null) {
snoozeOptionsExpandableLayout.setExpanded(false);
} else {
- snoozeOptionsExpandableLayout.setExpanded(savedInstanceState.getBoolean(SAVE_INSTANCE_KEY_LAYOUT_EXPANDED));
+ snoozeOptionsExpandableLayout.setExpanded(savedInstanceState.getBoolean(SAVE_INSTANCE_SNOOZE_LAYOUT_EXPANDED));
}
- snoozeOptionsExpandableLayout.setOnExpansionUpdateListener(this);
+ snoozeOptionsExpandableLayout.setOnExpansionUpdateListener((expansionFraction, state) -> setSnoozeImageView(state));
ConstraintLayout snoozeOptionsConstraintLayout = findViewById(R.id.settings_snoozeOptionsConstraintLayout);
snoozeOptionsConstraintLayout.setOnClickListener(this);
@@ -149,8 +164,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
// Initialise snooze ON/OFF switch:
/////////////////////////////////////////////
snoozeStateSwitch = findViewById(R.id.settingsSnoozeOnOffSwitch);
- snoozeStateSwitch.setChecked(
- sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_IS_ON, true));
+ snoozeStateSwitch.setChecked(sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_IS_ON, true));
setSwitchText();
snoozeStateSwitch.setOnCheckedChangeListener(this);
@@ -159,20 +173,13 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
snoozeIntvEditText = findViewById(R.id.settings_snoozeIntervalEditText);
snoozeFreqEditText = findViewById(R.id.settings_snoozeFreqEditText2);
- snoozeIntvEditText.setText(String.valueOf(
- sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_INTERVAL, 5)));
- snoozeFreqEditText.setText(String.valueOf(
- sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_FREQ, 3)));
+ snoozeIntvEditText.setText(String.valueOf(sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_INTERVAL, 5)));
+ snoozeFreqEditText.setText(String.valueOf(sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_FREQ, 3)));
- activateOrDeactivateSnoozeOptions(
- sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_IS_ON, true));
+ activateOrDeactivateSnoozeOptions(sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_SNOOZE_IS_ON, true));
snoozeImageView = findViewById(R.id.snoozeExpColapImage);
- if (snoozeOptionsExpandableLayout.isExpanded()) {
- snoozeImageView.setImageResource(R.drawable.ic_collapse);
- } else {
- snoozeImageView.setImageResource(R.drawable.ic_expand);
- }
+ setSnoozeImageView(snoozeOptionsExpandableLayout.getState());
snoozeFreqEditText.addTextChangedListener(new TextWatcher() {
@Override
@@ -246,10 +253,72 @@ public void afterTextChanged(Editable editable) {
// Auto select tone enable/disable:
//////////////////////////////////////////
autoSelectToneCheckBox = findViewById(R.id.autoToneSelectionCheckBox);
- autoSelectToneCheckBox.setChecked(
- sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_AUTO_SET_TONE, true));
+ autoSelectToneCheckBox.setChecked(sharedPreferences.getBoolean(ConstantsAndStatics.SHARED_PREF_KEY_AUTO_SET_TONE, true));
autoSelectToneCheckBox.setOnCheckedChangeListener(this);
+ ////////////////////////////////////////////////////////
+ // Initialise shakeSencitivityExpandableLayout:
+ ///////////////////////////////////////////////////////
+ shakeSensitivityExpandableLayout = findViewById(R.id.shakeSensitivityExpandableLayout);
+ if (savedInstanceState == null) {
+ shakeSensitivityExpandableLayout.setExpanded(false, false);
+ } else {
+ shakeSensitivityExpandableLayout.setExpanded(savedInstanceState.getBoolean(SAVE_INSTANCE_SHAKE_LAYOUT_EXPANDED));
+ }
+ shakeSensitivityExpandableLayout.setOnExpansionUpdateListener((expansionFraction, state) -> setShakeImageView(state));
+
+ ////////////////////////////////////////////////////////
+ // Initialise shakeSensitivityConstarintLayout:
+ ///////////////////////////////////////////////////////
+ ConstraintLayout shakeOptionsConstraintLayout = findViewById(R.id.shakeSensitivityConstarintLayout);
+ shakeOptionsConstraintLayout.setOnClickListener(this);
+
+ ////////////////////////////////////////////////////////
+ // Initialise shakeImageView:
+ ///////////////////////////////////////////////////////
+ shakeImageView = findViewById(R.id.shakeExpColImage);
+ setShakeImageView(shakeSensitivityExpandableLayout.getState());
+
+ ////////////////////////////////////////////////////////
+ // Initialise sensitivitySeekBar:
+ ///////////////////////////////////////////////////////
+ SeekBar shakeSensitivitySeekBar = findViewById(R.id.shakeSensitivitySeekBar);
+
+ double min = 1.5, max = 6.5, stepSize = 0.2;
+ int steps = (int) ((max - min) / stepSize);
+
+ shakeSensitivitySeekBar.setMax(steps);
+ shakeSensitivitySeekBar.setProgress(getStepValue(sharedPreferences.getFloat(ConstantsAndStatics.SHARED_PREF_KEY_SHAKE_SENSITIVITY,
+ ConstantsAndStatics.DEFAULT_SHAKE_SENSITIVITY)));
+ shakeSensitivitySeekBar.setOnSeekBarChangeListener(this);
+
+ TextView testShakeTextView = findViewById(R.id.testShakeSenstivityTextView);
+ testShakeTextView.setOnClickListener(this);
+
+ sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
+ acclerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+
+ if (savedInstanceState == null) {
+ isShakeTestGoingOn = false;
+ } else {
+ isShakeTestGoingOn = savedInstanceState.getBoolean(SAVE_INSTANCE_IS_SHAKE_ONGOING);
+ lastShakeTime = System.currentTimeMillis();
+ }
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ if (isShakeTestGoingOn) {
+ sensorManager.registerListener(this, acclerometer, SensorManager.SENSOR_DELAY_UI, new Handler());
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ sensorManager.unregisterListener(this, acclerometer);
}
//-----------------------------------------------------------------------------------------------------
@@ -257,7 +326,9 @@ public void afterTextChanged(Editable editable) {
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putBoolean(SAVE_INSTANCE_KEY_LAYOUT_EXPANDED, snoozeOptionsExpandableLayout.isExpanded());
+ outState.putBoolean(SAVE_INSTANCE_SNOOZE_LAYOUT_EXPANDED, snoozeOptionsExpandableLayout.isExpanded());
+ outState.putBoolean(SAVE_INSTANCE_SHAKE_LAYOUT_EXPANDED, shakeSensitivityExpandableLayout.isExpanded());
+ outState.putBoolean(SAVE_INSTANCE_IS_SHAKE_ONGOING, isShakeTestGoingOn);
}
@@ -287,10 +358,9 @@ private void setToneTextView(@NonNull Uri uri) {
if (uri.equals(Settings.System.DEFAULT_ALARM_ALERT_URI)) {
toneTextView.setText(R.string.defaultAlarmToneText);
-
} else {
- String fileNameWithExt = null;
+ String fileName = null;
try (Cursor cursor = getContentResolver().query(uri, null, null, null, null)) {
@@ -299,17 +369,17 @@ private void setToneTextView(@NonNull Uri uri) {
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (index != - 1) {
- fileNameWithExt = cursor.getString(index);
+ fileName = cursor.getString(index);
} else {
- fileNameWithExt = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
+ fileName = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
}
}
} catch (Exception ignored) {
}
}
- if (fileNameWithExt != null) {
- toneTextView.setText(fileNameWithExt);
+ if (fileName != null) {
+ toneTextView.setText(fileName);
} else {
toneTextView.setText(uri.getLastPathSegment());
}
@@ -362,6 +432,26 @@ private void setVolumeImageView(int volume) {
}
}
+ //----------------------------------------------------------------------------------------------------
+
+ private void setShakeImageView(int state) {
+ if (state == ExpandableLayout.State.EXPANDED) {
+ shakeImageView.setImageResource(R.drawable.ic_collapse);
+ } else if (state == ExpandableLayout.State.COLLAPSED) {
+ shakeImageView.setImageResource(R.drawable.ic_expand);
+ }
+ }
+
+ //----------------------------------------------------------------------------------------------------
+
+ private void setSnoozeImageView(int state) {
+ if (state == ExpandableLayout.State.EXPANDED) {
+ snoozeImageView.setImageResource(R.drawable.ic_collapse);
+ } else if (state == ExpandableLayout.State.COLLAPSED) {
+ snoozeImageView.setImageResource(R.drawable.ic_expand);
+ }
+ }
+
//-----------------------------------------------------------------------------------------------------
@Override
@@ -420,19 +510,7 @@ public void onNothingSelected(AdapterView> adapterView) {
* Applies the appropriate theme. Gets the theme using {@link ConstantsAndStatics#getTheme(int)}.
*/
private void applyTheme() {
- AppCompatDelegate.setDefaultNightMode(ConstantsAndStatics.getTheme(
- sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, defaultTheme)));
- }
-
- //-----------------------------------------------------------------------------------------------------
-
- @Override
- public void onExpansionUpdate(float expansionFraction, int state) {
- if (state == ExpandableLayout.State.EXPANDED) {
- snoozeImageView.setImageResource(R.drawable.ic_collapse);
- } else if (state == ExpandableLayout.State.COLLAPSED) {
- snoozeImageView.setImageResource(R.drawable.ic_expand);
- }
+ AppCompatDelegate.setDefaultNightMode(ConstantsAndStatics.getTheme(sharedPreferences.getInt(ConstantsAndStatics.SHARED_PREF_KEY_THEME, defaultTheme)));
}
//-----------------------------------------------------------------------------------------------------
@@ -504,6 +582,15 @@ public void onClick(View view) {
.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true)
.putExtra(ConstantsAndStatics.EXTRA_PLAY_RINGTONE, false);
startActivityForResult(intent, RINGTONE_REQUEST_CODE);
+ } else if (view.getId() == R.id.shakeSensitivityConstarintLayout) {
+ shakeSensitivityExpandableLayout.toggle();
+ } else if (view.getId() == R.id.testShakeSenstivityTextView) {
+ sensorManager.registerListener(this, acclerometer, SensorManager.SENSOR_DELAY_UI, new Handler());
+ lastShakeTime = System.currentTimeMillis();
+ DialogFragment dialogFragment = new AlertDialog_TestShakeSensitivity();
+ dialogFragment.setCancelable(false);
+ dialogFragment.show(getSupportFragmentManager(), "");
+ isShakeTestGoingOn = true;
}
}
@@ -546,9 +633,99 @@ public void onStartTrackingTouch(SeekBar seekBar) {
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
- prefEditor.remove(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_ALARM_VOLUME)
- .putInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_ALARM_VOLUME, seekBar.getProgress())
- .commit();
+ if (seekBar.getId() == R.id.settings_volumeSeekbar) {
+ prefEditor.remove(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_ALARM_VOLUME)
+ .putInt(ConstantsAndStatics.SHARED_PREF_KEY_DEFAULT_ALARM_VOLUME, seekBar.getProgress())
+ .commit();
+ } else if (seekBar.getId() == R.id.shakeSensitivitySeekBar) {
+ Log.e(getClass().getSimpleName(), "Sensitivity value = " + getSensitivityValue(seekBar.getProgress()));
+ prefEditor.remove(ConstantsAndStatics.SHARED_PREF_KEY_SHAKE_SENSITIVITY)
+ .putFloat(ConstantsAndStatics.SHARED_PREF_KEY_SHAKE_SENSITIVITY, getSensitivityValue(seekBar.getProgress()))
+ .commit();
+ }
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ /**
+ * Calculates the steps of seekbar from sensitivity value.
+ *
+ * @param sensitivity The value of sensitivity, i.e. the minimum gForce required to trigger the detector.
+ *
+ * @return The corresponding progress value that can be set in the seekbar.
+ */
+ private int getStepValue(float sensitivity) {
+ return (int) ((sensitivity - 1.5f) / .2f);
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ /**
+ * Given a progress value from the seekbar, this function calculates the sensitivity of shake detector.
+ *
+ * @param step The value returned by {@link SeekBar#getProgress()}}.
+ *
+ * @return The sensitivity corresponding to the step.
+ */
+ private float getSensitivityValue(int step) {
+ BigDecimal bigDecimal = new BigDecimal(1.5f + step * .2f).setScale(1, RoundingMode.FLOOR);
+ return bigDecimal.floatValue();
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ @Override
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+ float x = event.values[0];
+ float y = event.values[1];
+ float z = event.values[2];
+
+ float gX = x / SensorManager.GRAVITY_EARTH;
+ float gY = y / SensorManager.GRAVITY_EARTH;
+ float gZ = z / SensorManager.GRAVITY_EARTH;
+
+ float gForce = (float) Math.sqrt(gX * gX + gY * gY + gZ * gZ);
+ // gForce will be close to 1 when there is no movement.
+
+ if (gForce >= sharedPreferences.getFloat(ConstantsAndStatics.SHARED_PREF_KEY_SHAKE_SENSITIVITY, ConstantsAndStatics.DEFAULT_SHAKE_SENSITIVITY)) {
+ long currTime = System.currentTimeMillis();
+ if (Math.abs(currTime - lastShakeTime) > MINIMUM_MILLIS_BETWEEN_SHAKES) {
+ lastShakeTime = currTime;
+ shakeVibration();
+ }
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ /**
+ * Creates a vibration for a small period of time, indicating that the app has registered a shake event.
+ */
+ private void shakeVibration() {
+ Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
+ if (vibrator.hasVibrator()) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ vibrator.vibrate(VibrationEffect.createOneShot(200, VibrationEffect.DEFAULT_AMPLITUDE));
+ } else {
+ vibrator.vibrate(200);
+ }
+ }
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ @Override
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ }
+
+ //-----------------------------------------------------------------------------------------------------
+
+ @Override
+ public void onDialogNegativeClick(DialogFragment dialogFragment) {
+ sensorManager.unregisterListener(this, acclerometer);
+ isShakeTestGoingOn = false;
}
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_DiscardChanges.java b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_DiscardChanges.java
index ea1b6f0..4660840 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_DiscardChanges.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_DiscardChanges.java
@@ -23,8 +23,7 @@ public void onAttach(@NonNull Context context) {
if (context instanceof DialogListener) {
listener = (DialogListener) context;
} else {
- throw new ClassCastException(context.getClass() + " must implement AlertDialog_DiscardChanges" +
- ".DialogListener");
+ throw new ClassCastException(context.getClass() + " must implement AlertDialog_DiscardChanges.DialogListener");
}
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_PermissionReason.java b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_PermissionReason.java
index a747560..5095a0f 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_PermissionReason.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_PermissionReason.java
@@ -13,7 +13,7 @@ public class AlertDialog_PermissionReason extends DialogFragment {
private DialogListener listener;
- private String message;
+ private final String message;
public AlertDialog_PermissionReason(String message) {
this.message = message;
@@ -31,8 +31,7 @@ public void onAttach(@NonNull Context context) {
if (context instanceof DialogListener) {
listener = (DialogListener) context;
} else {
- throw new ClassCastException(context.getClass() + " must implement AlertDialog_PermissionReason" +
- ".DialogListener");
+ throw new ClassCastException(context.getClass() + " must implement AlertDialog_PermissionReason.DialogListener");
}
}
@@ -43,8 +42,7 @@ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
builder.setMessage(message)
.setPositiveButton(getResources().getString(R.string.cancelDialog_positive),
- (dialogInterface, i) -> listener
- .onDialogPositiveClick(AlertDialog_PermissionReason.this))
+ (dialogInterface, i) -> listener.onDialogPositiveClick(AlertDialog_PermissionReason.this))
.setNegativeButton(getResources().getString(R.string.cancelDialog_negative),
(dialogInterface, i) -> {
listener.onDialogNegativeClick(AlertDialog_PermissionReason.this);
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_TestShakeSensitivity.java b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_TestShakeSensitivity.java
new file mode 100644
index 0000000..08e101f
--- /dev/null
+++ b/app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_TestShakeSensitivity.java
@@ -0,0 +1,54 @@
+package in.basulabs.shakealarmclock;
+
+import android.app.Dialog;
+import android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AlertDialog;
+import androidx.fragment.app.DialogFragment;
+
+public class AlertDialog_TestShakeSensitivity extends DialogFragment {
+
+ private AlertDialog_TestShakeSensitivity.DialogListener listener;
+
+ public interface DialogListener {
+
+ void onDialogNegativeClick(DialogFragment dialogFragment);
+
+ }
+
+ @Override
+ public void onAttach(@NonNull Context context) {
+ super.onAttach(context);
+ if (context instanceof AlertDialog_TestShakeSensitivity.DialogListener) {
+ listener = (AlertDialog_TestShakeSensitivity.DialogListener) context;
+ } else {
+ throw new ClassCastException(context.getClass() + " must implement AlertDialog_TestShakeSensitivity.DialogListener");
+ }
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity());
+ builder.setTitle(R.string.title_shakeDetectionTest)
+ .setMessage(getResources().getString(R.string.message_shakeDetectionTest))
+ .setNegativeButton(getResources().getString(R.string.negative_shakeDetectionTest), (dialogInterface, i) -> {
+ listener.onDialogNegativeClick(AlertDialog_TestShakeSensitivity.this);
+ dismiss();
+ })
+ .setCancelable(false);
+
+ return builder.create();
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ listener = null;
+ }
+
+}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java b/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
index a29b13a..dede3e8 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
@@ -2,7 +2,6 @@
import android.content.Context;
import android.content.Intent;
-import android.os.Process;
import android.util.Log;
import androidx.annotation.Nullable;
@@ -27,8 +26,8 @@
final class ConstantsAndStatics {
/**
- * Bundle key for the Bundle that is passed with intent from {@link Activity_AlarmDetails} to {@link
- * Activity_AlarmsList} containing the data set by the user.
+ * Bundle key for the Bundle that is passed with intent from {@link Activity_AlarmDetails} to {@link Activity_AlarmsList} containing the data set by the
+ * user.
*/
static final String BUNDLE_KEY_ALARM_DETAILS = "in.basulabs.shakealarmclock.BundleWithAlarmDetails";
@@ -43,8 +42,8 @@ final class ConstantsAndStatics {
static final String BUNDLE_KEY_ALARM_MINUTE = "in.basulabs.shakealarmclock.MinsPickedByUser";
/**
- * Bundle key for the alarm type. The value is one of {@link #ALARM_TYPE_SOUND_ONLY}, {@link
- * #ALARM_TYPE_VIBRATE_ONLY} or {@link #ALARM_TYPE_SOUND_AND_VIBRATE}.
+ * Bundle key for the alarm type. The value is one of {@link #ALARM_TYPE_SOUND_ONLY}, {@link #ALARM_TYPE_VIBRATE_ONLY} or {@link
+ * #ALARM_TYPE_SOUND_AND_VIBRATE}.
*/
static final String BUNDLE_KEY_ALARM_TYPE = "in.basulabs.shakealarmclock.AlarmType";
@@ -129,14 +128,12 @@ final class ConstantsAndStatics {
static final String BUNDLE_KEY_HAS_USER_CHOSEN_DATE = "in.basulabs.shakealarmclock.HAS_USER_CHOSEN_DATE";
/**
- * Intent action delivered to {@link android.content.BroadcastReceiver} in {@link Service_RingAlarm} instructing it
- * to snooze the alarm.
+ * Intent action delivered to {@link android.content.BroadcastReceiver} in {@link Service_RingAlarm} instructing it to snooze the alarm.
*/
static final String ACTION_SNOOZE_ALARM = "in.basulabs.shakealarmclock.Service_RingAlarm -- SNOOZE_ALARM";
/**
- * Intent action delivered to {@link android.content.BroadcastReceiver} in {@link Service_RingAlarm} instructing it
- * to cancel the alarm.
+ * Intent action delivered to {@link android.content.BroadcastReceiver} in {@link Service_RingAlarm} instructing it to cancel the alarm.
*/
static final String ACTION_CANCEL_ALARM = "in.basulabs.shakealarmclock.Service_RingAlarm -- CANCEL_ALARM";
@@ -155,23 +152,19 @@ final class ConstantsAndStatics {
*/
static final String ACTION_EXISTING_ALARM = "in.basulabs.shakealarmclock.ACTION_EXISTING_ALARM";
- static final String ACTION_NEW_ALARM_FROM_INTENT =
- "in.basulabs.shakealarmclock.ACTION_NEW_ALARM_FROM_INTENT";
-
- static final String ACTION_STOP_IMMEDIATELY = "in.basulabs.shakealarmclock.STOP_IMMEDIATELY";
+ static final String ACTION_NEW_ALARM_FROM_INTENT = "in.basulabs.shakealarmclock.ACTION_NEW_ALARM_FROM_INTENT";
/**
- * Indicates whether {@link Activity_RingtonePicker} should play the ringtone when the user clicks on a {@link
- * android.widget.RadioButton}. Default: {@code true}.
+ * Indicates whether {@link Activity_RingtonePicker} should play the ringtone when the user clicks on a {@link android.widget.RadioButton}. Default: {@code
+ * true}.
*/
static final String EXTRA_PLAY_RINGTONE = "in.basulabs.shakealarmclock.EXTRA_PLAY_RINGTONE";
/**
* Bundle key for the old alarm hour.
* This is passed from {@link Activity_AlarmDetails} to
- * {@link Activity_AlarmsList} if the user saves the edits made to an existing alarm. Using this and {@link
- * #BUNDLE_KEY_OLD_ALARM_MINUTE}, {@link Activity_AlarmsList} deletes the old alarm and adds/activates the new
- * alarm.
+ * {@link Activity_AlarmsList} if the user saves the edits made to an existing alarm. Using this and {@link #BUNDLE_KEY_OLD_ALARM_MINUTE}, {@link
+ * Activity_AlarmsList} deletes the old alarm and adds/activates the new alarm.
*
*
* @see #BUNDLE_KEY_OLD_ALARM_MINUTE
@@ -181,8 +174,8 @@ final class ConstantsAndStatics {
/**
* Bundle key for the old alarm minute.
* This is passed from {@link Activity_AlarmDetails} to
- * {@link Activity_AlarmsList} if the user saves the edits made to an existing alarm. Using this and {@link
- * #BUNDLE_KEY_OLD_ALARM_HOUR}, {@link Activity_AlarmsList} deletes the old alarm and adds/activates the new alarm.
+ * {@link Activity_AlarmsList} if the user saves the edits made to an existing alarm. Using this and {@link #BUNDLE_KEY_OLD_ALARM_HOUR}, {@link
+ * Activity_AlarmsList} deletes the old alarm and adds/activates the new alarm.
*
*
* @see #BUNDLE_KEY_OLD_ALARM_HOUR
@@ -200,31 +193,24 @@ final class ConstantsAndStatics {
static final String ACTION_DESTROY_RING_ALARM_ACTIVITY = "in.basulabs.shakealarmclock.DESTROY_RING_ALARM_ACTIVITY";
/**
- * {@link android.content.SharedPreferences} Key indicating whether the app was recently active. The value is {@code
- * boolean}.
- */
- static final String SHARED_PREF_KEY_WAS_APP_RECENTLY_ACTIVE =
- "in.basulabs.shakealarmclock.SHARED_PREF_KEY_WAS_APP_RECENTLY_ACTIVE";
-
- /**
- * {@link android.content.SharedPreferences} key indicating whether the read storage permission was asked before.
- * This is used to determine if the user had chosen "Don't ask again" before denying the permission. The value is
- * {@code boolean}.
+ * {@link android.content.SharedPreferences} key indicating whether the read storage permission was asked before. This is used to determine if the user had
+ * chosen "Don't ask again" before denying the permission. The value is {@code boolean}.
*/
static final String SHARED_PREF_KEY_PERMISSION_WAS_ASKED_BEFORE = "in.basulabs.shakealarmclock.PERMISSION_WAS_ASKED_BEFORE";
/**
- * {@link android.content.SharedPreferences} key to store the default shake operation. Can be either {@link
- * #DISMISS} or {@link #SNOOZE}.
+ * {@link android.content.SharedPreferences} key to store the default shake operation. Can be either {@link #DISMISS} or {@link #SNOOZE}.
*/
static final String SHARED_PREF_KEY_DEFAULT_SHAKE_OPERATION = "in.basulabs.shakealarmclock.DEFAULT_SHAKE_OPERATION";
/**
- * {@link android.content.SharedPreferences} key to store the default power button operation. Can be either {@link
- * #DISMISS} or {@link #SNOOZE}.
+ * {@link android.content.SharedPreferences} key to store the default power button operation. Can be either {@link #DISMISS} or {@link #SNOOZE}.
*/
- static final String SHARED_PREF_KEY_DEFAULT_POWER_BTN_OPERATION =
- "in.basulabs.shakealarmclock.DEFAULT_POWER_BTN_OPERATION";
+ static final String SHARED_PREF_KEY_DEFAULT_POWER_BTN_OPERATION = "in.basulabs.shakealarmclock.DEFAULT_POWER_BTN_OPERATION";
+
+ static final String SHARED_PREF_KEY_SHAKE_SENSITIVITY = "in.basulabs.shakealarmclock.SHAKE_SENSITIVITY";
+
+ static final float DEFAULT_SHAKE_SENSITIVITY = 3.2f;
/**
* Indicates that the ringing alarm should be snoozed.
@@ -249,15 +235,14 @@ final class ConstantsAndStatics {
static final String SHARED_PREF_KEY_DEFAULT_SNOOZE_INTERVAL = "in.basulabs.shakealarmclock.DEFAULT_SNOOZE_INTERVAL";
/**
- * {@link android.content.SharedPreferences} key to store the default snooze frequency, i.e. the number of times the
- * alarm will ring before being cancelled automatically.
+ * {@link android.content.SharedPreferences} key to store the default snooze frequency, i.e. the number of times the alarm will ring before being cancelled
+ * automatically.
*/
static final String SHARED_PREF_KEY_DEFAULT_SNOOZE_FREQ = "in.basulabs.shakealarmclock.DEFAULT_SNOOZE_FREQUENCY";
/**
- * {@link android.content.SharedPreferences} key to store the default alarm tone Uri. If the file is unavailable, it
- * will be replaced by the default alarm tone during runtime. The value is {@code String}; should be converted to
- * Uri using {@link android.net.Uri#parse(String)}.
+ * {@link android.content.SharedPreferences} key to store the default alarm tone Uri. If the file is unavailable, it will be replaced by the default alarm
+ * tone during runtime. The value is {@code String}; should be converted to Uri using {@link android.net.Uri#parse(String)}.
*/
static final String SHARED_PREF_KEY_DEFAULT_ALARM_TONE_URI = "in.basulabs.shakealarmclock.DEFAULT_ALARM_TONE_URI";
@@ -267,8 +252,7 @@ final class ConstantsAndStatics {
static final String SHARED_PREF_KEY_DEFAULT_ALARM_VOLUME = "in.basulabs.shakealarmclock.DEFAULT_ALARM_VOLUME";
/**
- * The app will set its theme according to time. From 10:00 PM to 6:00 AM, the theme will be dark, and light
- * otherwise.
+ * The app will set its theme according to time. From 10:00 PM to 6:00 AM, the theme will be dark, and light otherwise.
*/
static final int THEME_AUTO_TIME = 0;
@@ -283,14 +267,14 @@ final class ConstantsAndStatics {
static final int THEME_DARK = 2;
/**
- * Indicates that the theme of the app should be light. Corresponds to {@link androidx.appcompat.app.AppCompatDelegate#MODE_NIGHT_FOLLOW_SYSTEM}.
- * Available only on Android Q+.
+ * Indicates that the theme of the app should be light. Corresponds to {@link androidx.appcompat.app.AppCompatDelegate#MODE_NIGHT_FOLLOW_SYSTEM}. Available
+ * only on Android Q+.
*/
static final int THEME_SYSTEM = 3;
/**
- * {@link android.content.SharedPreferences} key to store the current theme. Can only have the values {@link
- * #THEME_AUTO_TIME}, {@link #THEME_LIGHT}, {@link #THEME_DARK} or {@link #THEME_SYSTEM}.
+ * {@link android.content.SharedPreferences} key to store the current theme. Can only have the values {@link #THEME_AUTO_TIME}, {@link #THEME_LIGHT}, {@link
+ * #THEME_DARK} or {@link #THEME_SYSTEM}.
*/
static final String SHARED_PREF_KEY_THEME = "in.basulabs.shakealarmclock.THEME";
@@ -304,8 +288,8 @@ final class ConstantsAndStatics {
//---------------------------------------------------------------------------------------------------------
/**
- * Creates a {@link PeriodicWorkRequest} and enqueues a unique work using {@link
- * WorkManager#enqueueUniquePeriodicWork(String, ExistingPeriodicWorkPolicy, PeriodicWorkRequest)}.
+ * Creates a {@link PeriodicWorkRequest} and enqueues a unique work using {@link WorkManager#enqueueUniquePeriodicWork(String, ExistingPeriodicWorkPolicy,
+ * PeriodicWorkRequest)}.
*
* @param context The {@link Context} that is scheduling the work.
*/
@@ -313,13 +297,12 @@ static void schedulePeriodicWork(Context context) {
try {
WorkManager.initialize(context, new Configuration.Builder().setMinimumLoggingLevel(Log.DEBUG).build());
- } catch (Exception ignored) {}
+ } catch (Exception ignored) {
+ }
- PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(Worker_ActivateAlarms.class,
- 15, TimeUnit.MINUTES).build();
+ PeriodicWorkRequest periodicWorkRequest = new PeriodicWorkRequest.Builder(Worker_ActivateAlarms.class, 15, TimeUnit.MINUTES).build();
- WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME_ACTIVATE_ALARMS,
- ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
+ WorkManager.getInstance(context).enqueueUniquePeriodicWork(WORK_NAME_ACTIVATE_ALARMS, ExistingPeriodicWorkPolicy.REPLACE, periodicWorkRequest);
}
//---------------------------------------------------------------------------------------------------------
@@ -333,7 +316,8 @@ static void cancelScheduledPeriodicWork(Context context) {
try {
WorkManager.initialize(context, new Configuration.Builder().setMinimumLoggingLevel(Log.DEBUG).build());
- } catch (Exception ignored) {}
+ } catch (Exception ignored) {
+ }
WorkManager.getInstance(context).cancelUniqueWork(WORK_NAME_ACTIVATE_ALARMS);
}
@@ -343,11 +327,11 @@ static void cancelScheduledPeriodicWork(Context context) {
/**
* Get the theme that can be applied using {@link AppCompatDelegate#setDefaultNightMode(int)}.
*
- * @param theme The theme value as stored in {@link android.content.SharedPreferences}. Can only have the values
- * {@link #THEME_AUTO_TIME}, {@link #THEME_LIGHT}, {@link #THEME_DARK} or {@link #THEME_SYSTEM}.
+ * @param theme The theme value as stored in {@link android.content.SharedPreferences}. Can only have the values {@link #THEME_AUTO_TIME}, {@link
+ * #THEME_LIGHT}, {@link #THEME_DARK} or {@link #THEME_SYSTEM}.
*
- * @return Can have the values {@link AppCompatDelegate#MODE_NIGHT_YES}, {@link AppCompatDelegate#MODE_NIGHT_NO} or
- * {@link AppCompatDelegate#MODE_NIGHT_FOLLOW_SYSTEM}.
+ * @return Can have the values {@link AppCompatDelegate#MODE_NIGHT_YES}, {@link AppCompatDelegate#MODE_NIGHT_NO} or {@link
+ * AppCompatDelegate#MODE_NIGHT_FOLLOW_SYSTEM}.
*/
static int getTheme(int theme) {
switch (theme) {
@@ -358,8 +342,7 @@ static int getTheme(int theme) {
case THEME_DARK:
return AppCompatDelegate.MODE_NIGHT_YES;
default:
- if (LocalTime.now().isAfter(LocalTime.of(21, 59))
- || LocalTime.now().isBefore(LocalTime.of(6, 0))) {
+ if (LocalTime.now().isAfter(LocalTime.of(21, 59)) || LocalTime.now().isBefore(LocalTime.of(6, 0))) {
return AppCompatDelegate.MODE_NIGHT_YES;
} else {
return AppCompatDelegate.MODE_NIGHT_NO;
@@ -370,10 +353,14 @@ static int getTheme(int theme) {
//---------------------------------------------------------------------------------------------------------
static void killServices(Context context, int alarmID) {
- Intent intent = new Intent()
- .putExtra(BUNDLE_KEY_ALARM_ID, alarmID)
- .setAction(ACTION_STOP_IMMEDIATELY);
- context.sendBroadcast(intent);
+
+ if (Service_RingAlarm.isThisServiceRunning && Service_RingAlarm.alarmID == alarmID) {
+ Intent intent1 = new Intent(context, Service_RingAlarm.class);
+ context.stopService(intent1);
+ } else if (Service_SnoozeAlarm.isThisServiceRunning && Service_SnoozeAlarm.alarmID == alarmID) {
+ Intent intent1 = new Intent(context, Service_SnoozeAlarm.class);
+ context.stopService(intent1);
+ }
}
//---------------------------------------------------------------------------------------------------------
@@ -386,11 +373,10 @@ static void killServices(Context context, int alarmID) {
* @param isRepeatOn Whether repeat is on or off.
* @param repeatDays The days when the alarm should be repeated. Should follow {@link DayOfWeek} enum.
*
- * @return A {@link LocalDateTime} object representing when the alarm should ring. This should be transformed into a
- * {@link java.time.ZonedDateTime} object and then passed to {@link android.app.AlarmManager}.
+ * @return A {@link LocalDateTime} object representing when the alarm should ring. This should be transformed into a {@link java.time.ZonedDateTime} object
+ * and then passed to {@link android.app.AlarmManager}.
*/
- static LocalDateTime getAlarmDateTime(LocalDate alarmDate, LocalTime alarmTime, boolean isRepeatOn,
- @Nullable ArrayList repeatDays) {
+ static LocalDateTime getAlarmDateTime(LocalDate alarmDate, LocalTime alarmTime, boolean isRepeatOn, @Nullable ArrayList repeatDays) {
LocalDateTime alarmDateTime;
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/Fragment_AlarmDetails_Main.java b/app/src/main/java/in/basulabs/shakealarmclock/Fragment_AlarmDetails_Main.java
index 36e78fd..5db0b80 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Fragment_AlarmDetails_Main.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Fragment_AlarmDetails_Main.java
@@ -323,7 +323,7 @@ private void displayAlarmTone() {
} else {
- String fileNameWithExt = null;
+ String fileName = null;
try (Cursor cursor = requireContext().getContentResolver()
.query(viewModel.getAlarmToneUri(), null, null, null, null)) {
@@ -333,17 +333,17 @@ private void displayAlarmTone() {
int index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if (index != - 1) {
- fileNameWithExt = cursor.getString(index);
+ fileName = cursor.getString(index);
} else {
- fileNameWithExt = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
+ fileName = cursor.getString(RingtoneManager.TITLE_COLUMN_INDEX);
}
}
} catch (Exception ignored) {
}
}
- if (fileNameWithExt != null) {
- alarmToneTV.setText(fileNameWithExt);
+ if (fileName != null) {
+ alarmToneTV.setText(fileName);
} else {
alarmToneTV.setText(viewModel.getAlarmToneUri().getLastPathSegment());
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java b/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java
index d22377a..b33cc7b 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java
@@ -25,10 +25,8 @@
import android.os.CountDownTimer;
import android.os.Handler;
import android.os.IBinder;
-import android.os.Process;
import android.os.VibrationEffect;
import android.os.Vibrator;
-import android.util.Log;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
@@ -72,7 +70,9 @@ public class Service_RingAlarm extends Service implements SensorEventListener {
private Uri alarmToneUri;
- private int alarmID;
+ public static int alarmID = - 1;
+
+ public static boolean isThisServiceRunning = false;
private SharedPreferences sharedPreferences;
@@ -89,12 +89,6 @@ public void onReceive(Context context, Intent intent) {
snoozeAlarm();
} else if (Objects.equals(intent.getAction(), ConstantsAndStatics.ACTION_CANCEL_ALARM)) {
dismissAlarm();
- } else if (intent.getAction().equals(ConstantsAndStatics.ACTION_STOP_IMMEDIATELY)){
- if (Objects.requireNonNull(intent.getExtras()).getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID) == alarmID){
- stopForeground(true);
- stopSelf();
- Process.killProcess(Process.myPid());
- }
}
}
};
@@ -109,6 +103,7 @@ public int onStartCommand(Intent intent, int flags, int startId) {
} else {
startForeground(NOTIFICATION_ID, buildRingNotification());
}
+ isThisServiceRunning = true;
ConstantsAndStatics.cancelScheduledPeriodicWork(this);
@@ -127,7 +122,6 @@ public int onStartCommand(Intent intent, int flags, int startId) {
alarmToneUri = alarmDetails.getParcelable(ConstantsAndStatics.BUNDLE_KEY_ALARM_TONE_URI);
alarmID = alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID);
- Log.e(this.getClass().getSimpleName(), "alarmID = " + alarmID);
ringTimer = new CountDownTimer(60000, 1000) {
@@ -158,7 +152,6 @@ public void onFinish() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConstantsAndStatics.ACTION_SNOOZE_ALARM);
intentFilter.addAction(ConstantsAndStatics.ACTION_CANCEL_ALARM);
- intentFilter.addAction(ConstantsAndStatics.ACTION_STOP_IMMEDIATELY);
registerReceiver(broadcastReceiver, intentFilter);
ringAlarm();
@@ -185,6 +178,8 @@ public void onDestroy() {
}
audioManager.setStreamVolume(AudioManager.STREAM_ALARM, initialAlarmStreamVolume, 0);
unregisterReceiver(broadcastReceiver);
+ isThisServiceRunning = false;
+ alarmID = - 1;
}
//--------------------------------------------------------------------------------------------------
@@ -208,8 +203,7 @@ private void initialiseShakeSensor() {
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
- NotificationChannel channel = new NotificationChannel(Integer.toString(NOTIFICATION_ID),
- "in.basulabs.shakealarmclock Notifications", importance);
+ NotificationChannel channel = new NotificationChannel(Integer.toString(NOTIFICATION_ID),"in.basulabs.shakealarmclock Notifications", importance);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
channel.setSound(null, null);
assert notificationManager != null;
@@ -220,11 +214,11 @@ private void createNotificationChannel() {
//--------------------------------------------------------------------------------------------------
/**
- * Creates a notification that can be shown when the alarm is ringing. Has a full screen intent to {@link
- * Activity_RingAlarm}. The content intent points to {@link Activity_AlarmsList}.
+ * Creates a notification that can be shown when the alarm is ringing. Has a full screen intent to {@link Activity_RingAlarm}. The content intent points to
+ * {@link Activity_AlarmsList}.
*
- * @return A {@link Notification} that can be used with {@link #startForeground(int, Notification)} or displayed
- * with {@link NotificationManager#notify(int, Notification)}.
+ * @return A {@link Notification} that can be used with {@link #startForeground(int, Notification)} or displayed with {@link NotificationManager#notify(int,
+ * Notification)}.
*/
private Notification buildRingNotification() {
createNotificationChannel();
@@ -233,8 +227,7 @@ private Notification buildRingNotification() {
fullScreenIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
fullScreenIntent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
- PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 3054,
- fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 3054, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
Integer.toString(NOTIFICATION_ID))
@@ -259,8 +252,7 @@ private void ringAlarm() {
notificationManager.notify(NOTIFICATION_ID, buildRingNotification());
initialiseShakeSensor();
- if (! (alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_TYPE)
- == ConstantsAndStatics.ALARM_TYPE_VIBRATE_ONLY)) {
+ if (! (alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_TYPE) == ConstantsAndStatics.ALARM_TYPE_VIBRATE_ONLY)) {
mediaPlayer = new MediaPlayer();
AudioAttributes attributes = new AudioAttributes.Builder()
@@ -268,8 +260,7 @@ private void ringAlarm() {
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build();
- audioManager.setStreamVolume(AudioManager.STREAM_ALARM,
- alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_VOLUME), 0);
+ audioManager.setStreamVolume(AudioManager.STREAM_ALARM, alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_VOLUME), 0);
try {
mediaPlayer.setDataSource(this, alarmToneUri);
@@ -279,8 +270,7 @@ private void ringAlarm() {
} catch (IOException ignored) {
}
- if (alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_TYPE)
- == ConstantsAndStatics.ALARM_TYPE_SOUND_AND_VIBRATE) {
+ if (alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_TYPE) == ConstantsAndStatics.ALARM_TYPE_SOUND_AND_VIBRATE) {
alarmVibration();
}
mediaPlayer.start();
@@ -316,8 +306,7 @@ private void alarmVibration() {
//--------------------------------------------------------------------------------------------------
/**
- * Snoozes the alarm. If snooze is off, or the snoze frequency has been reached, the alarm will be cancelled by
- * calling {@link #dismissAlarm()}.
+ * Snoozes the alarm. If snooze is off, or the snoze frequency has been reached, the alarm will be cancelled by calling {@link #dismissAlarm()}.
*/
private void snoozeAlarm() {
@@ -325,8 +314,7 @@ private void snoozeAlarm() {
if (alarmDetails.getBoolean(ConstantsAndStatics.BUNDLE_KEY_IS_SNOOZE_ON)) {
- if (numberOfTimesTheAlarmHasBeenSnoozed < alarmDetails
- .getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_FREQUENCY)) {
+ if (numberOfTimesTheAlarmHasBeenSnoozed < alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_FREQUENCY)) {
numberOfTimesTheAlarmHasBeenSnoozed++;
@@ -355,9 +343,7 @@ private void dismissAlarm() {
stopRinging();
cancelPendingIntent();
- Thread thread_toggleAlarm = new Thread(
- () -> alarmDatabase.alarmDAO()
- .toggleAlarm(alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID), 0));
+ Thread thread_toggleAlarm = new Thread(() -> alarmDatabase.alarmDAO().toggleAlarm(alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID), 0));
//////////////////////////////////////////////////////
// If repeat is on, set another alarm. Otherwise
@@ -439,17 +425,16 @@ private void stopRinging() {
private void setAlarm(LocalDateTime alarmDateTime) {
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
- Intent intent = new Intent(this, AlarmBroadcastReceiver.class);
- intent.setAction(ConstantsAndStatics.ACTION_DELIVER_ALARM);
- intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
- intent.putExtra(ConstantsAndStatics.BUNDLE_KEY_ALARM_DETAILS, alarmDetails);
+ Intent intent = new Intent(this, AlarmBroadcastReceiver.class)
+ .setAction(ConstantsAndStatics.ACTION_DELIVER_ALARM)
+ .setFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ .putExtra(ConstantsAndStatics.BUNDLE_KEY_ALARM_DETAILS, alarmDetails);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, alarmID, intent, PendingIntent.FLAG_CANCEL_CURRENT);
ZonedDateTime zonedDateTime = ZonedDateTime.of(alarmDateTime.withSecond(0), ZoneId.systemDefault());
- alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(zonedDateTime.toEpochSecond() * 1000,
- pendingIntent), pendingIntent);
+ alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(zonedDateTime.toEpochSecond() * 1000, pendingIntent), pendingIntent);
}
//---------------------------------------------------------------------------------------------------
@@ -492,7 +477,7 @@ public void onSensorChanged(SensorEvent event) {
float gForce = (float) Math.sqrt(gX * gX + gY * gY + gZ * gZ);
// gForce will be close to 1 when there is no movement.
- if (gForce >= 3.8f) {
+ if (gForce >= sharedPreferences.getFloat(ConstantsAndStatics.SHARED_PREF_KEY_SHAKE_SENSITIVITY, ConstantsAndStatics.DEFAULT_SHAKE_SENSITIVITY)) {
long currTime = System.currentTimeMillis();
if (Math.abs(currTime - lastShakeTime) > MINIMUM_MILLIS_BETWEEN_SHAKES) {
lastShakeTime = currTime;
@@ -522,17 +507,6 @@ private void shakeVibration() {
} else {
vibrator.vibrate(200);
}
- Thread thread = new Thread(() -> {
- try {
- Thread.sleep(200);
- } catch (InterruptedException ignored) {
- }
- });
- thread.start();
- try {
- thread.join();
- } catch (InterruptedException ignored) {
- }
}
}
@@ -541,4 +515,5 @@ private void shakeVibration() {
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
}
+
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java b/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java
index dd68592..4b5bbc3 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java
@@ -15,7 +15,6 @@
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.IBinder;
-import android.os.Process;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
@@ -34,13 +33,15 @@
public class Service_SnoozeAlarm extends Service {
- private int alarmID;
+ public static int alarmID;
private Bundle alarmDetails;
private static final int NOTIFICATION_ID = 651;
private int numberOfTimesTheAlarmhasBeenSnoozed;
private CountDownTimer snoozeTimer;
+ public static boolean isThisServiceRunning = false;
+
//--------------------------------------------------------------------------------------------------
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@@ -48,12 +49,6 @@ public class Service_SnoozeAlarm extends Service {
public void onReceive(Context context, Intent intent) {
if (Objects.equals(intent.getAction(), ConstantsAndStatics.ACTION_CANCEL_ALARM)) {
dismissAlarm();
- } else if (Objects.equals(intent.getAction(), ConstantsAndStatics.ACTION_STOP_IMMEDIATELY)){
- if (Objects.requireNonNull(intent.getExtras()).getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID) == alarmID){
- stopForeground(true);
- stopSelf();
- Process.killProcess(Process.myPid());
- }
}
}
};
@@ -64,11 +59,11 @@ public void onReceive(Context context, Intent intent) {
public int onStartCommand(Intent intent, int flags, int startId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
- startForeground(NOTIFICATION_ID, buildSnoozeNotification(),
- ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
+ startForeground(NOTIFICATION_ID, buildSnoozeNotification(), ServiceInfo.FOREGROUND_SERVICE_TYPE_NONE);
} else {
startForeground(NOTIFICATION_ID, buildSnoozeNotification());
}
+ isThisServiceRunning = true;
ConstantsAndStatics.cancelScheduledPeriodicWork(this);
@@ -77,12 +72,10 @@ public int onStartCommand(Intent intent, int flags, int startId) {
assert alarmDetails != null;
alarmID = alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID);
- numberOfTimesTheAlarmhasBeenSnoozed =
- intent.getExtras().getInt(Service_RingAlarm.BUNDLE_KEY_NO_OF_TIMES_SNOOZED);
+ numberOfTimesTheAlarmhasBeenSnoozed = intent.getExtras().getInt(Service_RingAlarm.BUNDLE_KEY_NO_OF_TIMES_SNOOZED);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConstantsAndStatics.ACTION_CANCEL_ALARM);
- intentFilter.addAction(ConstantsAndStatics.ACTION_STOP_IMMEDIATELY);
registerReceiver(broadcastReceiver, intentFilter);
Service_SnoozeAlarm myInstance = this;
@@ -95,21 +88,20 @@ public int onStartCommand(Intent intent, int flags, int startId) {
alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_MINUTE), 0, 0),
ZoneId.systemDefault());
- ZonedDateTime newAlarmDateTime = alarmDateTime.plusMinutes(numberOfTimesTheAlarmhasBeenSnoozed * alarmDetails
- .getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_TIME_IN_MINS));
+ ZonedDateTime newAlarmDateTime = alarmDateTime.plusMinutes(numberOfTimesTheAlarmhasBeenSnoozed *
+ alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_TIME_IN_MINS));
- snoozeTimer = new CountDownTimer(Math.abs(Duration.between(ZonedDateTime.now(),
- newAlarmDateTime).toMillis()), 500) {
+ snoozeTimer = new CountDownTimer(Math.abs(Duration.between(ZonedDateTime.now(), newAlarmDateTime).toMillis()), 500) {
@Override
- public void onTick(long l) {
+ public void onTick(long millisUntilFinished) {
}
@Override
public void onFinish() {
- Intent intent1 = new Intent(myInstance, Service_RingAlarm.class);
- intent1.putExtra(ConstantsAndStatics.BUNDLE_KEY_ALARM_DETAILS, alarmDetails);
- intent1.putExtra(Service_RingAlarm.BUNDLE_KEY_NO_OF_TIMES_SNOOZED, numberOfTimesTheAlarmhasBeenSnoozed);
+ Intent intent1 = new Intent(myInstance, Service_RingAlarm.class)
+ .putExtra(ConstantsAndStatics.BUNDLE_KEY_ALARM_DETAILS, alarmDetails)
+ .putExtra(Service_RingAlarm.BUNDLE_KEY_NO_OF_TIMES_SNOOZED, numberOfTimesTheAlarmhasBeenSnoozed);
ContextCompat.startForegroundService(myInstance, intent1);
myInstance.stopSelf();
}
@@ -128,10 +120,8 @@ public void onFinish() {
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_HIGH;
- NotificationChannel channel = new NotificationChannel(Integer.toString(NOTIFICATION_ID),
- "in.basulabs.shakealarmclock Notifications", importance);
- NotificationManager notificationManager = (NotificationManager) getSystemService(
- NOTIFICATION_SERVICE);
+ NotificationChannel channel = new NotificationChannel(Integer.toString(NOTIFICATION_ID),"in.basulabs.shakealarmclock Notifications", importance);
+ NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
channel.setSound(null, null);
assert notificationManager != null;
notificationManager.createNotificationChannel(channel);
@@ -145,11 +135,9 @@ private Notification buildSnoozeNotification() {
Intent intent = new Intent();
intent.setAction(ConstantsAndStatics.ACTION_CANCEL_ALARM);
- PendingIntent contentPendingIntent = PendingIntent.getBroadcast(this, 5017, intent,
- PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent contentPendingIntent = PendingIntent.getBroadcast(this, 5017, intent, PendingIntent.FLAG_UPDATE_CURRENT);
- NotificationCompat.Builder builder = new NotificationCompat.Builder(this,
- Integer.toString(NOTIFICATION_ID))
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(this, Integer.toString(NOTIFICATION_ID))
.setContentTitle(getResources().getString(R.string.app_name))
.setContentText(getResources().getString(R.string.notifContent_snooze))
.setPriority(NotificationCompat.PRIORITY_HIGH)
@@ -174,7 +162,7 @@ private void dismissAlarm() {
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Thread thread_toggleAlarm = new Thread(() ->
- alarmDatabase.alarmDAO().toggleAlarm(alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID),0));
+ alarmDatabase.alarmDAO().toggleAlarm(alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID), 0));
/////////////////////////////////////
// Dismiss the snoozed alarm
@@ -184,7 +172,7 @@ private void dismissAlarm() {
intent.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID),
- intent, PendingIntent.FLAG_NO_CREATE);
+ intent, PendingIntent.FLAG_NO_CREATE);
if (pendingIntent != null) {
alarmManager.cancel(pendingIntent);
@@ -202,7 +190,7 @@ private void dismissAlarm() {
}
} else {
LocalTime alarmTime = LocalTime.of(alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_HOUR),
- alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_MINUTE));
+ alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_MINUTE));
ArrayList repeatDays = alarmDetails.getIntegerArrayList(ConstantsAndStatics.BUNDLE_KEY_REPEAT_DAYS);
@@ -232,13 +220,11 @@ private void dismissAlarm() {
intent.putExtra(ConstantsAndStatics.BUNDLE_KEY_ALARM_DETAILS, alarmDetails);
- PendingIntent pendingIntent2 = PendingIntent.getBroadcast(this,
- alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID), intent, 0);
+ PendingIntent pendingIntent2 = PendingIntent.getBroadcast(this, alarmDetails.getInt(ConstantsAndStatics.BUNDLE_KEY_ALARM_ID), intent, 0);
- ZonedDateTime zonedDateTime = ZonedDateTime.of(alarmDateTime.withSecond(0), ZoneId.systemDefault());
+ ZonedDateTime zonedDateTime = ZonedDateTime.of(alarmDateTime.withSecond(0), ZoneId.systemDefault());
- alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(zonedDateTime.toEpochSecond() * 1000,
- pendingIntent2), pendingIntent2);
+ alarmManager.setAlarmClock(new AlarmManager.AlarmClockInfo(zonedDateTime.toEpochSecond() * 1000, pendingIntent2), pendingIntent2);
}
ConstantsAndStatics.schedulePeriodicWork(this);
stopForeground(true);
@@ -276,6 +262,8 @@ public IBinder onBind(Intent intent) {
public void onDestroy() {
super.onDestroy();
unregisterReceiver(broadcastReceiver);
+ isThisServiceRunning = false;
+ alarmID = -1;
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/ViewModel_RingtonePicker.java b/app/src/main/java/in/basulabs/shakealarmclock/ViewModel_RingtonePicker.java
new file mode 100644
index 0000000..4cc58fd
--- /dev/null
+++ b/app/src/main/java/in/basulabs/shakealarmclock/ViewModel_RingtonePicker.java
@@ -0,0 +1,115 @@
+package in.basulabs.shakealarmclock;
+
+import android.net.Uri;
+
+import androidx.lifecycle.MutableLiveData;
+import androidx.lifecycle.ViewModel;
+
+import java.util.ArrayList;
+
+public class ViewModel_RingtonePicker extends ViewModel {
+
+ private MutableLiveData defaultUri = new MutableLiveData<>();
+ private MutableLiveData existingUri = new MutableLiveData<>();
+ private MutableLiveData pickedUri = new MutableLiveData<>();
+
+ private MutableLiveData showDefault = new MutableLiveData<>();
+ private MutableLiveData showSilent = new MutableLiveData<>();
+ private MutableLiveData wasExistingUriGiven = new MutableLiveData<>();
+ private MutableLiveData playTone = new MutableLiveData<>();
+
+ private MutableLiveData title = new MutableLiveData<>();
+
+ private MutableLiveData> toneUriList = new MutableLiveData<>(new ArrayList<>());
+ private MutableLiveData> toneNameList = new MutableLiveData<>(new ArrayList<>());
+ private MutableLiveData> toneIdList = new MutableLiveData<>(new ArrayList<>());
+
+ public Uri getDefaultUri() {
+ return defaultUri.getValue();
+ }
+
+ public void setDefaultUri(Uri defaultUri) {
+ this.defaultUri.setValue(defaultUri);
+ }
+
+ public Uri getExistingUri() {
+ return existingUri.getValue();
+ }
+
+ public void setExistingUri(Uri existingUri) {
+ this.existingUri.setValue(existingUri);
+ }
+
+ public Uri getPickedUri() {
+ return pickedUri.getValue();
+ }
+
+ public void setPickedUri(Uri pickedUri) {
+ this.pickedUri.setValue(pickedUri);
+ }
+
+ public Boolean getShowDefault() {
+ return showDefault.getValue();
+ }
+
+ public void setShowDefault(boolean showDefault) {
+ this.showDefault.setValue(showDefault);
+ }
+
+ public Boolean getShowSilent() {
+ return showSilent.getValue();
+ }
+
+ public void setShowSilent(boolean showSilent) {
+ this.showSilent.setValue(showSilent);
+ }
+
+ public Boolean getWasExistingUriGiven() {
+ return wasExistingUriGiven.getValue();
+ }
+
+ public void setWasExistingUriGiven(boolean wasExistingUriGiven) {
+ this.wasExistingUriGiven.setValue(wasExistingUriGiven);
+ }
+
+ public Boolean getPlayTone() {
+ return playTone.getValue();
+ }
+
+ public void setPlayTone(boolean playTone) {
+ this.playTone.setValue(playTone);
+ }
+
+ public CharSequence getTitle() {
+ return title.getValue();
+ }
+
+ public void setTitle(CharSequence title) {
+ this.title.setValue(title);
+ }
+
+ public ArrayList getToneUriList() {
+ return toneUriList.getValue();
+ }
+
+ public void setToneUriList(ArrayList toneUriList) {
+ this.toneUriList.setValue(toneUriList);
+ }
+
+ public ArrayList getToneNameList() {
+ return toneNameList.getValue();
+ }
+
+ public void setToneNameList(ArrayList toneNameList) {
+ this.toneNameList.setValue(toneNameList);
+ }
+
+ public ArrayList getToneIdList() {
+ return toneIdList.getValue();
+ }
+
+ public void setToneIdList(ArrayList toneIdList) {
+ this.toneIdList.setValue(toneIdList);
+ }
+
+}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/Worker_ActivateAlarms.java b/app/src/main/java/in/basulabs/shakealarmclock/Worker_ActivateAlarms.java
index c38472a..38d05a8 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Worker_ActivateAlarms.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Worker_ActivateAlarms.java
@@ -128,7 +128,7 @@ private void activateAlarmsIfInactive() {
}
- if (stopExecuting && ! isStopped()) {
+ if ((stopExecuting && ! isStopped()) || Service_RingAlarm.isThisServiceRunning || Service_SnoozeAlarm.isThisServiceRunning) {
break;
}
}
diff --git a/app/src/main/res/layout/activity_settings_expand_shakeoptions.xml b/app/src/main/res/layout/activity_settings_expand_shakeoptions.xml
new file mode 100644
index 0000000..190047d
--- /dev/null
+++ b/app/src/main/res/layout/activity_settings_expand_shakeoptions.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_settings_scrollview.xml b/app/src/main/res/layout/activity_settings_scrollview.xml
index d5e3a01..0f331c0 100644
--- a/app/src/main/res/layout/activity_settings_scrollview.xml
+++ b/app/src/main/res/layout/activity_settings_scrollview.xml
@@ -34,7 +34,7 @@
app:layout_constraintTop_toBottomOf="@+id/textView10" />
+ app:layout_constraintTop_toBottomOf="@+id/shakeSensitivityExpandableLayout" />
+ app:layout_constraintTop_toBottomOf="@+id/snoozeOptionsExpandableLayout" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 42a7bd7..44b3fa9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -101,6 +101,7 @@
so that it can read the tones. Without this permission, the app will not work. Give the permission?
+ Settings
If I shake the phone when an alarm rings,
If I press the power button when an alarm rings,
@@ -129,8 +130,24 @@
Default alarm volume:
Automatically set new tones I select as default tones
+ Shake sensitivity settings\nTest the sensitivity of the shake
+ detector, and change it as you wish
+ Change sensitivity:
+ \u2191\nLeast\nsensitive
+ \u2191\nMost\nsensitive
+ Test shake sensitivity\nTap to enable the shake detector so that you can
+ choose the sensitivity that correctly suits you.
+
Activating alarms. This may take a while…
+
+
+ Test sensitivity of shake detector
+ Shake your phone. A vibration will tell you that a shake event has
+ been detected. Change the sensitivity as per your choice.
+ Stop
+
+
Default alarm tone
\ No newline at end of file