diff options
author | Artem Chep <artemchep@gmail.com> | 2013-01-08 10:36:33 -0500 |
---|---|---|
committer | Danny Baumann <dannybaumann@web.de> | 2013-01-22 11:16:46 +0100 |
commit | d8aa32d1fbbd1fcc186514ec2d37a8c2606f6eba (patch) | |
tree | ce2decd3c3595113f640034f696dd5789cea2eec | |
parent | fc06d831472c6f56fa02acb6563417117bca6c35 (diff) | |
download | android_packages_apps_DeskClock-d8aa32d1fbbd1fcc186514ec2d37a8c2606f6eba.tar.gz android_packages_apps_DeskClock-d8aa32d1fbbd1fcc186514ec2d37a8c2606f6eba.tar.bz2 android_packages_apps_DeskClock-d8aa32d1fbbd1fcc186514ec2d37a8c2606f6eba.zip |
Added flip and shake to snooze
both the actions flipping the phone, and shaking the phone can do one of the following operations
1. do nothing
2. snooze the alarm
3. dismiss the alarm
has been taken from Artem AchepClock implementation for ICS deskclock
source at http://github.com/Achep/android_packages_apps_DeskClock
PatchSet2 : Eliminated White Spaces
PatchSet3 : Fixed a line issue
PatchSet4 : Updated Correct Author
PatchSet5 : Really updated Author
PatchSet6 : Fixed a few lines, in-line comments
PatchSet7 : Cleanup; addressed Danny's comments
PatchSet8 : More cleanup
PatchSet10: Clean up string resources
Change-Id: Ifea8185690b07923b0c7cb3ab9b33ad5da7306e8
-rw-r--r-- | res/values/strings.xml | 28 | ||||
-rw-r--r-- | res/xml/settings.xml | 17 | ||||
-rw-r--r-- | src/com/android/deskclock/AlarmAlertFullScreen.java | 177 | ||||
-rw-r--r-- | src/com/android/deskclock/SettingsActivity.java | 26 |
4 files changed, 243 insertions, 5 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml index b3a4cb4d1..5e96d7734 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -195,6 +195,24 @@ <item quantity="other">minutes</item> </plurals> + <!-- Setting title for the flip action setting. --> + <string name="flip_action_title">Flip action</string> + + <!-- Dialog title of the flip action setting. --> + <string name="flip_action_dialog_title">Flip device to\u2026</string> + + <!-- Setting summary for the flip action setting. --> + <string name="flip_action_summary">Flipping the phone down will <xliff:g id="action">%s</xliff:g></string> + + <!-- Setting title for the shake action setting. --> + <string name="shake_action_title">Shake action</string> + + <!-- Dialog title for the shake action setting. --> + <string name="shake_action_dialog_title">Shake device to\u2026</string> + + <!-- Setting summary for the shake action setting. --> + <string name="shake_action_summary">Shaking the phone will <xliff:g id="action">%s</xliff:g></string> + <!-- Auto silence preference title --> <string name="auto_silence_title">Silence after</string> @@ -264,7 +282,15 @@ <item>Snooze</item> <item>Dismiss</item> <item>Do nothing</item> - </string-array> + </string-array> + + <!-- Summary texts for shake and flip actions. Must be ordered by numerical + value (do nothing = 0, snooze = 1, dismiss = 2) --> + <string-array name="action_summary_entries"> + <item>do nothing</item> + <item>snooze alarm</item> + <item>dismiss alarm</item> + </string-array> <!-- Values for the side-button setting. --> <string-array name="volume_button_setting_values" translatable="false"> diff --git a/res/xml/settings.xml b/res/xml/settings.xml index 22e0d1712..5d8a356ef 100644 --- a/res/xml/settings.xml +++ b/res/xml/settings.xml @@ -39,6 +39,23 @@ <PreferenceCategory android:title="@string/alarm_settings"> + + <ListPreference + android:key="flip_action" + android:title="@string/flip_action_title" + android:dialogTitle="@string/flip_action_dialog_title" + android:entries="@array/volume_button_setting_entries" + android:entryValues="@array/volume_button_setting_values" + android:defaultValue="0" /> + + <ListPreference + android:key="shake_action" + android:title="@string/shake_action_title" + android:dialogTitle="@string/shake_action_dialog_title" + android:entries="@array/volume_button_setting_entries" + android:entryValues="@array/volume_button_setting_values" + android:defaultValue="1"/> + <ListPreference android:key="auto_silence" android:title="@string/auto_silence_title" diff --git a/src/com/android/deskclock/AlarmAlertFullScreen.java b/src/com/android/deskclock/AlarmAlertFullScreen.java index 0cf49f89e..76166a9d2 100644 --- a/src/com/android/deskclock/AlarmAlertFullScreen.java +++ b/src/com/android/deskclock/AlarmAlertFullScreen.java @@ -26,6 +26,11 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; import android.content.res.Configuration; +import android.content.SharedPreferences; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; import android.os.Bundle; import android.os.Handler; import android.os.Message; @@ -53,6 +58,9 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig // These defaults must match the values in res/xml/settings.xml private static final String DEFAULT_SNOOZE = "10"; private static final String DEFAULT_VOLUME_BEHAVIOR = "2"; + private static final String DEFAULT_FLIP_ACTION = "0"; + private static final String DEFAULT_SHAKE_ACTION = "1"; + protected static final String SCREEN_OFF = "screen_off"; protected Alarm mAlarm; @@ -67,6 +75,13 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig private static final long PING_AUTO_REPEAT_DELAY_MSEC = 1200; private boolean mPingEnabled = true; + private int mFlipAction; + private int mShakeAction; + + // constants for no action/snooze/dismiss + private static final int ALARM_NO_ACTION = 0; + private static final int ALARM_SNOOZE = 1; + private static final int ALARM_DISMISS = 2; // Receives the ALARM_KILLED action from the AlarmKlaxon, // and also ALARM_SNOOZE_ACTION / ALARM_DISMISS_ACTION from other applications @@ -101,6 +116,105 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig } }; + private final SensorEventListener mFlipListener = new SensorEventListener() { + private static final int FACE_UP_LOWER_LIMIT = -45; + private static final int FACE_UP_UPPER_LIMIT = 45; + private static final int FACE_DOWN_UPPER_LIMIT = 135; + private static final int FACE_DOWN_LOWER_LIMIT = -135; + private static final int TILT_UPPER_LIMIT = 45; + private static final int TILT_LOWER_LIMIT = -45; + private static final int SENSOR_SAMPLES = 3; + + private boolean mWasFaceUp; + private boolean[] mSamples = new boolean[SENSOR_SAMPLES]; + private int mSampleIndex; + + @Override + public void onAccuracyChanged(Sensor sensor, int acc) { + } + + @Override + public void onSensorChanged(SensorEvent event) { + // Add a sample overwriting the oldest one. Several samples + // are used + // to avoid the erroneous values the sensor sometimes + // returns. + float y = event.values[1]; + float z = event.values[2]; + + if (!mWasFaceUp) { + // Check if its face up enough. + mSamples[mSampleIndex] = y > FACE_UP_LOWER_LIMIT + && y < FACE_UP_UPPER_LIMIT + && z > TILT_LOWER_LIMIT && z < TILT_UPPER_LIMIT; + + // The device first needs to be face up. + boolean faceUp = true; + for (boolean sample : mSamples) { + faceUp = faceUp && sample; + } + if (faceUp) { + mWasFaceUp = true; + for (int i = 0; i < SENSOR_SAMPLES; i++) { + mSamples[i] = false; + } + } + } else { + // Check if its face down enough. Note that wanted + // values go from FACE_DOWN_UPPER_LIMIT to 180 + // and from -180 to FACE_DOWN_LOWER_LIMIT + mSamples[mSampleIndex] = (y > FACE_DOWN_UPPER_LIMIT || y < FACE_DOWN_LOWER_LIMIT) + && z > TILT_LOWER_LIMIT + && z < TILT_UPPER_LIMIT; + + boolean faceDown = true; + for (boolean sample : mSamples) { + faceDown = faceDown && sample; + } + if (faceDown) { + handleAction(mFlipAction); + } + } + + mSampleIndex = ((mSampleIndex + 1) % SENSOR_SAMPLES); + } + }; + + private final SensorEventListener mShakeListener = new SensorEventListener() { + private static final float SENSITIVITY = 16; + private static final int BUFFER = 5; + private float[] gravity = new float[3]; + private float average = 0; + private int fill = 0; + + @Override + public void onAccuracyChanged(Sensor sensor, int acc) { + } + + public void onSensorChanged(SensorEvent event) { + final float alpha = 0.8F; + + for (int i = 0; i < 3; i++) { + gravity[i] = alpha * gravity[i] + (1 - alpha) * event.values[i]; + } + + float x = event.values[0] - gravity[0]; + float y = event.values[1] - gravity[1]; + float z = event.values[2] - gravity[2]; + + if (fill <= BUFFER) { + average += Math.abs(x) + Math.abs(y) + Math.abs(z); + fill++; + } else { + if (average / BUFFER >= SENSITIVITY) { + handleAction(mShakeAction); + } + average = 0; + fill = 0; + } + } + }; + @Override protected void onCreate(Bundle icicle) { super.onCreate(icicle); @@ -254,12 +368,12 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig return (NotificationManager) getSystemService(NOTIFICATION_SERVICE); } + private SensorManager getSensorManager() { + return (SensorManager) getSystemService(Context.SENSOR_SERVICE); + } + // Dismiss the alarm. private void dismiss(boolean killed) { - if (LOG) { - Log.v("AlarmAlertFullScreen - dismiss"); - } - Log.i(killed ? "Alarm killed" : "Alarm dismissed by user"); // The service told us that the alarm has been killed, do not modify // the notification or stop the service. @@ -272,6 +386,45 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig finish(); } + private void attachListeners() { + final SensorManager sm = getSensorManager(); + + if (mFlipAction != ALARM_NO_ACTION) { + sm.registerListener(mFlipListener, + sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), + SensorManager.SENSOR_DELAY_NORMAL); + } + + if (mShakeAction != ALARM_NO_ACTION) { + sm.registerListener(mShakeListener, + sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), + SensorManager.SENSOR_DELAY_GAME); + } + } + + private void detachListeners() { + if (mFlipAction != ALARM_NO_ACTION) { + getSensorManager().unregisterListener(mFlipListener); + } + if (mShakeAction != ALARM_NO_ACTION) { + getSensorManager().unregisterListener(mShakeListener); + } + } + + private void handleAction(int action) { + switch (action) { + case ALARM_SNOOZE: + snooze(); + break; + case ALARM_DISMISS: + dismiss(false); + break; + case ALARM_NO_ACTION: + default: + break; + } + } + /** * this is called when a second alarm is triggered while a * previous alert window is still active. @@ -302,6 +455,14 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig if (LOG) { Log.v("AlarmAlertFullScreen - onResume"); } + + final SharedPreferences prefs = PreferenceManager. + getDefaultSharedPreferences(this); + mFlipAction = Integer.parseInt(prefs.getString( + SettingsActivity.KEY_FLIP_ACTION, DEFAULT_FLIP_ACTION)); + mShakeAction = Integer.parseInt(prefs.getString( + SettingsActivity.KEY_SHAKE_ACTION, DEFAULT_SHAKE_ACTION)); + // If the alarm was deleted at some point, disable snooze. if (Alarms.getAlarm(getContentResolver(), mAlarm.id) == null) { mGlowPadView.setTargetResources(R.array.dismiss_drawables); @@ -313,6 +474,8 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig if (getResources().getBoolean(R.bool.config_rotateAlarmAlert) || mIsDocked) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED); } + + attachListeners(); } @Override @@ -324,6 +487,12 @@ public class AlarmAlertFullScreen extends Activity implements GlowPadView.OnTrig } @Override + public void onPause() { + super.onPause(); + detachListeners(); + } + + @Override public boolean dispatchKeyEvent(KeyEvent event) { // Do this on key down to handle a few of the system keys. boolean up = event.getAction() == KeyEvent.ACTION_UP; diff --git a/src/com/android/deskclock/SettingsActivity.java b/src/com/android/deskclock/SettingsActivity.java index 2b512e877..021f8bf4e 100644 --- a/src/com/android/deskclock/SettingsActivity.java +++ b/src/com/android/deskclock/SettingsActivity.java @@ -47,6 +47,10 @@ public class SettingsActivity extends PreferenceActivity "show_status_bar_icon"; static final String KEY_ALARM_SNOOZE = "snooze_duration"; + static final String KEY_FLIP_ACTION = + "flip_action"; + static final String KEY_SHAKE_ACTION = + "shake_action"; static final String KEY_VOLUME_BEHAVIOR = "volume_button_setting"; static final String KEY_AUTO_SILENCE = @@ -166,6 +170,14 @@ public class SettingsActivity extends PreferenceActivity final ListPreference listPref = (ListPreference) pref; final int idx = listPref.findIndexOfValue((String) newValue); listPref.setSummary(listPref.getEntries()[idx]); + } else if (KEY_FLIP_ACTION.equals(pref.getKey())) { + final ListPreference listPref = (ListPreference) pref; + String action = (String) newValue; + updateActionSummary(listPref, action, R.string.flip_action_summary); + } else if (KEY_SHAKE_ACTION.equals(pref.getKey())) { + final ListPreference listPref = (ListPreference) pref; + String action = (String) newValue; + updateActionSummary(listPref, action, R.string.shake_action_summary); } else if (KEY_SHOW_STATUS_BAR_ICON.equals(pref.getKey())) { // Check if any alarms are active. If yes and // we allow showing the alarm icon, the icon will be shown. @@ -184,6 +196,12 @@ public class SettingsActivity extends PreferenceActivity } } + private void updateActionSummary(ListPreference listPref, String action, int summaryResId) { + int i = Integer.parseInt(action); + listPref.setSummary(getString(summaryResId, + getResources().getStringArray(R.array.action_summary_entries)[i])); + } + private void refresh() { ListPreference listPref = (ListPreference) findPreference(KEY_AUTO_SILENCE); String delay = listPref.getValue(); @@ -206,6 +224,14 @@ public class SettingsActivity extends PreferenceActivity listPref.setSummary(listPref.getEntry()); listPref.setOnPreferenceChangeListener(this); + listPref = (ListPreference) findPreference(KEY_FLIP_ACTION); + updateActionSummary(listPref, listPref.getValue(), R.string.flip_action_summary); + listPref.setOnPreferenceChangeListener(this); + + listPref = (ListPreference) findPreference(KEY_SHAKE_ACTION); + updateActionSummary(listPref, listPref.getValue(), R.string.shake_action_summary); + listPref.setOnPreferenceChangeListener(this); + CheckBoxPreference hideStatusbarIcon = (CheckBoxPreference) findPreference(KEY_SHOW_STATUS_BAR_ICON); hideStatusbarIcon.setOnPreferenceChangeListener(this); |