diff --git a/README.md b/README.md
index 847ee0a2..ddf692b0 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ Install [openScale-dev-build.apk](https://github.com/oliexdev/openScale/releases
# Features
- Logs your body metrics (weight, body fat, body water, muscle percentage, lean body mass, bone mass, BMI, BMR, waist/hip circumference, waist-hip ratio, waist-to-height ratio)
+- Widget that can be added to the home screen showing any of the available metrics
- Keep track of your diet process
- Display all your data on a chart and table
- Import or export your data from/into a CSV file
diff --git a/android_app/app/src/main/AndroidManifest.xml b/android_app/app/src/main/AndroidManifest.xml
index 58ac47e6..30e2c975 100644
--- a/android_app/app/src/main/AndroidManifest.xml
+++ b/android_app/app/src/main/AndroidManifest.xml
@@ -36,6 +36,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
0) {
+ Intent intent = new Intent(context, WidgetProvider.class);
+ intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
+ context.sendBroadcast(intent);
+ }
+ }
+
public int addScaleUser(final ScaleUser user) {
return (int)userDAO.insert(user);
}
@@ -247,6 +262,9 @@ public class OpenScale {
return scaleMeasurementList;
}
+ public ScaleMeasurement getLatestScaleMeasurement(int userId) {
+ return measurementDAO.getLatest(userId);
+ }
public ScaleMeasurement[] getTupleScaleData(int id)
{
@@ -324,6 +342,7 @@ public class OpenScale {
}
alarmHandler.entryChanged(context, scaleMeasurement);
updateScaleData();
+ triggerWidgetUpdate();
} else {
if (!silent) {
Toast.makeText(context, context.getString(R.string.info_new_data_duplicated), Toast.LENGTH_LONG).show();
@@ -374,6 +393,7 @@ public class OpenScale {
alarmHandler.entryChanged(context, scaleMeasurement);
updateScaleData();
+ triggerWidgetUpdate();
}
public void deleteScaleData(int id)
diff --git a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleMeasurementDAO.java b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleMeasurementDAO.java
index e91a8022..dba85587 100644
--- a/android_app/app/src/main/java/com/health/openscale/core/database/ScaleMeasurementDAO.java
+++ b/android_app/app/src/main/java/com/health/openscale/core/database/ScaleMeasurementDAO.java
@@ -47,6 +47,9 @@ public interface ScaleMeasurementDAO {
@Query("SELECT * FROM scaleMeasurements WHERE datetime >= :startYear AND datetime < :endYear AND userId = :userId AND enabled = 1 ORDER BY datetime DESC")
List getAllInRange(Date startYear, Date endYear, int userId);
+ @Query("SELECT * FROM scaleMeasurements WHERE userId = :userId AND enabled = 1 ORDER BY datetime DESC LIMIT 1")
+ ScaleMeasurement getLatest(int userId);
+
@Insert (onConflict = OnConflictStrategy.IGNORE)
long insert(ScaleMeasurement measurement);
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java
index 9522a051..2727cb55 100644
--- a/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java
+++ b/android_app/app/src/main/java/com/health/openscale/gui/MainActivity.java
@@ -196,6 +196,7 @@ public class MainActivity extends BaseAppCompatActivity
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
if (settingsActivityRunning) {
recreate();
+ OpenScale.getInstance().triggerWidgetUpdate();
}
}
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java
index 6b4fa3bb..294410a8 100644
--- a/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java
+++ b/android_app/app/src/main/java/com/health/openscale/gui/fragments/TableFragment.java
@@ -284,7 +284,7 @@ public class TableFragment extends Fragment implements FragmentUpdateListener {
SpannableStringBuilder string = new SpannableStringBuilder();
string.append(visibleMeasurements.get(i).getValueAsString(false));
- visibleMeasurements.get(i).appendDiffValue(string);
+ visibleMeasurements.get(i).appendDiffValue(string, true);
stringCache[position][i] = string;
}
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java
index 2f17e6b2..48396bd2 100644
--- a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java
+++ b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java
@@ -405,7 +405,7 @@ public abstract class FloatMeasurementView extends MeasurementView {
}
@Override
- public void appendDiffValue(SpannableStringBuilder text) {
+ public void appendDiffValue(SpannableStringBuilder text, boolean newLine) {
if (previousValue < 0.0f) {
return;
}
@@ -425,7 +425,9 @@ public abstract class FloatMeasurementView extends MeasurementView {
color = Color.GRAY;
}
- text.append('\n');
+ if (newLine) {
+ text.append('\n');
+ }
int start = text.length();
text.append(symbol);
text.setSpan(new ForegroundColorSpan(color), start, text.length(),
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java
index d33a03b1..49375144 100644
--- a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java
+++ b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java
@@ -20,6 +20,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.preference.PreferenceManager;
@@ -65,6 +66,7 @@ public abstract class MeasurementView extends TableLayout {
private TableRow measurementRow;
private ImageView iconView;
+ private int iconId;
private TextView nameView;
private TextView valueView;
private LinearLayout incDecLayout;
@@ -84,6 +86,7 @@ public abstract class MeasurementView extends TableLayout {
initView(context);
nameView.setText(textId);
+ this.iconId = iconId;
iconView.setImageResource(iconId);
}
@@ -256,8 +259,9 @@ public abstract class MeasurementView extends TableLayout {
public CharSequence getName() { return nameView.getText(); }
public abstract String getValueAsString(boolean withUnit);
- public void appendDiffValue(SpannableStringBuilder builder) { }
+ public void appendDiffValue(SpannableStringBuilder builder, boolean newLine) { }
public Drawable getIcon() { return iconView.getDrawable(); }
+ public int getIconResource() { return iconId; }
protected boolean isEditable() {
return true;
@@ -319,6 +323,11 @@ public abstract class MeasurementView extends TableLayout {
return valueView.getCurrentTextColor();
}
+ public int getIndicatorColor() {
+ ColorDrawable background = (ColorDrawable)indicatorView.getBackground();
+ return background.getColor();
+ }
+
protected void showEvaluatorRow(boolean show) {
if (show) {
evaluatorRow.setVisibility(View.VISIBLE);
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetConfigure.java b/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetConfigure.java
new file mode 100644
index 00000000..6019112b
--- /dev/null
+++ b/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetConfigure.java
@@ -0,0 +1,120 @@
+/* Copyright (C) 2018 Erik Johansson
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+
+package com.health.openscale.gui.widget;
+
+import android.appwidget.AppWidgetManager;
+import android.content.Intent;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.view.View;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.TableRow;
+
+import com.health.openscale.R;
+import com.health.openscale.core.OpenScale;
+import com.health.openscale.core.datatypes.ScaleUser;
+import com.health.openscale.gui.activities.BaseAppCompatActivity;
+import com.health.openscale.gui.views.MeasurementView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class WidgetConfigure extends BaseAppCompatActivity {
+ private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setResult(RESULT_CANCELED);
+
+ Intent intent = getIntent();
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ appWidgetId = extras.getInt(
+ AppWidgetManager.EXTRA_APPWIDGET_ID,
+ AppWidgetManager.INVALID_APPWIDGET_ID);
+ }
+
+ if (appWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
+ finish();
+ }
+
+ setContentView(R.layout.widget_configuration);
+
+ OpenScale openScale = OpenScale.getInstance();
+
+ // Set up user spinner
+ final Spinner userSpinner = findViewById(R.id.widget_user_spinner);
+ List users = new ArrayList<>();
+ final List userIds = new ArrayList<>();
+ for (ScaleUser scaleUser : openScale.getScaleUserList()) {
+ users.add(scaleUser.getUserName());
+ userIds.add(scaleUser.getId());
+ }
+ ArrayAdapter userAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_item, users);
+ userAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ userSpinner.setAdapter(userAdapter);
+
+ // Hide user selector when there's only one user
+ if (users.size() == 1) {
+ TableRow row = (TableRow) userSpinner.getParent();
+ row.setVisibility(View.GONE);
+ }
+
+ // Set up measurement spinner
+ final Spinner measurementSpinner = findViewById(R.id.widget_measurement_spinner);
+ List measurements = new ArrayList<>();
+ final List measurementKeys = new ArrayList<>();
+ for (MeasurementView measurementView : MeasurementView.getMeasurementList(
+ this, MeasurementView.DateTimeOrder.NONE)) {
+ if (measurementView.isVisible()) {
+ measurements.add(measurementView.getName().toString());
+ measurementKeys.add(measurementView.getKey());
+ }
+ }
+ ArrayAdapter measurementAdapter = new ArrayAdapter<>(
+ this, android.R.layout.simple_spinner_item, measurements);
+ measurementAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ measurementSpinner.setAdapter(measurementAdapter);
+
+ findViewById(R.id.widget_save).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ int userId = userIds.get(userSpinner.getSelectedItemPosition());
+ String measurementKey = measurementKeys.get(measurementSpinner.getSelectedItemPosition());
+
+ PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).edit()
+ .putInt(WidgetProvider.getUserIdPreferenceName(appWidgetId), userId)
+ .putString(WidgetProvider.getMeasurementPreferenceName(appWidgetId), measurementKey)
+ .apply();
+
+ Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE, null);
+ intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[] {appWidgetId});
+ sendBroadcast(intent);
+
+ Intent resultValue = new Intent();
+ resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
+ setResult(RESULT_OK, resultValue);
+
+ finish();
+ }
+ });
+ }
+}
diff --git a/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetProvider.java b/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetProvider.java
new file mode 100644
index 00000000..73c8bbb8
--- /dev/null
+++ b/android_app/app/src/main/java/com/health/openscale/gui/widget/WidgetProvider.java
@@ -0,0 +1,198 @@
+/* Copyright (C) 2018 Erik Johansson
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ */
+
+package com.health.openscale.gui.widget;
+
+import android.app.PendingIntent;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProvider;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.SpannableStringBuilder;
+import android.util.TypedValue;
+import android.view.View;
+import android.widget.RemoteViews;
+
+import com.health.openscale.R;
+import com.health.openscale.core.OpenScale;
+import com.health.openscale.core.datatypes.ScaleMeasurement;
+import com.health.openscale.gui.MainActivity;
+import com.health.openscale.gui.activities.BaseAppCompatActivity;
+import com.health.openscale.gui.views.MeasurementView;
+
+import java.text.DateFormat;
+import java.util.List;
+
+public class WidgetProvider extends AppWidgetProvider {
+ List measurementViews;
+
+ public static final String getUserIdPreferenceName(int appWidgetId) {
+ return String.format("widget_%d_userid", appWidgetId);
+ }
+
+ public static final String getMeasurementPreferenceName(int appWidgetId) {
+ return String.format("widget_%d_measurement", appWidgetId);
+ }
+
+ private void updateWidget(Context context, AppWidgetManager appWidgetManager,
+ int appWidgetId, Bundle newOptions) {
+ // Make sure we use the correct language
+ context = BaseAppCompatActivity.createBaseContext(context);
+
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ int userId = prefs.getInt(getUserIdPreferenceName(appWidgetId), -1);
+ String key = prefs.getString(getMeasurementPreferenceName(appWidgetId), "");
+
+ if (measurementViews == null) {
+ measurementViews = MeasurementView.getMeasurementList(
+ context, MeasurementView.DateTimeOrder.NONE);
+ }
+
+ MeasurementView measurementView = measurementViews.get(0);
+ for (MeasurementView view : measurementViews) {
+ if (view.getKey().equals(key)) {
+ measurementView = view;
+ break;
+ }
+ }
+
+ OpenScale openScale = OpenScale.getInstance();
+ ScaleMeasurement latest = openScale.getLatestScaleMeasurement(userId);
+ if (latest != null) {
+ ScaleMeasurement previous = openScale.getTupleScaleData(latest.getId())[0];
+ measurementView.loadFrom(latest, previous);
+ }
+
+ final int minWidth = newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH);
+ // From https://developer.android.com/guide/practices/ui_guidelines/widget_design
+ final int twoCellsMinWidth = 110;
+ final int thirdCellsMinWidth = 180;
+ final int fourCellsMinWidth = 250;
+
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
+
+ views.setInt(R.id.indicator_view, "setBackgroundColor", measurementView.getIndicatorColor());
+
+ // Show icon in >= two cell mode
+ if (minWidth >= twoCellsMinWidth) {
+ views.setImageViewResource(R.id.widget_icon, measurementView.getIconResource());
+ views.setViewVisibility(R.id.widget_icon, View.VISIBLE);
+ views.setViewVisibility(R.id.widget_icon_vertical, View.GONE);
+ }
+ else {
+ views.setImageViewResource(R.id.widget_icon_vertical, measurementView.getIconResource());
+ views.setViewVisibility(R.id.widget_icon_vertical, View.VISIBLE);
+ views.setViewVisibility(R.id.widget_icon, View.GONE);
+ }
+
+ // Show measurement name in >= four cell mode
+ if (minWidth >= fourCellsMinWidth) {
+ views.setTextViewText(R.id.widget_name, measurementView.getName());
+ views.setTextViewText(R.id.widget_date,
+ latest != null
+ ? DateFormat.getDateTimeInstance(
+ DateFormat.LONG, DateFormat.SHORT).format(latest.getDateTime())
+ : "");
+ views.setViewVisibility(R.id.widget_name_date_layout, View.VISIBLE);
+ }
+ else {
+ views.setViewVisibility(R.id.widget_name_date_layout, View.GONE);
+ }
+
+ // Always show value, but use smaller font in once cell mode
+ views.setTextViewText(R.id.widget_value, measurementView.getValueAsString(true));
+ SpannableStringBuilder delta = new SpannableStringBuilder();
+ measurementView.appendDiffValue(delta, false);
+ views.setTextViewText(R.id.widget_delta, delta.toString());
+
+ if (minWidth >= thirdCellsMinWidth) {
+ views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 18);
+ views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 17);
+ }
+ else if (minWidth >= twoCellsMinWidth) {
+ views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 17);
+ views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 15);
+ }
+ else {
+ views.setTextViewTextSize(R.id.widget_value, TypedValue.COMPLEX_UNIT_DIP, 15);
+ views.setTextViewTextSize(R.id.widget_delta, TypedValue.COMPLEX_UNIT_DIP, 13);
+ }
+
+ // Start main activity when widget is clicked
+ Intent intent = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
+ views.setOnClickPendingIntent(R.id.widget_layout, pendingIntent);
+
+ appWidgetManager.updateAppWidget(appWidgetId, views);
+ }
+
+ @Override
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
+ for (int appWidgetId : appWidgetIds) {
+ Bundle newOptions = appWidgetManager.getAppWidgetOptions(appWidgetId);
+ updateWidget(context, appWidgetManager, appWidgetId, newOptions);
+ }
+ }
+
+ @Override
+ public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager,
+ int appWidgetId, Bundle newOptions) {
+ updateWidget(context, appWidgetManager, appWidgetId, newOptions);
+ }
+
+ @Override
+ public void onDeleted(Context context, int[] appWidgetIds) {
+ SharedPreferences.Editor editor =
+ PreferenceManager.getDefaultSharedPreferences(context).edit();
+ for (int appWidgetId : appWidgetIds) {
+ editor.remove(getUserIdPreferenceName(appWidgetId));
+ editor.remove(getMeasurementPreferenceName(appWidgetId));
+ }
+ editor.apply();
+ }
+
+ @Override
+ public void onDisabled(Context context) {
+ measurementViews = null;
+ }
+
+ @Override
+ public void onRestored(Context context, int[] oldWidgetIds, int[] newWidgetIds) {
+ SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+
+ for (int i = 0; i < oldWidgetIds.length; ++i) {
+ String oldKey = getUserIdPreferenceName(oldWidgetIds[i]);
+ if (prefs.contains(oldKey)) {
+ editor.putInt(getUserIdPreferenceName(newWidgetIds[i]),
+ prefs.getInt(oldKey, -1));
+ editor.remove(oldKey);
+ }
+
+ oldKey = getMeasurementPreferenceName(oldWidgetIds[i]);
+ if (prefs.contains(oldKey)) {
+ editor.putString(getMeasurementPreferenceName(newWidgetIds[i]),
+ prefs.getString(oldKey, ""));
+ editor.remove(oldKey);
+ }
+ }
+
+ editor.apply();
+ }
+}
diff --git a/android_app/app/src/main/res/drawable-hdpi/appwidget_bg.9.png b/android_app/app/src/main/res/drawable-hdpi/appwidget_bg.9.png
new file mode 100644
index 00000000..ae6cec22
Binary files /dev/null and b/android_app/app/src/main/res/drawable-hdpi/appwidget_bg.9.png differ
diff --git a/android_app/app/src/main/res/drawable-mdpi/appwidget_bg.9.png b/android_app/app/src/main/res/drawable-mdpi/appwidget_bg.9.png
new file mode 100644
index 00000000..da8f77e3
Binary files /dev/null and b/android_app/app/src/main/res/drawable-mdpi/appwidget_bg.9.png differ
diff --git a/android_app/app/src/main/res/drawable-xhdpi/appwidget_bg.9.png b/android_app/app/src/main/res/drawable-xhdpi/appwidget_bg.9.png
new file mode 100644
index 00000000..69fa70c1
Binary files /dev/null and b/android_app/app/src/main/res/drawable-xhdpi/appwidget_bg.9.png differ
diff --git a/android_app/app/src/main/res/layout/widget.xml b/android_app/app/src/main/res/layout/widget.xml
new file mode 100644
index 00000000..2c10142b
--- /dev/null
+++ b/android_app/app/src/main/res/layout/widget.xml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android_app/app/src/main/res/layout/widget_configuration.xml b/android_app/app/src/main/res/layout/widget_configuration.xml
new file mode 100644
index 00000000..5cfd9b5d
--- /dev/null
+++ b/android_app/app/src/main/res/layout/widget_configuration.xml
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android_app/app/src/main/res/values/colors.xml b/android_app/app/src/main/res/values/colors.xml
index 17a99a01..4b79b104 100644
--- a/android_app/app/src/main/res/values/colors.xml
+++ b/android_app/app/src/main/res/values/colors.xml
@@ -7,4 +7,6 @@
#000000
@android:color/holo_blue_light
#000000
+
+ #555
diff --git a/android_app/app/src/main/res/values/strings.xml b/android_app/app/src/main/res/values/strings.xml
index 095f957c..38fd5d82 100644
--- a/android_app/app/src/main/res/values/strings.xml
+++ b/android_app/app/src/main/res/values/strings.xml
@@ -220,4 +220,7 @@
Development
Save debug log to file
Your Bluetooth scale
+ Select measurement
+ Select user
+ Configure widget
diff --git a/android_app/app/src/main/res/xml/widget_info.xml b/android_app/app/src/main/res/xml/widget_info.xml
new file mode 100644
index 00000000..1426ef88
--- /dev/null
+++ b/android_app/app/src/main/res/xml/widget_info.xml
@@ -0,0 +1,10 @@
+
+