diff options
author | Wilhelm Fitzpatrick <rafial@cyngn.com> | 2015-12-23 15:58:25 -0800 |
---|---|---|
committer | Gerrit Code Review <gerrit@cyanogenmod.org> | 2016-01-02 02:05:45 -0800 |
commit | 91ac9cbe7c721b8d261f798ba9a78a1e5a458cdd (patch) | |
tree | e4943bba99b6c7ad3069987314ad433c872ca03b | |
parent | 811f84370c21cc3dfeb6785a86b8cd6c3581aaa3 (diff) | |
download | android_packages_apps_DeskClock-91ac9cbe7c721b8d261f798ba9a78a1e5a458cdd.tar.gz android_packages_apps_DeskClock-91ac9cbe7c721b8d261f798ba9a78a1e5a458cdd.tar.bz2 android_packages_apps_DeskClock-91ac9cbe7c721b8d261f798ba9a78a1e5a458cdd.zip |
DeskClock: Add back flip and shake actions
Allow the alarm to be dismissed/snoozed by flipping or shaking
Picked from:
http://review.cyanogenmod.org/#/c/29894
http://review.cyanogenmod.org/#/c/80342
http://review.cyanogenmod.org/#/c/81204
http://review.cyanogenmod.org/#/c/94950
Authors/Contributors:
Artem Chep <artemchep@gmail.com>
Danny Baumann <dannybaumann@web.de>
Ronald Ramsay II <ronaldramsayii@gmail.com>
Danesh M <daneshm90@gmail.com>
Michael Bestas <mikeioannina@gmail.com>
Martin Brabham <mbrabham@cyngn.com>
Change-Id: I222b6cd53a95db6f8662e7aef52aa6922d8a5d6a
-rw-r--r-- | res/values/cm_arrays.xml | 25 | ||||
-rw-r--r-- | res/values/cm_strings.xml | 22 | ||||
-rw-r--r-- | res/xml/settings.xml | 27 | ||||
-rw-r--r-- | src/com/android/deskclock/SettingsActivity.java | 61 | ||||
-rwxr-xr-x | src/com/android/deskclock/alarms/AlarmService.java | 174 |
5 files changed, 298 insertions, 11 deletions
diff --git a/res/values/cm_arrays.xml b/res/values/cm_arrays.xml new file mode 100644 index 000000000..e0e92a42f --- /dev/null +++ b/res/values/cm_arrays.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (C) 2012-2015 The CyanogenMod Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<resources> + <!-- 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" translatable="false"> + <item>@string/action_summary_snooze</item> + <item>@string/action_summary_dismiss</item> + <item>@string/action_summary_do_nothing</item> + </string-array> +</resources> diff --git a/res/values/cm_strings.xml b/res/values/cm_strings.xml index aa597101c..a8eaeccba 100644 --- a/res/values/cm_strings.xml +++ b/res/values/cm_strings.xml @@ -15,6 +15,28 @@ limitations under the License. --> <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- Settings summary for the volume buttons setting. --> + <string name="volume_buttons_summary">Pressing the volume buttons will <xliff:g id="action">%s</xliff:g></string> + + <!-- Setting title for the flip action setting. --> + <string name="flip_action_title">Flip action</string> + + <!-- Setting summary for the flip action setting. --> + <string name="flip_action_summary" product="tablet">Flipping the tablet down will <xliff:g id="action">%s</xliff:g></string> + <string name="flip_action_summary" product="default">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> + + <!-- Setting summary for the shake action setting. --> + <string name="shake_action_summary" product="tablet">Shaking the tablet will <xliff:g id="action">%s</xliff:g></string> + <string name="shake_action_summary" product="default">Shaking the phone will <xliff:g id="action">%s</xliff:g></string> + + <!-- Summary texts for shake and flip actions --> + <string name="action_summary_snooze">snooze the alarm</string> + <string name="action_summary_dismiss">dismiss the alarm</string> + <string name="action_summary_do_nothing">do nothing</string> + <!-- Setting title for accessing the cLock widget settings --> <string name="menu_item_widget_settings">Widget settings</string> <string name="activity_not_found">Activity not found!</string> diff --git a/res/xml/settings.xml b/res/xml/settings.xml index 77a355a4d..052d4ba77 100644 --- a/res/xml/settings.xml +++ b/res/xml/settings.xml @@ -38,6 +38,7 @@ </PreferenceCategory> <PreferenceCategory + android:key="key_alarm_settings" android:title="@string/alarm_settings"> <ListPreference android:key="auto_silence" @@ -57,6 +58,13 @@ android:title="@string/alarm_volume_title" /> <ListPreference + android:key="week_start" + android:title="@string/week_start_title" + android:dialogTitle="@string/week_start_title" + android:entries="@array/week_start_entries" + android:entryValues="@array/week_start_values" /> + + <ListPreference android:key="volume_button_setting" android:title="@string/volume_button_setting_title" android:dialogTitle="@string/volume_button_setting_title" @@ -65,11 +73,20 @@ android:defaultValue="0" /> <ListPreference - android:key="week_start" - android:title="@string/week_start_title" - android:dialogTitle="@string/week_start_title" - android:entries="@array/week_start_entries" - android:entryValues="@array/week_start_values" /> + android:key="flip_action" + android:title="@string/flip_action_title" + android:dialogTitle="@string/flip_action_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_title" + android:entries="@array/volume_button_setting_entries" + android:entryValues="@array/volume_button_setting_values" + android:defaultValue="0" /> <SwitchPreference android:key="show_status_bar_icon" diff --git a/src/com/android/deskclock/SettingsActivity.java b/src/com/android/deskclock/SettingsActivity.java index 3a4a36175..e376a0f2f 100644 --- a/src/com/android/deskclock/SettingsActivity.java +++ b/src/com/android/deskclock/SettingsActivity.java @@ -21,10 +21,13 @@ import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.res.Resources; +import android.hardware.Sensor; +import android.hardware.SensorManager; import android.media.AudioManager; import android.os.Bundle; import android.preference.ListPreference; import android.preference.Preference; +import android.preference.PreferenceCategory; import android.preference.PreferenceFragment; import android.preference.SwitchPreference; import android.text.format.DateUtils; @@ -48,6 +51,8 @@ public class SettingsActivity extends BaseActivity { public static final String KEY_ALARM_SNOOZE = "snooze_duration"; public static final String KEY_ALARM_VOLUME = "volume_setting"; public static final String KEY_VOLUME_BEHAVIOR = "volume_button_setting"; + public static final String KEY_FLIP_ACTION = "flip_action"; + public static final String KEY_SHAKE_ACTION = "shake_action"; public static final String KEY_AUTO_SILENCE = "auto_silence"; public static final String KEY_CLOCK_STYLE = "clock_style"; public static final String KEY_HOME_TZ = "home_time_zone"; @@ -55,6 +60,7 @@ public class SettingsActivity extends BaseActivity { public static final String KEY_VOLUME_BUTTONS = "volume_button_setting"; public static final String KEY_WEEK_START = "week_start"; public static final String KEY_SHOW_ALARM_ICON = "show_status_bar_icon"; + public static final String KEY_ALARM_SETTINGS = "key_alarm_settings"; public static final String DEFAULT_VOLUME_BEHAVIOR = "0"; public static final String VOLUME_BEHAVIOR_SNOOZE = "1"; @@ -148,9 +154,14 @@ public class SettingsActivity extends BaseActivity { homeTimeZonePref.setEnabled(!autoHomeClockEnabled); notifyHomeTimeZoneChanged(); } else if (KEY_VOLUME_BUTTONS.equals(pref.getKey())) { - final ListPreference volumeButtonsPref = (ListPreference) pref; - final int index = volumeButtonsPref.findIndexOfValue((String) newValue); - volumeButtonsPref.setSummary(volumeButtonsPref.getEntries()[index]); + final ListPreference listPref = (ListPreference) pref; + updateActionSummary(listPref, (String) newValue, R.string.volume_buttons_summary); + } else if (KEY_FLIP_ACTION.equals(pref.getKey())) { + final ListPreference listPref = (ListPreference) pref; + updateActionSummary(listPref, (String) newValue, R.string.flip_action_summary); + } else if (KEY_SHAKE_ACTION.equals(pref.getKey())) { + final ListPreference listPref = (ListPreference) pref; + updateActionSummary(listPref, (String) newValue, R.string.shake_action_summary); } else if (KEY_WEEK_START.equals(pref.getKey())) { final ListPreference weekStartPref = (ListPreference) findPreference(KEY_WEEK_START); final int idx = weekStartPref.findIndexOfValue((String) newValue); @@ -234,11 +245,43 @@ public class SettingsActivity extends BaseActivity { homeTimezonePref.setSummary(homeTimezonePref.getEntry()); homeTimezonePref.setOnPreferenceChangeListener(this); - final ListPreference volumeButtonsPref = - (ListPreference) findPreference(KEY_VOLUME_BUTTONS); - volumeButtonsPref.setSummary(volumeButtonsPref.getEntry()); + final ListPreference volumeButtonsPref = (ListPreference) findPreference(KEY_VOLUME_BUTTONS); + updateActionSummary(volumeButtonsPref, volumeButtonsPref.getValue(), R.string.volume_buttons_summary); volumeButtonsPref.setOnPreferenceChangeListener(this); + SensorManager sensorManager = (SensorManager) + getActivity().getSystemService(Context.SENSOR_SERVICE); + + final ListPreference flipActionPref = (ListPreference) findPreference(KEY_FLIP_ACTION); + if (flipActionPref != null) { + List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ORIENTATION); + if (sensorList.size() < 1) { // This will be true if no orientation sensor + flipActionPref.setValue("0"); // Turn it off + PreferenceCategory category = (PreferenceCategory) findPreference(KEY_ALARM_SETTINGS); + if (category != null) { + category.removePreference(flipActionPref); + } + } else { + updateActionSummary(flipActionPref, flipActionPref.getValue(), R.string.flip_action_summary); + flipActionPref.setOnPreferenceChangeListener(this); + } + } + + final ListPreference shakeActionPref = (ListPreference) findPreference(KEY_SHAKE_ACTION); + if (shakeActionPref != null) { + List<Sensor> sensorList = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER); + if (sensorList.size() < 1) { // This will be true if no accelerometer sensor + shakeActionPref.setValue("0"); // Turn it off + PreferenceCategory category = (PreferenceCategory) findPreference(KEY_ALARM_SETTINGS); + if (category != null) { + category.removePreference(shakeActionPref); + } + } else { + updateActionSummary(shakeActionPref, shakeActionPref.getValue(), R.string.shake_action_summary); + shakeActionPref.setOnPreferenceChangeListener(this); + } + } + final Preference volumePref = findPreference(KEY_ALARM_VOLUME); volumePref.setOnPreferenceClickListener(this); @@ -275,6 +318,12 @@ public class SettingsActivity extends BaseActivity { getActivity().sendBroadcast(i); } + private void updateActionSummary(ListPreference listPref, String action, int summaryResId) { + int i = listPref.findIndexOfValue(action); + listPref.setSummary(getString(summaryResId, + getResources().getStringArray(R.array.action_summary_entries)[i])); + } + private class TimeZoneRow implements Comparable<TimeZoneRow> { private static final boolean SHOW_DAYLIGHT_SAVINGS_INDICATOR = false; diff --git a/src/com/android/deskclock/alarms/AlarmService.java b/src/com/android/deskclock/alarms/AlarmService.java index 50a1d8113..d972b450d 100755 --- a/src/com/android/deskclock/alarms/AlarmService.java +++ b/src/com/android/deskclock/alarms/AlarmService.java @@ -15,6 +15,7 @@ */ package com.android.deskclock.alarms; +import android.app.PendingIntent; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -23,11 +24,18 @@ import android.content.Intent; import android.content.IntentFilter; import android.os.Binder; import android.os.IBinder; +import android.content.SharedPreferences; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.preference.PreferenceManager; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import com.android.deskclock.AlarmAlertWakeLock; import com.android.deskclock.LogUtils; +import com.android.deskclock.SettingsActivity; import com.android.deskclock.R; import com.android.deskclock.events.Events; import com.android.deskclock.provider.AlarmInstance; @@ -68,6 +76,14 @@ public class AlarmService extends Service { /** Private action used to stop an alarm with this service. */ public static final String STOP_ALARM_ACTION = "STOP_ALARM"; + // 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; + + // default action for flip and shake + private static final String DEFAULT_ACTION = Integer.toString(ALARM_NO_ACTION); + /** Binder given to AlarmActivity */ private final IBinder mBinder = new Binder(); @@ -123,6 +139,9 @@ public class AlarmService extends Service { private TelephonyManager mTelephonyManager; private int mInitialCallState; private AlarmInstance mCurrentAlarm = null; + private SensorManager mSensorManager; + private int mFlipAction; + private int mShakeAction; private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { @Override @@ -192,6 +211,7 @@ public class AlarmService extends Service { AlarmKlaxon.start(this, mCurrentAlarm); changeToProfile(this, mCurrentAlarm); sendBroadcast(new Intent(ALARM_ALERT_ACTION)); + attachListeners(); } private void stopCurrentAlarm() { @@ -206,6 +226,7 @@ public class AlarmService extends Service { sendBroadcast(new Intent(ALARM_DONE_ACTION)); mCurrentAlarm = null; + detachListeners(); AlarmAlertWakeLock.releaseCpuLock(); } @@ -251,6 +272,14 @@ public class AlarmService extends Service { filter.addAction(ALARM_DISMISS_ACTION); registerReceiver(mActionsReceiver, filter); mIsRegistered = true; + + // set up for flip and shake actions + mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + mFlipAction = Integer.parseInt(prefs.getString( + SettingsActivity.KEY_FLIP_ACTION, DEFAULT_ACTION)); + mShakeAction = Integer.parseInt(prefs.getString( + SettingsActivity.KEY_SHAKE_ACTION, DEFAULT_ACTION)); } @Override @@ -303,4 +332,149 @@ public class AlarmService extends Service { mIsRegistered = false; } } + + 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; + } + } + }; + + private void attachListeners() { + if (mFlipAction != ALARM_NO_ACTION) { + mSensorManager.registerListener(mFlipListener, + mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION), + SensorManager.SENSOR_DELAY_NORMAL, + 300 * 1000); //batch every 300 milliseconds + } + + if (mShakeAction != ALARM_NO_ACTION) { + mSensorManager.registerListener(mShakeListener, + mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), + SensorManager.SENSOR_DELAY_GAME, + 50 * 1000); //batch every 50 milliseconds + } + } + + private void detachListeners() { + if (mFlipAction != ALARM_NO_ACTION) { + mSensorManager.unregisterListener(mFlipListener); + } + if (mShakeAction != ALARM_NO_ACTION) { + mSensorManager.unregisterListener(mShakeListener); + } + } + + private void handleAction(int action) { + switch (action) { + case ALARM_SNOOZE: + // Setup Snooze Action + Intent snoozeIntent = AlarmStateManager.createStateChangeIntent(this, "SNOOZE_TAG", + mCurrentAlarm, AlarmInstance.SNOOZE_STATE); + sendBroadcast(snoozeIntent); + break; + case ALARM_DISMISS: + // Setup Dismiss Action + Intent dismissIntent = AlarmStateManager.createStateChangeIntent(this, "DISMISS_TAG", + mCurrentAlarm, AlarmInstance.DISMISSED_STATE); + sendBroadcast(dismissIntent); + break; + case ALARM_NO_ACTION: + default: + break; + } + } + } |