1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-12-26 18:45:49 +01:00

Rework the Daily Widget:

- make layout transparent rather then red, update the preview image
- move battery to top row to reduce size, add status indicators with icons
- add preference settings, to choose for which device this widget is
- data is no longer calculated for all devices but for a selected device
- add debug items to view and erase widget settings and registrations
  (debug items are intentionally not translatable yet)
This commit is contained in:
vanous 2020-12-07 22:13:49 +01:00
parent ec95766d1f
commit 502f689862
14 changed files with 657 additions and 98 deletions

View File

@ -528,6 +528,8 @@
android:label="@string/widget_listing_label">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="android.appwidget.action.APPWIDGET_DELETED" />
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
<action android:name="nodomain.freeyourgadget.gadgetbridge.WidgetClick" />
</intent-filter>
@ -541,6 +543,13 @@
android:excludeFromRecents="true"
android:launchMode="singleInstance"
android:theme="@style/Theme.AppCompat.Light.Dialog" />
<activity android:name=".activities.WidgetConfigurationActivity">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
</intent-filter>
</activity>
<activity
android:name=".activities.ExternalPebbleJSActivity"
android:allowTaskReparenting="true"

View File

@ -11,11 +11,30 @@
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Copyright (C) 2019-2020 Andreas Shimokawa, vanous
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
@ -24,6 +43,8 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.RemoteViews;
import android.widget.Toast;
@ -32,40 +53,55 @@ import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
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.WidgetAlarmsActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.DailyTotals;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.WidgetPreferenceStorage;
public class Widget extends AppWidgetProvider {
public static final String WIDGET_CLICK = "nodomain.freeyourgadget.gadgetbridge.WidgetClick";
public static final String APPWIDGET_DELETED = "nodomain.freeyourgadget.gadgetbridge.APPWIDGET_DELETED";
public static final String APPWIDGET_DELETED = "android.appwidget.action.APPWIDGET_DELETED";
public static final String APPWIDGET_CONFIGURE = "nodomain.freeyourgadget.gadgetbridge.APPWIDGET_CONFIGURE";
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() {
Context context = GBApplication.getContext();
Calendar day = GregorianCalendar.getInstance();
@ -74,7 +110,10 @@ public class Widget extends AppWidgetProvider {
return new long[]{0, 0, 0};
}
DailyTotals ds = new DailyTotals();
return ds.getDailyTotalsForAllDevices(day);
return ds.getDailyTotalsForDevice(selectedDevice, day);
//return ds.getDailyTotalsForAllDevices(day);
}
private String getHM(long value) {
@ -84,16 +123,23 @@ public class Widget extends AppWidgetProvider {
private void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
GBDevice device = getSelectedDevice();
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
}
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
//onclick refresh
Intent intent = new Intent(context, Widget.class);
intent.setAction(WIDGET_CLICK);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
PendingIntent refreshDataIntent = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//views.setOnClickPendingIntent(R.id.todaywidget_bottom_layout, refreshDataIntent);
views.setOnClickPendingIntent(R.id.todaywidget_header_bar, refreshDataIntent);
views.setOnClickPendingIntent(R.id.todaywidget_header_container, refreshDataIntent);
//open GB main window
Intent startMainIntent = new Intent(context, ControlCenterv2.class);
@ -103,33 +149,55 @@ public class Widget extends AppWidgetProvider {
//alarms popup menu
Intent startAlarmListIntent = new Intent(context, WidgetAlarmsActivity.class);
PendingIntent startAlarmListPIntent = PendingIntent.getActivity(context, 0, startAlarmListIntent, 0);
views.setOnClickPendingIntent(R.id.todaywidget_header_plus, startAlarmListPIntent);
views.setOnClickPendingIntent(R.id.todaywidget_header_alarm_icon, startAlarmListPIntent);
//charts, requires device
if (device != null) {
if (selectedDevice != null) {
Intent startChartsIntent = new Intent(context, ChartsActivity.class);
startChartsIntent.putExtra(GBDevice.EXTRA_DEVICE, device);
startChartsIntent.putExtra(GBDevice.EXTRA_DEVICE, selectedDevice);
PendingIntent startChartsPIntent = PendingIntent.getActivity(context, 0, startChartsIntent, 0);
views.setOnClickPendingIntent(R.id.todaywidget_bottom_layout, startChartsPIntent);
}
long[] dailyTotals = getSteps();
int steps = (int) dailyTotals[0];
int sleep = (int) dailyTotals[1];
views.setTextViewText(R.id.todaywidget_steps, context.getString(R.string.widget_steps_label, dailyTotals[0]));
views.setTextViewText(R.id.todaywidget_sleep, context.getString(R.string.widget_sleep_label, getHM(dailyTotals[1])));
ActivityUser activityUser = new ActivityUser();
int stepGoal = activityUser.getStepsGoal();
int sleepGoal = activityUser.getSleepDuration();
int sleepGoalMinutes = sleepGoal * 60;
int distanceGoal = activityUser.getDistanceMeters() * 100;
int stepLength = activityUser.getStepLengthCm();
int distanceFormatted = (int) (dailyTotals[0] * stepLength / 100);
if (device != null) {
String status = String.format("%1s", device.getStateString());
if (device.isConnected()) {
if (device.getBatteryLevel() > 1) {
status = String.format("Battery %1s%%", device.getBatteryLevel());
String unit = "###m";
if (distanceFormatted > 2000) {
distanceFormatted = distanceFormatted / 1000;
unit = "###.#km";
}
DecimalFormat df = new DecimalFormat(unit);
views.setTextViewText(R.id.todaywidget_steps, String.format("%1s", steps));
views.setTextViewText(R.id.todaywidget_sleep, String.format("%1s", getHM(sleep)));
views.setTextViewText(R.id.todaywidget_distance, df.format(distanceFormatted));
views.setProgressBar(R.id.todaywidget_steps_progress, stepGoal, steps, false);
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) {
views.setViewVisibility(R.id.todaywidget_battery_icon, View.VISIBLE);
status = String.format("%1s%%", selectedDevice.getBatteryLevel());
}
}
String deviceName = selectedDevice.getAlias() != null ? selectedDevice.getAlias() : selectedDevice.getName();
views.setTextViewText(R.id.todaywidget_device_status, status);
views.setTextViewText(R.id.todaywidget_device_name, device.getName());
views.setTextViewText(R.id.todaywidget_device_name, deviceName);
}
// Instruct the widget manager to update the widget
@ -160,13 +228,15 @@ public class Widget extends AppWidgetProvider {
public void updateWidget() {
Context context = GBApplication.getContext();
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
ComponentName thisAppWidget = new ComponentName(context.getPackageName(), Widget.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
onUpdate(context, appWidgetManager, appWidgetIds);
}
public void removeWidget(Context context, int appWidgetId) {
WidgetPreferenceStorage widgetPreferenceStorage = new WidgetPreferenceStorage();
widgetPreferenceStorage.removeWidgetById(context, appWidgetId);
}
@Override
@ -177,7 +247,6 @@ public class Widget extends AppWidgetProvider {
}
}
@Override
public void onEnabled(Context context) {
if (broadcastReceiver == null) {
@ -198,9 +267,8 @@ public class Widget extends AppWidgetProvider {
@Override
public void onDisabled(Context context) {
if (broadcastReceiver != null) {
AndroidUtils.safeUnregisterBroadcastReceiver(context,broadcastReceiver);
AndroidUtils.safeUnregisterBroadcastReceiver(context, broadcastReceiver);
broadcastReceiver = null;
}
}
@ -208,16 +276,25 @@ public class Widget extends AppWidgetProvider {
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
LOG.debug("gbwidget LOCAL onReceive, action: " + intent.getAction());
LOG.debug("gbwidget LOCAL onReceive, action: " + intent.getAction() + intent);
Bundle extras = intent.getExtras();
int appWidgetId = -1;
if (extras != null) {
appWidgetId = extras.getInt(
AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
}
//this handles widget re-connection after apk updates
if (WIDGET_CLICK.equals(intent.getAction())) {
if (broadcastReceiver == null) {
onEnabled(context);
}
refreshData();
refreshData();
//updateWidget();
} else if (APPWIDGET_DELETED.equals(intent.getAction())) {
onDisabled(context);
removeWidget(context, appWidgetId);
}
}

View File

@ -381,7 +381,7 @@ public class ActivitySummariesFilter extends AbstractGBActivity {
update_filter_fields();
}
private LinkedHashMap getAllDevices(Context appContext) {
public LinkedHashMap getAllDevices(Context appContext) {
DaoSession daoSession;
GBApplication gbApp = (GBApplication) appContext;
LinkedHashMap<String, Pair<Long, Integer>> newMap = new LinkedHashMap<>(1);

View File

@ -22,7 +22,10 @@ import android.app.AlertDialog;
import android.app.DatePickerDialog;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -55,6 +58,7 @@ import java.util.Objects;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.Widget;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
@ -66,6 +70,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
import nodomain.freeyourgadget.gadgetbridge.service.serial.GBDeviceProtocol;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.WidgetPreferenceStorage;
import static android.content.Intent.EXTRA_SUBJECT;
import static nodomain.freeyourgadget.gadgetbridge.util.GB.NOTIFICATION_CHANNEL_ID;
@ -333,6 +338,76 @@ public class DebugActivity extends AbstractGBActivity {
showWarning();
}
});
Button showWidgetsButton = findViewById(R.id.showWidgetsButton);
showWidgetsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showAllRegisteredAppWidgets();
}
});
Button unregisterWidgetsButton = findViewById(R.id.deleteWidgets);
unregisterWidgetsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unregisterAllRegisteredAppWidgets();
}
});
Button showWidgetsPrefsButton = findViewById(R.id.showWidgetsPrefs);
showWidgetsPrefsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showAppWidgetsPrefs();
}
});
Button deleteWidgetsPrefsButton = findViewById(R.id.deleteWidgetsPrefs);
deleteWidgetsPrefsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
deleteWidgetsPrefs();
}
});
}
private void deleteWidgetsPrefs() {
WidgetPreferenceStorage widgetPreferenceStorage = new WidgetPreferenceStorage();
widgetPreferenceStorage.deleteWidgetsPrefs(DebugActivity.this);
widgetPreferenceStorage.showAppWidgetsPrefs(DebugActivity.this);
}
private void showAppWidgetsPrefs() {
WidgetPreferenceStorage widgetPreferenceStorage = new WidgetPreferenceStorage();
widgetPreferenceStorage.showAppWidgetsPrefs(DebugActivity.this);
}
private void showAllRegisteredAppWidgets() {
//https://stackoverflow.com/questions/17387191/check-if-a-widget-is-exists-on-homescreen-using-appwidgetid
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(DebugActivity.this);
AppWidgetHost appWidgetHost = new AppWidgetHost(DebugActivity.this, 1); // for removing phantoms
int[] appWidgetIDs = appWidgetManager.getAppWidgetIds(new ComponentName(DebugActivity.this, Widget.class));
GB.toast("Number of registered app widgets: " + appWidgetIDs.length, Toast.LENGTH_SHORT, GB.INFO);
for (int appWidgetID : appWidgetIDs) {
GB.toast("Widget: " + appWidgetID, Toast.LENGTH_SHORT, GB.INFO);
}
}
private void unregisterAllRegisteredAppWidgets() {
//https://stackoverflow.com/questions/17387191/check-if-a-widget-is-exists-on-homescreen-using-appwidgetid
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(DebugActivity.this);
AppWidgetHost appWidgetHost = new AppWidgetHost(DebugActivity.this, 1); // for removing phantoms
int[] appWidgetIDs = appWidgetManager.getAppWidgetIds(new ComponentName(DebugActivity.this, Widget.class));
GB.toast("Number of registered app widgets: " + appWidgetIDs.length, Toast.LENGTH_SHORT, GB.INFO);
for (int appWidgetID : appWidgetIDs) {
appWidgetHost.deleteAppWidgetId(appWidgetID);
GB.toast("Removing widget: " + appWidgetID, Toast.LENGTH_SHORT, GB.INFO);
}
}
private void showWarning() {

View File

@ -0,0 +1,132 @@
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.Widget;
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 WidgetConfigurationActivity extends Activity {
private static final Logger LOG = LoggerFactory.getLogger(Widget.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(WidgetConfigurationActivity.this);
builder.setTitle("Select device");
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.supportsActivityTracks()
&& !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

@ -56,7 +56,7 @@ public class DailyTotals {
}
long[] all_daily = getDailyTotalsForDevice(device, day);
all_steps += all_daily[0];
all_sleep += all_daily[1] + all_daily[2];
all_sleep += all_daily[1];
}
}
//LOG.debug("gbwidget daily totals, all steps:" + all_steps);
@ -78,12 +78,11 @@ public class DailyTotals {
long[] sleep = getTotalsSleepForActivityAmounts(amountsSleep);
long steps = getTotalsStepsForActivityAmounts(amountsSteps);
return new long[]{steps, sleep[0], sleep[1]};
return new long[]{steps, sleep[0] + sleep[1]};
} catch (Exception e) {
GB.toast("Error loading activity summaries.", Toast.LENGTH_SHORT, GB.ERROR, e);
return new long[]{0, 0, 0};
//GB.toast("Error loading sleep/steps widget data for device: " + device, Toast.LENGTH_SHORT, GB.ERROR, e);
return new long[]{0, 0};
}
}

View File

@ -0,0 +1,139 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.Widget;
public class WidgetPreferenceStorage {
private static final Logger LOG = LoggerFactory.getLogger(WidgetPreferenceStorage.class);
boolean isWidgetInPrefs = false;
String PREFS_WIDGET_SETTINGS = "widget_settings";
public String getSavedDeviceAddress(Context context, int appWidgetId) {
String savedDeviceAddress = null;
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String savedWidgetsPreferencesData = sharedPrefs.getString(PREFS_WIDGET_SETTINGS, "");
JSONArray savedWidgetsPreferencesDataArray = null;
try {
savedWidgetsPreferencesDataArray = new JSONArray(savedWidgetsPreferencesData);
savedWidgetsPreferencesDataArray = new JSONArray("fdsfdsfsffs");
} catch (
JSONException e) {
LOG.error(e.getMessage());
}
LOG.debug("widget JSON loaded: " + savedWidgetsPreferencesDataArray);
if (savedWidgetsPreferencesDataArray == null) {
return null;
}
for (int i = 0; i < savedWidgetsPreferencesDataArray.length(); i++) {
try {
JSONArray a = savedWidgetsPreferencesDataArray.getJSONArray(i);
if (appWidgetId == a.getInt(0)) {
isWidgetInPrefs = true;
savedDeviceAddress = a.getString(1);
}
} catch (JSONException e) {
LOG.error(e.getMessage());
}
}
return savedDeviceAddress;
}
public void removeWidgetById(Context context, int appWidgetId) {
LOG.debug("widget trying to remove: " + appWidgetId);
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String savedWidgetsPreferencesData = sharedPrefs.getString(PREFS_WIDGET_SETTINGS, "");
JSONArray savedWidgetsPreferencesDataArray = null;
try {
savedWidgetsPreferencesDataArray = new JSONArray(savedWidgetsPreferencesData);
} catch (
JSONException e) {
LOG.error(e.getMessage());
}
if (savedWidgetsPreferencesDataArray == null) {
return;
}
for (int i = 0; i < savedWidgetsPreferencesDataArray.length(); i++) {
try {
JSONArray a = savedWidgetsPreferencesDataArray.getJSONArray(i);
if (appWidgetId == a.getInt(0)) {
GB.toast("Removing widget preferences: " + appWidgetId, Toast.LENGTH_SHORT, GB.INFO);
savedWidgetsPreferencesDataArray.remove(i);
}
} catch (JSONException e) {
LOG.error(e.getMessage());
}
}
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(PREFS_WIDGET_SETTINGS, savedWidgetsPreferencesDataArray.toString());
editor.commit();
editor.apply();
}
public void saveWidgetPrefs(Context context, String AppWidgetId, String HwAddress) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String savedWidgetsPreferencesData = sharedPrefs.getString(PREFS_WIDGET_SETTINGS, "");
JSONArray savedWidgetsPreferencesDataArray = null;
try {
savedWidgetsPreferencesDataArray = new JSONArray(savedWidgetsPreferencesData);
} catch (
JSONException e) {
LOG.error(e.getMessage());
}
if (savedWidgetsPreferencesDataArray == null) {
savedWidgetsPreferencesDataArray = new JSONArray();
}
try {
savedWidgetsPreferencesDataArray.put(new JSONArray(new String[]{AppWidgetId, HwAddress}));
} catch (JSONException e) {
LOG.error(e.getMessage());
}
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(PREFS_WIDGET_SETTINGS, savedWidgetsPreferencesDataArray.toString());
editor.commit();
editor.apply();
}
public boolean isWidgetInPrefs() {
return isWidgetInPrefs;
}
public void deleteWidgetsPrefs(Context context) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = sharedPrefs.edit();
editor.putString(PREFS_WIDGET_SETTINGS, "");
editor.commit();
editor.apply();
}
public void showAppWidgetsPrefs(Context context) {
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);
String savedWidgetsPreferencesData = sharedPrefs.getString(PREFS_WIDGET_SETTINGS, "");
JSONArray savedWidgetsPreferencesDataArray = null;
try {
savedWidgetsPreferencesDataArray = new JSONArray(savedWidgetsPreferencesData);
} catch (
JSONException e) {
LOG.error(e.getMessage());
}
GB.toast("Saved app widget preferences: " + savedWidgetsPreferencesDataArray, Toast.LENGTH_SHORT, GB.INFO);
}
}

View File

@ -1,3 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="24dp" android:viewportHeight="24" android:viewportWidth="24" android:tint="#7E7E7E" android:width="24dp">
<path android:fillColor="#000" android:pathData="M10.74 11.72c0.47 1.23 0.42 2.51-0.99 3.02-2.9 1.07-3.55-1.74-3.59-1.88l4.58-1.14m-5.03-0.81l4.32-1.07c-0.19-1.05 0.1-2.1 0.1-3.34 0-1.68-1.33-4.97-3.45-4.44C4.26 2.66 3.91 5.35 4 6.65c0.12 1.3 1.64 4.08 1.71 4.26m12.14 8.94c-0.03 0.15-0.69 2.95-3.59 1.89-1.4-0.52-1.46-1.8-0.99-3.03l4.58 1.14m2.15-6.2c0.1-1.3-0.24-4-2.67-4.6-2.11-0.55-3.44 2.76-3.44 4.45 0 1.23 0.28 2.28 0.11 3.33l4.3 1.07c0.08-0.18 1.59-2.96 1.7-4.25z"/>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#7E7E7E"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#000"
android:pathData="M10.74 11.72c0.47 1.23 0.42 2.51-0.99 3.02-2.9 1.07-3.55-1.74-3.59-1.88l4.58-1.14m-5.03-0.81l4.32-1.07c-0.19-1.05 0.1-2.1 0.1-3.34 0-1.68-1.33-4.97-3.45-4.44C4.26 2.66 3.91 5.35 4 6.65c0.12 1.3 1.64 4.08 1.71 4.26m12.14 8.94c-0.03 0.15-0.69 2.95-3.59 1.89-1.4-0.52-1.46-1.8-0.99-3.03l4.58 1.14m2.15-6.2c0.1-1.3-0.24-4-2.67-4.6-2.11-0.55-3.44 2.76-3.44 4.45 0 1.23 0.28 2.28 0.11 3.33l4.3 1.07c0.08-0.18 1.59-2.96 1.7-4.25z" />
</vector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -166,6 +166,35 @@
grid:layout_columnSpan="2"
grid:layout_gravity="fill_horizontal"
android:text="@string/share_log" />
<Button
android:id="@+id/showWidgetsButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
grid:layout_columnSpan="2"
grid:layout_gravity="fill_horizontal"
android:text="Show all registered app widgets IDs" />
<Button
android:id="@+id/deleteWidgets"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
grid:layout_columnSpan="2"
grid:layout_gravity="fill_horizontal"
android:text="Delete all registered app widgets IDs" />
<Button
android:id="@+id/showWidgetsPrefs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
grid:layout_columnSpan="2"
grid:layout_gravity="fill_horizontal"
android:text="Show app Widgets Preferences" />
<Button
android:id="@+id/deleteWidgetsPrefs"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
grid:layout_columnSpan="2"
grid:layout_gravity="fill_horizontal"
android:text="Delete app Widgets Preferences" />
</androidx.gridlayout.widget.GridLayout>
</ScrollView>

View File

@ -1,8 +1,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/alarm_list_top_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/primary_dark"
android:orientation="vertical">
<LinearLayout
@ -24,33 +24,44 @@
android:src="@drawable/ic_notification" />
<LinearLayout
android:id="@+id/todaywidget_header_bar"
<TextView
android:id="@+id/todaywidget_device_name"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_weight="1"
android:gravity="start"
android:paddingLeft="0dp"
android:paddingRight="0dp">
<TextView
android:id="@+id/todaywidget_device_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:drawablePadding="4dp"
android:ellipsize="end"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
</LinearLayout>
android:drawablePadding="4dp"
android:ellipsize="end"
android:gravity="center_vertical"
android:maxLines="1"
android:text="@string/app_name"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
<ImageView
android:id="@+id/todaywidget_header_plus"
android:id="@+id/todaywidget_battery_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="start|center_vertical"
android:backgroundTint="#FFFFFF"
android:background="@drawable/ic_battery_full"
android:contentDescription="@string/icon_placeholder"
android:padding="0dp" />
<TextView
android:id="@+id/todaywidget_device_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|end"
android:foregroundGravity="right"
android:gravity="end"
android:text="@string/device_not_connected"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
<ImageView
android:id="@+id/todaywidget_header_alarm_icon"
android:layout_width="32dp"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
@ -65,55 +76,137 @@
<LinearLayout
android:id="@+id/todaywidget_bottom_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:background="#2BE3DBDB"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingLeft="3dp"
android:paddingRight="3dp">
android:paddingRight="3dp"
android:paddingBottom="5dp">
<LinearLayout
android:id="@+id/todaywidget_bottom_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/todaywidget_steps_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="start|center_vertical"
android:backgroundTint="#FFFFFF"
android:background="@drawable/ic_shoe_print"
android:contentDescription="@string/icon_placeholder"
android:padding="0dp" />
<TextView
android:id="@+id/todaywidget_steps"
android:layout_width="wrap_content"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/widget_steps_label"
android:gravity="center_vertical|center_horizontal"
android:text="@string/widget_steps_label"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
android:orientation="vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<TextView
android:id="@+id/todaywidget_steps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
<ProgressBar
android:id="@+id/todaywidget_steps_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_weight="1"
android:background="#FFFFFF" />
</LinearLayout>
<TextView
android:id="@+id/todaywidget_sleep"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/widget_sleep_label"
android:gravity="center_vertical|center_horizontal"
android:text="@string/widget_sleep_label"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
</LinearLayout>
<TextView
android:id="@+id/empty"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView
android:id="@+id/todaywidget_device_status"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:foregroundGravity="right"
android:gravity="end"
android:text="@string/device_not_connected"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/todaywidget_distance_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="start|center_vertical"
android:backgroundTint="#FFFFFF"
android:background="@drawable/ic_distance"
android:contentDescription="@string/icon_placeholder"
android:padding="0dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<TextView
android:id="@+id/todaywidget_distance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
<ProgressBar
android:id="@+id/todaywidget_distance_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_weight="1"
android:background="#FFFFFF" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/todaywidget_sleep_icon"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_gravity="start|center_vertical"
android:backgroundTint="#FFFFFF"
android:background="@drawable/ic_activity_sleep"
android:contentDescription="@string/icon_placeholder" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
<TextView
android:id="@+id/todaywidget_sleep"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal"
android:textColor="@color/primarytext_dark"
android:textSize="18sp" />
<ProgressBar
android:id="@+id/todaywidget_sleep_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="3dp"
android:layout_weight="1"
android:background="#FFFFFF" />
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@ -8,7 +8,7 @@
android:orientation="vertical">
<LinearLayout
android:id="@+id/todaywidget_header_container"
android:id="@+id/todaywidget_alarm_header_container"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="@color/accent"
@ -17,7 +17,7 @@
<LinearLayout
android:id="@+id/todaywidget_header_bar"
android:id="@+id/todaywidget_alarm_header_bar"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"

View File

@ -900,8 +900,6 @@
<string name="add_widget">Add widget</string>
<string name="appwidget_setting_alarm">Setting alarm for %1$02d:%2$02d</string>
<string name="appwidget_sleep_alarm_widget_label">Sleep Alarm</string>
<string name="widget_steps_label">Steps: %1$02d</string>
<string name="widget_sleep_label">Sleep: %1$s</string>
<string name="widget_listing_label">Status and Alarms</string>
<string name="widget_set_alarm_after">Set alarm after:</string>
<string name="widget_5_minutes">5 minutes</string>

View File

@ -9,6 +9,7 @@
android:resizeMode="horizontal|vertical"
android:previewImage="@drawable/widget_preview"
android:updatePeriodMillis="86400000"
android:configure="nodomain.freeyourgadget.gadgetbridge.activities.WidgetConfigurationActivity"
android:widgetCategory="home_screen|keyguard|searchbox">
</appwidget-provider>