Widget and SleepAlarmWidget: modify for multidevice support

This commit is contained in:
vanous 2022-05-28 14:57:01 +02:00
parent 93e05e8dd6
commit 4db2877a91
8 changed files with 229 additions and 76 deletions

View File

@ -590,6 +590,12 @@
</intent-filter>
</activity>
<activity android:name=".activities.SleepAlarmWidgetConfigurationActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name=".activities.ExternalPebbleJSActivity"
android:allowTaskReparenting="true"

View File

@ -24,6 +24,7 @@ import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.widget.RemoteViews;
import android.widget.Toast;
@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.WidgetPreferenceStorage;
/**
* Implementation of SleepAlarmWidget functionality. When pressing the widget, an alarm will be set
@ -44,11 +46,10 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
* value is retrieved using ActivityUser.().getSleepDuration().
*/
public class SleepAlarmWidget extends AppWidgetProvider {
/**
* This is our dedicated action to detect when the widget has been clicked.
*/
public static final String ACTION =
public static final String ACTION_CLICK =
"nodomain.freeyourgadget.gadgetbridge.SLEEP_ALARM_WIDGET_CLICK";
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
@ -59,9 +60,10 @@ public class SleepAlarmWidget extends AppWidgetProvider {
// Add our own click intent
Intent intent = new Intent(context, SleepAlarmWidget.class);
intent.setAction(ACTION);
intent.setAction(ACTION_CLICK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent clickPI = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
context, appWidgetId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.sleepalarmwidget_text, clickPI);
// Instruct the widget manager to update the widget
@ -89,7 +91,15 @@ public class SleepAlarmWidget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (ACTION.equals(intent.getAction())) {
Bundle extras = intent.getExtras();
int appWidgetId = -1;
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
if (ACTION_CLICK.equals(intent.getAction())) {
int userSleepDuration = new ActivityUser().getSleepDurationGoal();
// current timestamp
GregorianCalendar calendar = new GregorianCalendar();
@ -102,16 +112,11 @@ public class SleepAlarmWidget extends AppWidgetProvider {
// overwrite the first alarm and activate it, without
Context appContext = context.getApplicationContext();
if (appContext instanceof GBApplication) {
GBApplication gbApp = (GBApplication) appContext;
GBDevice selectedDevice = gbApp.getDeviceManager().getSelectedDevice();
if (selectedDevice == null || !selectedDevice.isInitialized()) {
GB.toast(context,
context.getString(R.string.appwidget_not_connected),
Toast.LENGTH_LONG, GB.WARN);
return;
}
GBDevice deviceForWidget = new WidgetPreferenceStorage().getDeviceForWidget(appWidgetId);
if (deviceForWidget == null || !deviceForWidget.isInitialized()) {
GB.toast(context, context.getString(R.string.appwidget_not_connected),
Toast.LENGTH_SHORT, GB.WARN);
return;
}
int hours = calendar.get(Calendar.HOUR_OF_DAY);

View File

@ -54,11 +54,9 @@ import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2;
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.WidgetAlarmsActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -77,30 +75,9 @@ public class Widget extends AppWidgetProvider {
private static final Logger LOG = LoggerFactory.getLogger(Widget.class);
static BroadcastReceiver broadcastReceiver = null;
GBDevice selectedDevice;
private GBDevice getSelectedDevice() {
Context context = GBApplication.getContext();
if (!(context instanceof GBApplication)) {
return null;
}
GBApplication gbApp = (GBApplication) context;
return gbApp.getDeviceManager().getSelectedDevice();
}
private GBDevice getDeviceByMAC(Context appContext, String HwAddress) {
GBApplication gbApp = (GBApplication) appContext;
List<? extends GBDevice> devices = gbApp.getDeviceManager().getDevices();
for (GBDevice device : devices) {
if (device.getAddress().equals(HwAddress)) {
return device;
}
}
return null;
}
private long[] getSteps() {
private long[] getSteps(GBDevice gbDevice) {
Context context = GBApplication.getContext();
Calendar day = GregorianCalendar.getInstance();
@ -108,7 +85,7 @@ public class Widget extends AppWidgetProvider {
return new long[]{0, 0, 0};
}
DailyTotals ds = new DailyTotals();
return ds.getDailyTotalsForDevice(selectedDevice, day);
return ds.getDailyTotalsForDevice(gbDevice, day);
//return ds.getDailyTotalsForAllDevices(day);
}
@ -119,11 +96,10 @@ public class Widget extends AppWidgetProvider {
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
selectedDevice = getSelectedDevice();
WidgetPreferenceStorage widgetPreferenceStorage = new WidgetPreferenceStorage();
String savedDeviceAddress = widgetPreferenceStorage.getSavedDeviceAddress(context, appWidgetId);
if (savedDeviceAddress != null) {
selectedDevice = getDeviceByMAC(context.getApplicationContext(), savedDeviceAddress); //this would probably only happen if device no longer exists in GB
GBDevice deviceForWidget = new WidgetPreferenceStorage().getDeviceForWidget(appWidgetId);
if (deviceForWidget == null) {
LOG.debug("Widget: no device, bailing out");
return;
}
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
@ -143,17 +119,17 @@ public class Widget extends AppWidgetProvider {
//alarms popup menu
Intent startAlarmListIntent = new Intent(context, WidgetAlarmsActivity.class);
startAlarmListIntent.putExtra(GBDevice.EXTRA_DEVICE, selectedDevice);
startAlarmListIntent.putExtra(GBDevice.EXTRA_DEVICE, deviceForWidget);
PendingIntent startAlarmListPIntent = PendingIntent.getActivity(context, appWidgetId, startAlarmListIntent, PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.todaywidget_header_alarm_icon, startAlarmListPIntent);
//charts
Intent startChartsIntent = new Intent(context, ChartsActivity.class);
startChartsIntent.putExtra(GBDevice.EXTRA_DEVICE, selectedDevice);
startChartsIntent.putExtra(GBDevice.EXTRA_DEVICE, deviceForWidget);
PendingIntent startChartsPIntent = PendingIntent.getActivity(context, appWidgetId, startChartsIntent, PendingIntent.FLAG_CANCEL_CURRENT);
views.setOnClickPendingIntent(R.id.todaywidget_bottom_layout, startChartsPIntent);
long[] dailyTotals = getSteps();
long[] dailyTotals = getSteps(deviceForWidget);
int steps = (int) dailyTotals[0];
int sleep = (int) dailyTotals[1];
ActivityUser activityUser = new ActivityUser();
@ -172,17 +148,17 @@ public class Widget extends AppWidgetProvider {
views.setProgressBar(R.id.todaywidget_sleep_progress, sleepGoalMinutes, sleep, false);
views.setProgressBar(R.id.todaywidget_distance_progress, distanceGoal, steps * stepLength, false);
views.setViewVisibility(R.id.todaywidget_battery_icon, View.GONE);
if (selectedDevice != null) {
String status = String.format("%1s", selectedDevice.getStateString());
if (selectedDevice.isConnected()) {
if (selectedDevice.getBatteryLevel() > 1) {
if (deviceForWidget != null) {
String status = String.format("%1s", deviceForWidget.getStateString());
if (deviceForWidget.isConnected()) {
if (deviceForWidget.getBatteryLevel() > 1) {
views.setViewVisibility(R.id.todaywidget_battery_icon, View.VISIBLE);
status = String.format("%1s%%", selectedDevice.getBatteryLevel());
status = String.format("%1s%%", deviceForWidget.getBatteryLevel());
}
}
String deviceName = selectedDevice.getAlias() != null ? selectedDevice.getAlias() : selectedDevice.getName();
String deviceName = deviceForWidget.getAlias() != null ? deviceForWidget.getAlias() : deviceForWidget.getName();
views.setTextViewText(R.id.todaywidget_device_status, status);
views.setTextViewText(R.id.todaywidget_device_name, deviceName);
}
@ -191,11 +167,11 @@ public class Widget extends AppWidgetProvider {
appWidgetManager.updateAppWidget(appWidgetId, views);
}
public void refreshData() {
public void refreshData(int appWidgetId) {
Context context = GBApplication.getContext();
GBDevice device = getSelectedDevice();
GBDevice deviceForWidget = new WidgetPreferenceStorage().getDeviceForWidget(appWidgetId);
if (device == null || !device.isInitialized()) {
if (deviceForWidget == null || !deviceForWidget.isInitialized()) {
GB.toast(context,
context.getString(R.string.device_not_connected),
Toast.LENGTH_SHORT, GB.ERROR);
@ -265,7 +241,7 @@ public class Widget extends AppWidgetProvider {
super.onReceive(context, intent);
LOG.debug("gbwidget LOCAL onReceive, action: " + intent.getAction() + intent);
Bundle extras = intent.getExtras();
int appWidgetId = -1;
int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
@ -277,7 +253,7 @@ public class Widget extends AppWidgetProvider {
if (broadcastReceiver == null) {
onEnabled(context);
}
refreshData();
refreshData(appWidgetId);
//updateWidget();
} else if (APPWIDGET_DELETED.equals(intent.getAction())) {
onDisabled(context);

View File

@ -0,0 +1,139 @@
package nodomain.freeyourgadget.gadgetbridge.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.appwidget.AppWidgetManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Pair;
import android.widget.ListView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.WidgetPreferenceStorage;
public class SleepAlarmWidgetConfigurationActivity extends Activity {
// modified copy of WidgetConfigurationActivity
// if we knew which widget is calling this config activity, we could only use a single configuration
// activity and customize the filter in getAllDevices based on the caller.
private static final Logger LOG = LoggerFactory.getLogger(SleepAlarmWidgetConfigurationActivity.class);
int mAppWidgetId;
LinkedHashMap<String, Pair<String, Integer>> allDevices;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(RESULT_CANCELED);
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
// make the result intent and set the result to canceled
Intent resultValue;
resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_CANCELED, resultValue);
if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
finish();
}
AlertDialog.Builder builder = new AlertDialog.Builder(SleepAlarmWidgetConfigurationActivity.this);
builder.setTitle(R.string.widget_settings_select_device_title);
allDevices = getAllDevices(getApplicationContext());
List<String> list = new ArrayList<>();
for (Map.Entry<String, Pair<String, Integer>> item : allDevices.entrySet()) {
list.add(item.getKey());
}
String[] allDevicesString = list.toArray(new String[0]);
builder.setSingleChoiceItems(allDevicesString, 0, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ListView lw = ((AlertDialog) dialog).getListView();
int selectedItemPosition = lw.getCheckedItemPosition();
if (selectedItemPosition > -1) {
Map.Entry<String, Pair<String, Integer>> selectedItem =
(Map.Entry<String, Pair<String, Integer>>) allDevices.entrySet().toArray()[selectedItemPosition];
WidgetPreferenceStorage widgetPreferenceStorage = new WidgetPreferenceStorage();
widgetPreferenceStorage.saveWidgetPrefs(getApplicationContext(), String.valueOf(mAppWidgetId), selectedItem.getValue().first);
}
Intent resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_OK, resultValue);
finish();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent resultValue;
resultValue = new Intent();
resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
setResult(RESULT_CANCELED, resultValue);
finish();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
public LinkedHashMap getAllDevices(Context appContext) {
DaoSession daoSession;
GBApplication gbApp = (GBApplication) appContext;
LinkedHashMap<String, Pair<String, Integer>> newMap = new LinkedHashMap<>(1);
List<? extends GBDevice> devices = gbApp.getDeviceManager().getDevices();
try (DBHandler handler = GBApplication.acquireDB()) {
daoSession = handler.getDaoSession();
for (GBDevice device : devices) {
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(device);
Device dbDevice = DBHelper.findDevice(device, daoSession);
int icon = device.isInitialized() ? device.getType().getIcon() : device.getType().getDisabledIcon();
if (dbDevice != null && coordinator != null
&& (coordinator.getAlarmSlotCount() > 0)
&& !newMap.containsKey(device.getAliasOrName())) {
newMap.put(device.getAliasOrName(), new Pair(device.getAddress(), icon));
}
}
} catch (Exception e) {
LOG.error("Error getting list of all devices: " + e);
}
return newMap;
}
}

View File

@ -40,17 +40,17 @@ import nodomain.freeyourgadget.gadgetbridge.util.GB;
public class WidgetAlarmsActivity extends Activity implements View.OnClickListener {
TextView textView;
GBDevice deviceForWidget;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context appContext = this.getApplicationContext();
GBDevice selectedDevice;
Bundle extras = getIntent().getExtras();
if (extras != null) {
selectedDevice = extras.getParcelable(GBDevice.EXTRA_DEVICE);
deviceForWidget = extras.getParcelable(GBDevice.EXTRA_DEVICE);
} else {
GB.toast(this,
"Error no device",
@ -59,9 +59,8 @@ public class WidgetAlarmsActivity extends Activity implements View.OnClickListen
}
if (appContext instanceof GBApplication) {
GBApplication gbApp = (GBApplication) appContext;
if (selectedDevice == null || !selectedDevice.isInitialized()) {
if (deviceForWidget == null || !deviceForWidget.isInitialized()) {
GB.toast(this,
this.getString(R.string.not_connected),
Toast.LENGTH_LONG, GB.INFO);
@ -128,16 +127,11 @@ public class WidgetAlarmsActivity extends Activity implements View.OnClickListen
// overwrite the first alarm and activate it, without
Context appContext = this.getApplicationContext();
if (appContext instanceof GBApplication) {
GBApplication gbApp = (GBApplication) appContext;
GBDevice selectedDevice = gbApp.getDeviceManager().getSelectedDevice();
if (selectedDevice == null || !selectedDevice.isInitialized()) {
GB.toast(this,
this.getString(R.string.appwidget_not_connected),
Toast.LENGTH_LONG, GB.WARN);
return;
}
if (deviceForWidget == null || !deviceForWidget.isInitialized()) {
GB.toast(this,
this.getString(R.string.appwidget_not_connected),
Toast.LENGTH_LONG, GB.WARN);
return;
}
int hours = calendar.get(Calendar.HOUR_OF_DAY);
@ -152,6 +146,5 @@ public class WidgetAlarmsActivity extends Activity implements View.OnClickListen
alarms.add(alarm);
GBApplication.deviceService().onSetAlarms(alarms);
}
}

View File

@ -31,7 +31,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
import nodomain.freeyourgadget.gadgetbridge.util.WidgetPreferenceStorage;
public class WidgetConfigurationActivity extends Activity {
private static final Logger LOG = LoggerFactory.getLogger(Widget.class);
private static final Logger LOG = LoggerFactory.getLogger(WidgetConfigurationActivity.class);
int mAppWidgetId;
LinkedHashMap<String, Pair<String, Integer>> allDevices;
@ -44,6 +44,7 @@ public class WidgetConfigurationActivity extends Activity {
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
mAppWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,

View File

@ -26,7 +26,11 @@ import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.Widget;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class WidgetPreferenceStorage {
private static final Logger LOG = LoggerFactory.getLogger(WidgetPreferenceStorage.class);
@ -151,4 +155,31 @@ public class WidgetPreferenceStorage {
}
GB.toast("Saved app widget preferences: " + savedWidgetsPreferencesDataArray, Toast.LENGTH_SHORT, GB.INFO);
}
public GBDevice getDeviceForWidget(int appWidgetId) {
Context context = GBApplication.getContext();
if (!(context instanceof GBApplication)) {
return null;
}
String savedDeviceAddress = getSavedDeviceAddress(context, appWidgetId);
if (savedDeviceAddress != null) {
return getDeviceByMAC(context.getApplicationContext(), savedDeviceAddress); //this would probably only happen if device no longer exists in GB
}
return null;
}
private GBDevice getDeviceByMAC(Context appContext, String HwAddress) {
GBApplication gbApp = (GBApplication) appContext;
List<? extends GBDevice> devices = gbApp.getDeviceManager().getDevices();
for (GBDevice device : devices) {
if (device.getAddress().equals(HwAddress)) {
return device;
}
}
return null;
}
}

View File

@ -6,4 +6,6 @@
android:minWidth="40dp"
android:previewImage="@drawable/ic_launcher"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>
android:configure="nodomain.freeyourgadget.gadgetbridge.activities.SleepAlarmWidgetConfigurationActivity"
android:widgetCategory="home_screen">
</appwidget-provider>