Merge pull request #239 from 0nse/sleepAlarmWidget

Add widget to quickly set an alarm according to the user's preferred sleep length (in hours)
here
Andreas Shimokawa 2016-03-02 00:36:13 +01:00
commit 5eb525ee44
12 changed files with 220 additions and 19 deletions

View File

@ -24,7 +24,6 @@
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="false" />
<uses-feature
android:name="android.hardware.telephony"
android:required="false" />
@ -48,25 +47,26 @@
<activity
android:name=".activities.SettingsActivity"
android:label="@string/title_activity_settings"
android:parentActivityName=".activities.ControlCenter"/>
android:parentActivityName=".activities.ControlCenter" />
<activity
android:name=".devices.miband.MiBandPreferencesActivity"
android:label="@string/preferences_miband_settings"
android:parentActivityName=".activities.SettingsActivity"/>
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.AppManagerActivity"
android:label="@string/title_activity_appmanager"
android:parentActivityName=".activities.ControlCenter"/>
android:parentActivityName=".activities.ControlCenter" />
<activity
android:name=".activities.AppBlacklistActivity"
android:label="@string/title_activity_appblacklist"
android:parentActivityName=".activities.SettingsActivity"/>
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.FwAppInstallerActivity"
android:label="@string/title_activity_fw_app_insaller"
android:parentActivityName=".activities.ControlCenter">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
@ -87,7 +87,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\.pbw" />
<data android:pathPattern="/.*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\.pbw" />
@ -98,7 +97,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\.pbz" />
<data android:pathPattern="/.*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\.pbz" />
@ -109,7 +107,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\.pbl" />
<data android:pathPattern="/.*\\..*\\.pbl" />
<data android:pathPattern="/.*\\..*\\..*\\.pbl" />
@ -123,6 +120,7 @@
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<!-- no mimeType filter, needed for CM-derived ROMs? -->
@ -142,7 +140,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.fw" />
<data android:pathPattern="/.*\\.pbw" />
<data android:pathPattern="/.*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\.pbw" />
@ -153,7 +150,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbw" />
<data android:pathPattern="/.*\\.pbz" />
<data android:pathPattern="/.*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\.pbz" />
@ -164,7 +160,6 @@
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\..*\\.pbz" />
<data android:pathPattern="/.*\\.pbl" />
<data android:pathPattern="/.*\\..*\\.pbl" />
<data android:pathPattern="/.*\\..*\\..*\\.pbl" />
@ -180,10 +175,11 @@
<!-- to receive the firmwares from the donwload content provider -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
</activity>
<service
@ -222,11 +218,11 @@
android:name=".activities.DebugActivity"
android:label="@string/title_activity_debug"
android:parentActivityName=".activities.ControlCenter"
android:windowSoftInputMode="stateHidden"></activity>
android:windowSoftInputMode="stateHidden" />
<activity
android:name=".activities.DiscoveryActivity"
android:label="@string/title_activity_discovery"
android:parentActivityName=".activities.ControlCenter"></activity>
android:parentActivityName=".activities.ControlCenter" />
<activity
android:name=".activities.AndroidPairingActivity"
android:label="@string/title_activity_android_pairing" />
@ -236,16 +232,31 @@
<activity
android:name=".activities.charts.ChartsActivity"
android:label="@string/title_activity_charts"
android:parentActivityName=".activities.ControlCenter"/>
android:parentActivityName=".activities.ControlCenter" />
<activity
android:name=".activities.ConfigureAlarms"
android:label="@string/title_activity_set_alarm"
android:parentActivityName=".activities.SettingsActivity"/>
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".activities.AlarmDetails"
android:label="@string/title_activity_alarm_details"
android:parentActivityName=".activities.ConfigureAlarms"/>
<provider android:authorities="com.getpebble.android.provider" android:exported="true" android:name=".contentprovider.PebbleContentProvider" />
android:parentActivityName=".activities.ConfigureAlarms" />
<provider
android:name=".contentprovider.PebbleContentProvider"
android:authorities="com.getpebble.android.provider"
android:exported="true" />
<receiver android:name=".SleepAlarmWidget">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="nodomain.freeyourgadget.gadgetbridge.SLEEP_ALARM_WIDGET_CLICK" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/sleep_alarm_widget_info" />
</receiver>
</application>
</manifest>

View File

@ -0,0 +1,115 @@
package nodomain.freeyourgadget.gadgetbridge;
import android.annotation.TargetApi;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.widget.RemoteViews;
import android.widget.Toast;
import java.util.Calendar;
import java.util.GregorianCalendar;
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
import nodomain.freeyourgadget.gadgetbridge.impl.GBAlarm;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
/**
* Implementation of SleepAlarmWidget functionality. When pressing the widget, an alarm will be set
* to trigger after a predefined number of hours. A toast will confirm the user about this. The
* value is retrieved using ActivityUser.().getActivityUserSleepDuration().
*/
public class SleepAlarmWidget extends AppWidgetProvider {
/**
* This is our dedicated action to detect when the widget has been clicked.
*/
public static final String ACTION =
"nodomain.freeyourgadget.gadgetbridge.SLEEP_ALARM_WIDGET_CLICK";
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.sleep_alarm_widget);
// Add our own click intent
Intent intent = new Intent(ACTION);
PendingIntent clickPI = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.sleepalarmwidget_text, clickPI);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (ACTION.equals(intent.getAction())) {
int userSleepDuration = new ActivityUser().getActivityUserSleepDuration();
// current timestamp
GregorianCalendar calendar = new GregorianCalendar();
// add preferred sleep duration
calendar.add(Calendar.HOUR_OF_DAY, userSleepDuration);
int hours = calendar.get(calendar.HOUR_OF_DAY);
int minutes = calendar.get(calendar.MINUTE);
// overwrite the first alarm and activate it
GBAlarm alarm = new GBAlarm(0, true, true, Alarm.ALARM_ONCE, hours, minutes);
alarm.store();
if (GBApplication.isRunningLollipopOrLater()) {
setAlarmViaAlarmManager(context, calendar.getTimeInMillis());
}
GB.toast(context,
String.format(context.getString(R.string.appwidget_alarms_set), hours, minutes),
Toast.LENGTH_SHORT, GB.INFO);
}
}
/**
* Use the Android alarm manager to create the alarm icon in the status bar.
*
* @param packageContext {@code Context}: A Context of the application package implementing this
* class.
* @param triggerTime {@code long}: time at which the underlying alarm is triggered in wall time
* milliseconds since the epoch
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private void setAlarmViaAlarmManager(Context packageContext, long triggerTime) {
AlarmManager am = (AlarmManager) packageContext.getSystemService(Context.ALARM_SERVICE);
// TODO: launch the alarm configuration activity when clicking the alarm in the status bar
Intent intent = new Intent(packageContext, ConfigureAlarms.class);
PendingIntent pi = PendingIntent.getBroadcast(packageContext, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
am.setAlarmClock(new AlarmManager.AlarmClockInfo(triggerTime, pi), pi);
}
}

View File

@ -15,6 +15,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActi
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_GENDER;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_HEIGHT_CM;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_SLEEP_DURATION;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_WEIGHT_KG;
import static nodomain.freeyourgadget.gadgetbridge.model.ActivityUser.PREF_USER_YEAR_OF_BIRTH;
@ -137,6 +138,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
PREF_USER_GENDER,
PREF_USER_HEIGHT_CM,
PREF_USER_WEIGHT_KG,
PREF_USER_SLEEP_DURATION,
};
}

View File

@ -16,17 +16,20 @@ public class ActivityUser {
private Integer activityUserYearOfBirth;
private Integer activityUserHeightCm;
private Integer activityUserWeightKg;
private Integer activityUserSleepDuration;
public static final int defaultUserGender = 0;
public static final int defaultUserYearOfBirth = 0;
public static final int defaultUserAge = 0;
public static final int defaultUserHeightCm = 175;
public static final int defaultUserWeightKg = 70;
public static final int defaultUserSleepDuration = 7;
public static final String PREF_USER_YEAR_OF_BIRTH = "activity_user_year_of_birth";
public static final String PREF_USER_GENDER = "activity_user_gender";
public static final String PREF_USER_HEIGHT_CM = "activity_user_height_cm";
public static final String PREF_USER_WEIGHT_KG = "activity_user_weight_kg";
public static final String PREF_USER_SLEEP_DURATION = "activity_user_sleep_duration";
public int getActivityUserWeightKg() {
if (activityUserWeightKg == null) {
@ -56,6 +59,20 @@ public class ActivityUser {
return activityUserHeightCm;
}
/**
* @return the user defined sleep duration or the default value when none is set or the stored
* value is out of any logical bounds.
*/
public int getActivityUserSleepDuration() {
if(activityUserSleepDuration == null) {
fetchPreferences();
}
if (activityUserSleepDuration < 1 || activityUserSleepDuration > 24) {
activityUserSleepDuration = defaultUserSleepDuration;
}
return activityUserSleepDuration;
}
public int getActivityUserAge() {
int userYear = getActivityUserYearOfBirth();
int age = 25;
@ -74,5 +91,6 @@ public class ActivityUser {
activityUserHeightCm = Integer.parseInt(prefs.getString(PREF_USER_HEIGHT_CM, Integer.toString(defaultUserHeightCm)));
activityUserWeightKg = Integer.parseInt(prefs.getString(PREF_USER_WEIGHT_KG, Integer.toString(defaultUserWeightKg)));
activityUserYearOfBirth = Integer.parseInt(prefs.getString(PREF_USER_YEAR_OF_BIRTH, Integer.toString(defaultUserYearOfBirth)));
activityUserSleepDuration = Integer.parseInt(prefs.getString(PREF_USER_SLEEP_DURATION, Integer.toString(defaultUserSleepDuration)));
}
}

View File

@ -0,0 +1,18 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/primary_light"
android:padding="@dimen/widget_margin">
<TextView
android:id="@+id/sleepalarmwidget_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/appwidget_text"
android:text="@string/appwidget_text"
android:textColor="#ffffff"
android:textSize="24sp"
android:gravity="center_vertical|center_horizontal"
android:textStyle="bold|italic" />
</RelativeLayout>

View File

@ -200,4 +200,6 @@
<string name="fwinstaller_firmware_not_compatible_to_device">Diese Firmware ist nicht mit dem Gerät kompatibel</string>
<string name="waiting_for_reconnect">warte auf eingehende Verbindung</string>
<string name="appmananger_app_reinstall">Erneut installieren</string>
<string name="add_widget">Widget hinzufügen</string>
<string name="activity_prefs_sleep_duration">Bevorzugte Schlafdauer in Stunden</string>
</resources>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">0dp</dimen>
</resources>

View File

@ -2,4 +2,10 @@
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">8dp</dimen>
</resources>

View File

@ -225,4 +225,9 @@
<string name="authenticating">authenticating</string>
<string name="authentication_required">authentication required</string>
<string name="appwidget_text">Zzz</string>
<string name="add_widget">Add widget</string>
<string name="activity_prefs_sleep_duration">Preferred sleep duration in hours</string>
<string name="appwidget_alarms_set">An alarm was set for %1$02d:%2$02d</string>
</resources>

View File

@ -153,6 +153,12 @@
android:key="activity_user_weight_kg"
android:maxLength="3"
android:title="@string/activity_prefs_weight_kg" />
<EditTextPreference
android:inputType="number"
android:key="activity_user_sleep_duration"
android:maxLength="2"
android:title="@string/activity_prefs_sleep_duration" />
</PreferenceScreen>
<PreferenceCategory

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/sleep_alarm_widget"
android:initialLayout="@layout/sleep_alarm_widget"
android:minHeight="40dp"
android:minWidth="40dp"
android:previewImage="@drawable/ic_launcher"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>

View File

@ -10,7 +10,6 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.ServiceCommand;