mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-09 19:49:30 +01:00
Merge pull request #239 from 0nse/sleepAlarmWidget
Add widget to quickly set an alarm according to the user's preferred sleep length (in hours)
This commit is contained in:
commit
5eb525ee44
@ -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>
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
18
app/src/main/res/layout/sleep_alarm_widget.xml
Normal file
18
app/src/main/res/layout/sleep_alarm_widget.xml
Normal 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>
|
@ -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>
|
||||
|
10
app/src/main/res/values-v14/dimens.xml
Normal file
10
app/src/main/res/values-v14/dimens.xml
Normal 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>
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
9
app/src/main/res/xml/sleep_alarm_widget_info.xml
Normal file
9
app/src/main/res/xml/sleep_alarm_widget_info.xml
Normal 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>
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user