toneIdList;
private AudioAttributes audioAttributes;
private Bundle savedInstanceState;
@@ -64,13 +57,14 @@ public class Activity_RingtonePicker extends AppCompatActivity implements View.O
private RadioGroup radioGroup;
- private static final int DEFAULT_RADIO_BTN_ID = View.generateViewId(), SILENT_RADIO_BTN_ID = View
- .generateViewId();
+ private static final int DEFAULT_RADIO_BTN_ID = View.generateViewId(), SILENT_RADIO_BTN_ID = View.generateViewId();
private static final int FILE_REQUEST_CODE = 4937, PERMISSIONS_REQUEST_CODE = 3720;
private SharedPreferences sharedPreferences;
+ private ViewModel_RingtonePicker viewModel;
+
//----------------------------------------------------------------------------------------------------
@Override
@@ -78,6 +72,8 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ringtonepicker);
+ viewModel = new ViewModelProvider(this).get(ViewModel_RingtonePicker.class);
+
this.savedInstanceState = savedInstanceState;
setSupportActionBar(findViewById(R.id.toolbar4));
@@ -102,10 +98,6 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
Cursor allTonesCursor;
- toneNameList = new ArrayList<>();
- toneUriList = new ArrayList<>();
- toneIdList = new ArrayList<>();
-
if (Objects.equals(getIntent().getAction(), ACTION_RINGTONE_PICKER)) {
int type;
@@ -123,62 +115,62 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
int id = allTonesCursor.getInt(ID_COLUMN_INDEX);
String uri = allTonesCursor.getString(URI_COLUMN_INDEX);
- toneUriList.add(Uri.parse(uri + "/" + id));
- toneNameList.add(allTonesCursor.getString(TITLE_COLUMN_INDEX));
- toneIdList.add(View.generateViewId());
+ viewModel.getToneUriList().add(Uri.parse(uri + "/" + id));
+ viewModel.getToneNameList().add(allTonesCursor.getString(TITLE_COLUMN_INDEX));
+ viewModel.getToneIdList().add(View.generateViewId());
} while (allTonesCursor.moveToNext());
}
});
thread.start();
if (intent.hasExtra(EXTRA_RINGTONE_SHOW_DEFAULT)) {
- showDefault = Objects.requireNonNull(intent.getExtras()).getBoolean(EXTRA_RINGTONE_SHOW_DEFAULT);
+ viewModel.setShowDefault(Objects.requireNonNull(intent.getExtras()).getBoolean(EXTRA_RINGTONE_SHOW_DEFAULT));
} else {
- showDefault = true;
+ viewModel.setShowDefault(true);
}
if (intent.hasExtra(EXTRA_RINGTONE_SHOW_SILENT)) {
- showSilent = Objects.requireNonNull(intent.getExtras()).getBoolean(EXTRA_RINGTONE_SHOW_SILENT);
+ viewModel.setShowSilent(Objects.requireNonNull(intent.getExtras()).getBoolean(EXTRA_RINGTONE_SHOW_SILENT));
} else {
- showSilent = false;
+ viewModel.setShowSilent(false);
}
- if (showDefault) {
+ if (viewModel.getShowDefault()) {
if (intent.hasExtra(EXTRA_RINGTONE_DEFAULT_URI)) {
- defaultUri = Objects.requireNonNull(intent.getExtras()).getParcelable(EXTRA_RINGTONE_DEFAULT_URI);
+ viewModel.setDefaultUri(Objects.requireNonNull(intent.getExtras()).getParcelable(EXTRA_RINGTONE_DEFAULT_URI));
} else {
if (type == RingtoneManager.TYPE_ALARM) {
- defaultUri = Settings.System.DEFAULT_ALARM_ALERT_URI;
+ viewModel.setDefaultUri(Settings.System.DEFAULT_ALARM_ALERT_URI);
} else if (type == RingtoneManager.TYPE_NOTIFICATION) {
- defaultUri = Settings.System.DEFAULT_NOTIFICATION_URI;
+ viewModel.setDefaultUri(Settings.System.DEFAULT_NOTIFICATION_URI);
} else if (type == RingtoneManager.TYPE_RINGTONE) {
- defaultUri = Settings.System.DEFAULT_RINGTONE_URI;
+ viewModel.setDefaultUri(Settings.System.DEFAULT_RINGTONE_URI);
} else {
- defaultUri = RingtoneManager.getActualDefaultRingtoneUri(this, type);
+ viewModel.setDefaultUri(RingtoneManager.getActualDefaultRingtoneUri(this, type));
}
}
} else {
- defaultUri = null;
+ viewModel.setDefaultUri(null);
}
if (intent.hasExtra(EXTRA_RINGTONE_EXISTING_URI)) {
- existingUri = Objects.requireNonNull(intent.getExtras()).getParcelable(EXTRA_RINGTONE_EXISTING_URI);
- wasExistingUriGiven = true;
+ viewModel.setExistingUri(Objects.requireNonNull(intent.getExtras()).getParcelable(EXTRA_RINGTONE_EXISTING_URI));
+ viewModel.setWasExistingUriGiven(true);
} else {
- existingUri = null;
- wasExistingUriGiven = false;
+ viewModel.setExistingUri(null);
+ viewModel.setWasExistingUriGiven(false);
}
if (intent.hasExtra(EXTRA_RINGTONE_TITLE)) {
- title = (CharSequence) Objects.requireNonNull(intent.getExtras()).get(EXTRA_RINGTONE_TITLE);
+ viewModel.setTitle((CharSequence) Objects.requireNonNull(intent.getExtras()).get(EXTRA_RINGTONE_TITLE));
} else {
- title = "Select tone:";
+ viewModel.setTitle("Select tone:");
}
if (intent.hasExtra(ConstantsAndStatics.EXTRA_PLAY_RINGTONE)) {
- playTone = Objects.requireNonNull(intent.getExtras()).getBoolean(ConstantsAndStatics.EXTRA_PLAY_RINGTONE);
+ viewModel.setPlayTone(Objects.requireNonNull(intent.getExtras()).getBoolean(ConstantsAndStatics.EXTRA_PLAY_RINGTONE));
} else {
- playTone = true;
+ viewModel.setPlayTone(true);
}
try {
@@ -201,9 +193,9 @@ public boolean onCreateOptionsMenu(Menu menu) {
// Get the action view used in your playTone item
MenuItem toggleservice = menu.findItem(R.id.playTone);
SwitchCompat actionView = (SwitchCompat) toggleservice.getActionView();
- actionView.setChecked(playTone);
+ actionView.setChecked(viewModel.getPlayTone());
actionView.setOnCheckedChangeListener((buttonView, isChecked) -> {
- playTone = isChecked;
+ viewModel.setPlayTone(isChecked);
if (! isChecked) {
try {
mediaPlayer.stop();
@@ -230,7 +222,9 @@ protected void onResume() {
protected void onPause() {
super.onPause();
try {
- mediaPlayer.stop();
+ if (mediaPlayer.isPlaying()) {
+ mediaPlayer.stop();
+ }
} catch (Exception ignored) {
}
}
@@ -242,46 +236,46 @@ protected void onPause() {
*/
private void populateRadioGroup() {
- Objects.requireNonNull(getSupportActionBar()).setTitle(title);
+ Objects.requireNonNull(getSupportActionBar()).setTitle(viewModel.getTitle());
- if (showDefault) {
+ if (viewModel.getShowDefault()) {
createOneRadioButton(DEFAULT_RADIO_BTN_ID, getResources().getString(R.string.defaultTone));
}
- if (showSilent) {
+ if (viewModel.getShowSilent()) {
createOneRadioButton(SILENT_RADIO_BTN_ID, getResources().getString(R.string.silentTone));
}
- for (int i = 0; i < toneIdList.size(); i++) {
- createOneRadioButton(toneIdList.get(i), toneNameList.get(i));
+ for (int i = 0; i < viewModel.getToneIdList().size(); i++) {
+ createOneRadioButton(viewModel.getToneIdList().get(i), viewModel.getToneNameList().get(i));
}
- if (existingUri != null) {
+ if (viewModel.getExistingUri() != null) {
////////////////////////////////////////////////////////////////////
// As existingUri is not null, we are required to pre-select
// a specific RadioButton.
///////////////////////////////////////////////////////////////////
- if (showDefault && existingUri.equals(defaultUri)) {
+ if (viewModel.getShowDefault() && viewModel.getExistingUri().equals(viewModel.getDefaultUri())) {
///////////////////////////////////////////////////////////////////////////
// The existingUri is same as defaultUri, and showDefault is true.
// So, we check the "Default" RadioButton.
//////////////////////////////////////////////////////////////////////////
((RadioButton) findViewById(DEFAULT_RADIO_BTN_ID)).setChecked(true);
- setPickedUri(defaultUri);
+ setPickedUri(viewModel.getDefaultUri());
} else {
// Find index of existingUri in toneUriList
- int index = toneUriList.indexOf(existingUri);
+ int index = viewModel.getToneUriList().indexOf(viewModel.getExistingUri());
if (index != - 1) {
// toneUriList has existingUri. Check the corresponding RadioButton.
- ((RadioButton) findViewById(toneIdList.get(index))).setChecked(true);
- setPickedUri(existingUri);
+ ((RadioButton) findViewById(viewModel.getToneIdList().get(index))).setChecked(true);
+ setPickedUri(viewModel.getExistingUri());
} else {
///////////////////////////////////////////////////////////////////////
@@ -291,7 +285,7 @@ private void populateRadioGroup() {
// If the file does not exist, we do not select any Radiogroup.
///////////////////////////////////////////////////////////////////////
try (Cursor cursor = getContentResolver()
- .query(existingUri, null, null, null, null)) {
+ .query(viewModel.getExistingUri(), null, null, null, null)) {
if (cursor != null && cursor.getCount() > 0 && cursor.moveToFirst()) {
// existingUri is a valid Uri.
@@ -306,15 +300,15 @@ private void populateRadioGroup() {
int toneId = View.generateViewId();
- toneNameList.add(fileNameWithExt);
- toneUriList.add(existingUri);
- toneIdList.add(toneId);
+ viewModel.getToneNameList().add(fileNameWithExt);
+ viewModel.getToneUriList().add(viewModel.getExistingUri());
+ viewModel.getToneIdList().add(toneId);
createOneRadioButton(toneId, fileNameWithExt);
((RadioButton) findViewById(toneId)).setChecked(true);
- setPickedUri(existingUri);
+ setPickedUri(viewModel.getExistingUri());
}
}
@@ -322,13 +316,13 @@ private void populateRadioGroup() {
}
} else {
- if (wasExistingUriGiven) {
+ if (viewModel.getWasExistingUriGiven()) {
//////////////////////////////////////////////////////////////////////////
// existingUri was specifically passed as a null value. If showSilent
// is true, we pre-select the "Silent" RadioButton. Otherwise
// we do not select any specific RadioButton.
/////////////////////////////////////////////////////////////////////////
- if (showSilent) {
+ if (viewModel.getShowSilent()) {
((RadioButton) findViewById(SILENT_RADIO_BTN_ID)).setChecked(true);
}
}
@@ -340,7 +334,7 @@ private void populateRadioGroup() {
private void setPickedUri(@Nullable Uri newUri) {
if (savedInstanceState == null) {
- pickedUri = newUri;
+ viewModel.setPickedUri(newUri);
}
}
@@ -353,8 +347,7 @@ private void setPickedUri(@Nullable Uri newUri) {
* @param text The text to be set in the {@link RadioButton}.
*/
private void createOneRadioButton(int id, String text) {
- RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT);
+ RadioGroup.LayoutParams params = new RadioGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.setMargins(5, 24, 5, 24);
RadioButton radioButton = new RadioButton(this);
@@ -383,14 +376,14 @@ public boolean onOptionsItemSelected(@NonNull MenuItem item) {
@Override
public void onClick(View view) {
if (view.getId() == DEFAULT_RADIO_BTN_ID) {
- pickedUri = defaultUri;
+ viewModel.setPickedUri(viewModel.getDefaultUri());
playChosenTone();
} else if (view.getId() == SILENT_RADIO_BTN_ID) {
- pickedUri = null;
+ viewModel.setPickedUri(null);
} else if (view.getId() == R.id.chooseCustomToneConstarintLayout) {
openFileBrowser();
} else {
- pickedUri = toneUriList.get(toneIdList.indexOf(view.getId()));
+ viewModel.setPickedUri(viewModel.getToneUriList().get(viewModel.getToneIdList().indexOf(view.getId())));
playChosenTone();
}
}
@@ -400,15 +393,15 @@ public void onClick(View view) {
@Override
public void onBackPressed() {
- if (pickedUri == null) {
- if (showSilent) {
- Intent intent = new Intent().putExtra(EXTRA_RINGTONE_PICKED_URI, pickedUri);
+ if (viewModel.getPickedUri() == null) {
+ if (viewModel.getShowSilent()) {
+ Intent intent = new Intent().putExtra(EXTRA_RINGTONE_PICKED_URI, viewModel.getPickedUri());
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_CANCELED);
}
} else {
- Intent intent = new Intent().putExtra(EXTRA_RINGTONE_PICKED_URI, pickedUri);
+ Intent intent = new Intent().putExtra(EXTRA_RINGTONE_PICKED_URI, viewModel.getPickedUri());
setResult(RESULT_OK, intent);
}
finish();
@@ -465,8 +458,7 @@ private void checkAndRequestPermission() {
.putBoolean(ConstantsAndStatics.SHARED_PREF_KEY_PERMISSION_WAS_ASKED_BEFORE, true)
.commit();
- ActivityCompat.requestPermissions(this,
- new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE);
} else {
////////////////////////////////////////////////////////////////////////////////
@@ -484,9 +476,8 @@ private void checkAndRequestPermission() {
* Shows an {@code AlertDialog} explaining why the permission is necessary.
*/
private void showPermissionExplanationDialog() {
- DialogFragment dialogPermissionReason =
- new AlertDialog_PermissionReason(
- getResources().getString(R.string.permissionReasonExp_ringtonePicker));
+ DialogFragment dialogPermissionReason = new AlertDialog_PermissionReason(
+ getResources().getString(R.string.permissionReasonExp_ringtonePicker));
dialogPermissionReason.setCancelable(false);
dialogPermissionReason.show(getSupportFragmentManager(), "");
}
@@ -494,8 +485,7 @@ private void showPermissionExplanationDialog() {
//--------------------------------------------------------------------------------------------------
@Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
- @NonNull int[] grantResults) {
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Permission granted", Toast.LENGTH_SHORT).show();
@@ -520,10 +510,10 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten
if (cursor != null) {
- if (toneUriList.contains(toneUri)) {
+ if (viewModel.getToneUriList().contains(toneUri)) {
- int index = toneUriList.indexOf(toneUri);
- ((RadioButton) findViewById(toneIdList.get(index))).setChecked(true);
+ int index = viewModel.getToneUriList().indexOf(toneUri);
+ ((RadioButton) findViewById(viewModel.getToneIdList().get(index))).setChecked(true);
} else {
@@ -534,15 +524,15 @@ protected void onActivityResult(int requestCode, int resultCode, @Nullable Inten
String fileNameWithoutExt = fileNameWithExt.substring(0, fileNameWithExt.indexOf("."));
int toneId = View.generateViewId();
- toneNameList.add(fileNameWithoutExt);
- toneUriList.add(toneUri);
- toneIdList.add(toneId);
+ viewModel.getToneNameList().add(fileNameWithoutExt);
+ viewModel.getToneUriList().add(toneUri);
+ viewModel.getToneIdList().add(toneId);
createOneRadioButton(toneId, fileNameWithoutExt);
((RadioButton) findViewById(toneId)).setChecked(true);
}
- pickedUri = toneUri;
+ viewModel.setPickedUri(toneUri);
playChosenTone();
}
}
@@ -570,8 +560,7 @@ public void onDialogPositiveClick(DialogFragment dialogFragment) {
startActivity(intent);
} else {
- ActivityCompat.requestPermissions(this,
- new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE);
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_CODE);
}
}
}
@@ -589,19 +578,21 @@ public void onDialogNegativeClick(DialogFragment dialogFragment) {
//----------------------------------------------------------------------------------------------------
private void playChosenTone() {
- if (pickedUri != null && playTone) {
+ if (viewModel.getPickedUri() != null && viewModel.getPlayTone()) {
try {
mediaPlayer.reset();
- mediaPlayer.setDataSource(this, pickedUri);
+ mediaPlayer.setDataSource(this, viewModel.getPickedUri());
mediaPlayer.setLooping(false);
mediaPlayer.setAudioAttributes(audioAttributes);
- mediaPlayer.prepare();
- mediaPlayer.start();
+ mediaPlayer.prepareAsync();
+ mediaPlayer.setOnPreparedListener(MediaPlayer::start);
} catch (Exception ignored) {
}
}
}
+ //----------------------------------------------------------------------------------------------------
+
@Override
protected void onDestroy() {
super.onDestroy();
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/Activity_Settings.java b/app/src/main/java/in/basulabs/shakealarmclock/Activity_Settings.java
index 25aeb80..ca65d71 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Activity_Settings.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Activity_Settings.java
@@ -49,8 +49,7 @@ public class Activity_Settings extends AppCompatActivity implements AdapterView.
private SwitchCompat snoozeStateSwitch;
private CheckBox autoSelectToneCheckBox;
- private static final String SAVE_INSTANCE_KEY_LAYOUT_EXPANDED =
- "in.basulabs.shakealarmclock.Activity_Settings.LAYOUT_EXPANDED";
+ private static final String SAVE_INSTANCE_KEY_LAYOUT_EXPANDED = "in.basulabs.shakealarmclock.Activity_Settings.LAYOUT_EXPANDED";
private int defaultTheme;
@@ -68,7 +67,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
////////////////////////////////////
setSupportActionBar(findViewById(R.id.toolbar5));
Objects.requireNonNull(getSupportActionBar()).setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setTitle("Settings");
+ getSupportActionBar().setTitle(R.string.settings_title);
//////////////////////////////////////////////////
// Get SharedPreferences and its editor:
@@ -134,7 +133,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
///////////////////////////////////////////////////////////
// Initialise expandable layout for snooze options:
//////////////////////////////////////////////////////////
- snoozeOptionsExpandableLayout = findViewById(R.id.expandable_layout);
+ snoozeOptionsExpandableLayout = findViewById(R.id.snoozeOptionsExpandableLayout);
if (savedInstanceState == null) {
snoozeOptionsExpandableLayout.setExpanded(false);
} else {
@@ -246,8 +245,7 @@ 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);
}
@@ -287,10 +285,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 +296,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());
}
diff --git a/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java b/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
index a29b13a..a719155 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,20 @@ 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";
/**
* Indicates that the ringing alarm should be snoozed.
@@ -249,15 +231,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 +248,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 +263,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 +284,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 +293,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 +312,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 +323,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 +338,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 +349,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 +369,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..be19678 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;
}
//--------------------------------------------------------------------------------------------------
@@ -220,11 +215,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();
@@ -316,8 +311,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() {
@@ -541,4 +535,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..9dfe26e 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);
@@ -82,7 +77,6 @@ public int onStartCommand(Intent intent, int flags, int startId) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ConstantsAndStatics.ACTION_CANCEL_ALARM);
- intentFilter.addAction(ConstantsAndStatics.ACTION_STOP_IMMEDIATELY);
registerReceiver(broadcastReceiver, intentFilter);
Service_SnoozeAlarm myInstance = this;
@@ -96,10 +90,10 @@ public int onStartCommand(Intent intent, int flags, int startId) {
ZoneId.systemDefault());
ZonedDateTime newAlarmDateTime = alarmDateTime.plusMinutes(numberOfTimesTheAlarmhasBeenSnoozed * alarmDetails
- .getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_TIME_IN_MINS));
+ .getInt(ConstantsAndStatics.BUNDLE_KEY_SNOOZE_TIME_IN_MINS));
snoozeTimer = new CountDownTimer(Math.abs(Duration.between(ZonedDateTime.now(),
- newAlarmDateTime).toMillis()), 500) {
+ newAlarmDateTime).toMillis()), 500) {
@Override
public void onTick(long l) {
@@ -174,7 +168,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 +178,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 +196,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);
@@ -233,12 +227,12 @@ 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);
+ 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);
+ pendingIntent2), pendingIntent2);
}
ConstantsAndStatics.schedulePeriodicWork(this);
stopForeground(true);
@@ -276,6 +270,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/res/layout/activity_settings_scrollview.xml b/app/src/main/res/layout/activity_settings_scrollview.xml
index d5e3a01..91a586a 100644
--- a/app/src/main/res/layout/activity_settings_scrollview.xml
+++ b/app/src/main/res/layout/activity_settings_scrollview.xml
@@ -34,13 +34,13 @@
app:layout_constraintTop_toBottomOf="@+id/textView10" />
+ app:layout_constraintTop_toBottomOf="@+id/snoozeOptionsExpandableLayout" />
+ Settings
If I shake the phone when an alarm rings,
If I press the power button when an alarm rings,
@@ -131,6 +132,8 @@
Activating alarms. This may take a while…
+
+
Default alarm tone
\ No newline at end of file
From cfb60427d95250c3baae73f23e565f84210f9704 Mon Sep 17 00:00:00 2001
From: WrichikBasu <56736644+WrichikBasu@users.noreply.github.com>
Date: Mon, 2 Nov 2020 20:16:25 +0530
Subject: [PATCH 2/2] Support for changing sensitivity of shake detector
Sensitivity of shake detector can now be changed by going to settings.
---
app/build.gradle | 4 +-
app/src/main/AndroidManifest.xml | 1 +
.../shakealarmclock/Activity_AlarmsList.java | 6 +-
.../shakealarmclock/Activity_Settings.java | 282 ++++++++++++++----
.../AlertDialog_DiscardChanges.java | 3 +-
.../AlertDialog_PermissionReason.java | 8 +-
.../AlertDialog_TestShakeSensitivity.java | 54 ++++
.../shakealarmclock/ConstantsAndStatics.java | 6 +-
.../shakealarmclock/Service_RingAlarm.java | 46 +--
.../shakealarmclock/Service_SnoozeAlarm.java | 36 +--
.../Worker_ActivateAlarms.java | 2 +-
.../activity_settings_expand_shakeoptions.xml | 90 ++++++
.../layout/activity_settings_scrollview.xml | 67 ++++-
app/src/main/res/values/strings.xml | 14 +
14 files changed, 496 insertions(+), 123 deletions(-)
create mode 100644 app/src/main/java/in/basulabs/shakealarmclock/AlertDialog_TestShakeSensitivity.java
create mode 100644 app/src/main/res/layout/activity_settings_expand_shakeoptions.xml
diff --git a/app/build.gradle b/app/build.gradle
index eb149ed..038f2c1 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -8,8 +8,8 @@ android {
applicationId "in.basulabs.shakealarmclock"
minSdkVersion 21
targetSdkVersion 30
- versionCode 8
- versionName "1.2.5"
+ versionCode 10
+ versionName "1.2.7"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 324432c..f136e9a 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,7 @@
+
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);
///////////////////////////////////////////////////////////
@@ -137,9 +153,9 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
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);
@@ -148,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);
@@ -158,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
@@ -248,6 +256,69 @@ public void afterTextChanged(Editable editable) {
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);
}
//-----------------------------------------------------------------------------------------------------
@@ -255,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);
}
@@ -359,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
@@ -417,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)));
}
//-----------------------------------------------------------------------------------------------------
@@ -501,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;
}
}
@@ -543,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 a719155..dede3e8 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/ConstantsAndStatics.java
@@ -206,7 +206,11 @@ final class ConstantsAndStatics {
/**
* {@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.
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 be19678..b33cc7b 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Service_RingAlarm.java
@@ -203,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;
@@ -228,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))
@@ -254,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()
@@ -263,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);
@@ -274,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();
@@ -319,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++;
@@ -349,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
@@ -433,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);
}
//---------------------------------------------------------------------------------------------------
@@ -486,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;
@@ -516,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) {
- }
}
}
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 9dfe26e..4b5bbc3 100644
--- a/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java
+++ b/app/src/main/java/in/basulabs/shakealarmclock/Service_SnoozeAlarm.java
@@ -72,8 +72,7 @@ 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);
@@ -89,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();
}
@@ -122,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);
@@ -139,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)
@@ -226,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());
- 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);
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 91a586a..0f331c0 100644
--- a/app/src/main/res/layout/activity_settings_scrollview.xml
+++ b/app/src/main/res/layout/activity_settings_scrollview.xml
@@ -40,7 +40,7 @@
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
app:el_duration="500"
- app:el_expanded="true"
+ app:el_expanded="false"
app:el_parallax="0.5"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
@@ -95,7 +95,7 @@
android:background="?android:attr/listDivider"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/powerBtnOpSpinner" />
+ app:layout_constraintTop_toBottomOf="@+id/shakeSensitivityExpandableLayout" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ 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 52a64be..44b3fa9 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -130,9 +130,23 @@
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