Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 91ac9cbe authored by Wilhelm Fitzpatrick's avatar Wilhelm Fitzpatrick Committed by Gerrit Code Review
Browse files

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
parent 811f8437
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
<?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>
+22 −0
Original line number Diff line number Diff line
@@ -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>
+22 −5
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@
    </PreferenceCategory>

    <PreferenceCategory
        android:key="key_alarm_settings"
        android:title="@string/alarm_settings">
        <ListPreference
            android:key="auto_silence"
@@ -56,6 +57,13 @@
            android:key="volume_setting"
            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"
@@ -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"
+55 −6
Original line number Diff line number Diff line
@@ -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;

+174 −0
Original line number Diff line number Diff line
@@ -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;
        }
    }

}