Drop support for outdated app weather notification

This commit is contained in:
Daniele Gobbetti
2025-07-20 11:50:56 +02:00
committed by José Rebelo
parent 34812c02db
commit 86e53f0e85
9 changed files with 0 additions and 455 deletions
-16
View File
@@ -562,22 +562,6 @@
</intent-filter>
</receiver>
<receiver
android:name=".externalevents.WeatherNotificationReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_UPDATE_2" />
</intent-filter>
</receiver>
<activity android:name=".externalevents.WeatherNotificationConfig"
android:exported="true">
<intent-filter>
<action android:name="ru.gelin.android.weather.notification.ACTION_WEATHER_SKIN_PREFERENCES" />
</intent-filter>
</activity>
<receiver
android:name=".externalevents.AutoStartReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED"
@@ -526,7 +526,6 @@ public abstract class AbstractAppManagerFragment extends Fragment {
if (!PebbleProtocol.UUID_WEATHER.equals(selectedApp.getUUID())) {
menu.removeItem(R.id.appmanager_weather_activate);
menu.removeItem(R.id.appmanager_weather_deactivate);
menu.removeItem(R.id.appmanager_weather_install_provider);
}
if (selectedApp.getType() == GBDeviceApp.Type.APP_SYSTEM || selectedApp.getType() == GBDeviceApp.Type.WATCHFACE_SYSTEM) {
menu.removeItem(R.id.appmanager_app_delete);
@@ -535,17 +534,6 @@ public abstract class AbstractAppManagerFragment extends Fragment {
menu.removeItem(R.id.appmanager_app_configure);
}
if (PebbleProtocol.UUID_WEATHER.equals(selectedApp.getUUID())) {
PackageManager pm = getActivity().getPackageManager();
try {
pm.getPackageInfo("ru.gelin.android.weather.notification", PackageManager.GET_ACTIVITIES);
menu.removeItem(R.id.appmanager_weather_install_provider);
} catch (PackageManager.NameNotFoundException e) {
//menu.removeItem(R.id.appmanager_weather_activate);
//menu.removeItem(R.id.appmanager_weather_deactivate);
}
}
if ((mGBDevice.getType() != DeviceType.FOSSILQHYBRID) || (selectedApp.getType() != GBDeviceApp.Type.WATCHFACE)) {
menu.removeItem(R.id.appmanager_app_edit);
}
@@ -638,9 +626,6 @@ public abstract class AbstractAppManagerFragment extends Fragment {
} else if (itemId == R.id.appmanager_health_deactivate || itemId == R.id.appmanager_hrm_deactivate || itemId == R.id.appmanager_weather_deactivate) {
GBApplication.deviceService(mGBDevice).onAppDelete(selectedApp.getUUID());
return true;
} else if (itemId == R.id.appmanager_weather_install_provider) {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://f-droid.org/app/ru.gelin.android.weather.notification")));
return true;
} else if (itemId == R.id.appmanager_app_configure) {
GBApplication.deviceService(mGBDevice).onAppStart(selectedApp.getUUID(), true);
@@ -1,31 +0,0 @@
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniele
Gobbetti
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.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.os.Bundle;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
public class WeatherNotificationConfig extends AbstractGBActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_weather_notification);
}
}
@@ -1,64 +0,0 @@
/* Copyright (C) 2015-2024 Andreas Shimokawa, Daniele Gobbetti
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.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Collections;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import ru.gelin.android.weather.notification.ParcelableWeather2;
public class WeatherNotificationReceiver extends BroadcastReceiver {
private static final Logger LOG = LoggerFactory.getLogger(WeatherNotificationReceiver.class);
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == null || !intent.getAction().contains("WEATHER_UPDATE_2")) {
LOG.info("Wrong action");
return;
}
ParcelableWeather2 parcelableWeather2 = null;
try {
parcelableWeather2 = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER");
} catch (RuntimeException e) {
LOG.error("cannot get ParcelableWeather2", e);
}
if (parcelableWeather2 != null) {
Weather weather = Weather.INSTANCE;
weather.setReconstructedOWMForecast(parcelableWeather2.reconstructedOWMForecast);
WeatherSpec weatherSpec = parcelableWeather2.weatherSpec;
LOG.info("weather in " + weatherSpec.location + " is " + weatherSpec.currentCondition + " (" + (weatherSpec.currentTemp - 273) + "°C)");
ArrayList<WeatherSpec> weatherSpecs = new ArrayList<>(Collections.singletonList(weatherSpec));
Weather.INSTANCE.setWeatherSpec(weatherSpecs);
GBApplication.deviceService().onSendWeather(weatherSpecs);
}
}
}
@@ -10,7 +10,6 @@ object Weather {
private val LOG = LoggerFactory.getLogger("Weather")
private val weatherSpecs = CopyOnWriteArrayList<WeatherSpec>()
private var reconstructedOWMForecast: JSONObject? = null
private var cacheManager: WeatherCacheManager? = null
@@ -62,12 +61,6 @@ object Weather {
}
}
fun getReconstructedOWMForecast(): JSONObject? = reconstructedOWMForecast
fun setReconstructedOWMForecast(value: JSONObject?) {
reconstructedOWMForecast = value
}
fun initializeCache(cacheManager: WeatherCacheManager) {
this.cacheManager = cacheManager
@@ -1,291 +0,0 @@
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniele
Gobbetti, José Rebelo, Petr Vaněk, Taavi Eomäe
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.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package ru.gelin.android.weather.notification;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherMapper;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
public class ParcelableWeather2 implements Parcelable {
private static final Logger LOG = LoggerFactory.getLogger(ParcelableWeather2.class);
// getters and setters suck ;)
public WeatherSpec weatherSpec = new WeatherSpec();
public JSONObject reconstructedOWMForecast = null;
private ParcelableWeather2(Parcel in) {
int version = in.readInt();
if (version != 2) {
return;
}
Bundle bundle = in.readBundle(getClass().getClassLoader());
weatherSpec.location = bundle.getString("weather_location");
long time = bundle.getLong("weather_time");
long queryTime = bundle.getLong("weather_query_time");
weatherSpec.timestamp = (int) (queryTime / 1000);
bundle.getString("weather_forecast_url");
int conditions = bundle.getInt("weather_conditions");
if (conditions > 0) {
Bundle conditionBundle = in.readBundle(getClass().getClassLoader());
weatherSpec.currentCondition = conditionBundle.getString("weather_condition_text");
conditionBundle.getStringArray("weather_condition_types");
weatherSpec.currentTemp = conditionBundle.getInt("weather_current_temp");
weatherSpec.windDirection = mapDirToDeg(conditionBundle.getString("weather_wind_direction"));
weatherSpec.windSpeed = getSpeedInKMH(conditionBundle.getInt("weather_wind_speed"),
conditionBundle.getString("weather_wind_speed_unit"));
String[] currentConditionType = conditionBundle.getStringArray("weather_condition_types");
if (currentConditionType != null) {
weatherSpec.currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]);
}
weatherSpec.todayMinTemp = conditionBundle.getInt("weather_low_temp");
weatherSpec.todayMaxTemp = conditionBundle.getInt("weather_high_temp");
weatherSpec.currentHumidity = conditionBundle.getInt("weather_humidity_value");
//fetch forecasts
int timeOffset = 0;
JSONArray list = new JSONArray();
JSONObject city = new JSONObject();
while (--conditions > 0) {
timeOffset += 86400; //manually determined
JSONObject item = new JSONObject();
JSONObject condition = new JSONObject();
JSONObject main = new JSONObject();
JSONArray weather = new JSONArray();
Bundle forecastBundle = in.readBundle(getClass().getClassLoader());
String[] forecastConditionType = forecastBundle.getStringArray("weather_condition_types");
int forecastConditionCode = 0;
if (forecastConditionType != null && forecastConditionType.length > 0) {
forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]);
}
int forecastLowTemp = forecastBundle.getInt("weather_low_temp");
int forecastHighTemp = forecastBundle.getInt("weather_high_temp");
int forecastHumidity = forecastBundle.getInt("weather_humidity_value");
WeatherSpec.Daily daily = new WeatherSpec.Daily();
daily.minTemp = forecastLowTemp;
daily.maxTemp = forecastHighTemp;
daily.conditionCode = forecastConditionCode;
daily.humidity = forecastHumidity;
weatherSpec.forecasts.add(daily);
try {
condition.put("id", forecastConditionCode);
condition.put("main", forecastBundle.getString("weather_condition_text"));
condition.put("description", forecastBundle.getString("weather_condition_text"));
condition.put("icon", WeatherMapper.INSTANCE.mapToOpenWeatherMapIcon(forecastConditionCode));
weather.put(condition);
main.put("temp", forecastBundle.getInt("weather_current_temp"));
main.put("humidity", forecastHumidity);
main.put("temp_min", forecastLowTemp);
main.put("temp_max", forecastHighTemp);
//forecast
item.put("dt", (time / 1000) + timeOffset);
item.put("main", main);
item.put("weather", weather);
list.put(item);
} catch (JSONException e) {
LOG.error("error while construction JSON", e);
}
}
try {
//"city":{"id":3181913,"name":"Bolzano","coord":{"lat":46.4927,"lon":11.3336},"country":"IT"}
city.put("name", weatherSpec.location);
city.put("country", "World");
reconstructedOWMForecast = new JSONObject();
reconstructedOWMForecast.put("city", city);
reconstructedOWMForecast.put("cnt", list.length());
reconstructedOWMForecast.put("list", list);
} catch (JSONException e) {
LOG.error("error while construction JSON", e);
}
LOG.debug("Forecast JSON for Webview: " + reconstructedOWMForecast);
}
}
public static final Creator<ParcelableWeather2> CREATOR = new Creator<ParcelableWeather2>() {
@Override
public ParcelableWeather2 createFromParcel(Parcel in) {
return new ParcelableWeather2(in);
}
@Override
public ParcelableWeather2[] newArray(int size) {
return new ParcelableWeather2[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
// we do not really want to use this at all
}
private int weatherConditionTypesToOpenWeatherMapIds(String weather_condition_type) {
switch (weather_condition_type) {
case "THUNDERSTORM_RAIN_LIGHT":
return 200;
case "THUNDERSTORM_RAIN":
return 201;
case "THUNDERSTORM_RAIN_HEAVY":
return 202;
case "THUNDERSTORM_LIGHT":
return 210;
case "THUNDERSTORM":
return 211;
case "THUNDERSTORM_HEAVY":
return 212;
case "THUNDERSTORM_RAGGED":
return 221;
case "THUNDERSTORM_DRIZZLE_LIGHT":
return 230;
case "THUNDERSTORM_DRIZZLE":
return 231;
case "THUNDERSTORM_DRIZZLE_HEAVY":
return 232;
case "DRIZZLE_LIGHT":
return 300;
case "DRIZZLE":
return 301;
case "DRIZZLE_HEAVY":
return 302;
case "DRIZZLE_RAIN_LIGHT":
return 310;
case "DRIZZLE_RAIN":
return 311;
case "DRIZZLE_RAIN_HEAVY":
return 312;
case "DRIZZLE_SHOWER":
return 321;
case "RAIN_LIGHT":
return 500;
case "RAIN":
return 501;
case "RAIN_HEAVY":
return 502;
case "RAIN_VERY_HEAVY":
return 503;
case "RAIN_EXTREME":
return 504;
case "RAIN_FREEZING":
return 511;
case "RAIN_SHOWER_LIGHT":
return 520;
case "RAIN_SHOWER":
return 521;
case "RAIN_SHOWER_HEAVY":
return 522;
case "SNOW_LIGHT":
return 600;
case "SNOW":
return 601;
case "SNOW_HEAVY":
return 602;
case "SLEET":
return 611;
case "SNOW_SHOWER":
return 621;
case "MIST":
return 701;
case "SMOKE":
return 711;
case "HAZE":
return 721;
case "SAND_WHIRLS":
return 731;
case "FOG":
return 741;
case "CLOUDS_CLEAR":
return 800;
case "CLOUDS_FEW":
return 801;
case "CLOUDS_SCATTERED":
return 802;
case "CLOUDS_BROKEN":
return 803;
case "CLOUDS_OVERCAST":
return 804;
case "TORNADO":
return 900;
case "TROPICAL_STORM":
return 901;
case "HURRICANE":
return 902;
case "COLD":
return 903;
case "HOT":
return 904;
case "WINDY":
return 905;
case "HAIL":
return 906;
}
return 3200;
}
private int getSpeedInKMH(int speed, String incomingUnit) {
float kmhSpeed = 0;
switch (incomingUnit) {
case "MPS":
kmhSpeed = speed * 3.6f;
break;
case "MPH":
kmhSpeed = speed * 1.6093f;
break;
case "KPH":
kmhSpeed = speed;
break;
}
return Math.round(kmhSpeed);
}
private int mapDirToDeg(String dir) {
return Math.round(WindDirection.valueOf(dir).ordinal() * 22.5f);
}
private enum WindDirection { // see upstream code, we can't be more precise than getting the quadrant
N, NNE, NE, ENE, E, ESE, SE, SSE, S, SSW, SW, WSW, W, WNW, NW, NNW
}
}
@@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp">
<TextView
android:text="Weather on your Pebble"
android:textAlignment="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="20dp" />
<androidx.legacy.widget.Space
android:layout_width="match_parent"
android:layout_height="@dimen/activity_vertical_margin" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/weather_notification_label"
android:text="@string/weather_notification_label" />
</LinearLayout>
@@ -42,9 +42,6 @@
<item
android:id="@+id/appmanager_weather_deactivate"
android:title="@string/appmanager_weather_deactivate" />
<item
android:id="@+id/appmanager_weather_install_provider"
android:title="@string/appmanager_weather_install_provider" />
<item
android:id="@+id/appmanager_app_configure"
android:title="@string/app_configure"/>
-2
View File
@@ -122,7 +122,6 @@
<string name="appmanager_hrm_deactivate">Deactivate HRM</string>
<string name="appmanager_weather_activate">Activate System Weather app</string>
<string name="appmanager_weather_deactivate">Deactivate System Weather app</string>
<string name="appmanager_weather_install_provider">Install the Weather Notification app</string>
<string name="app_configure">Configure</string>
<string name="app_move_to_top">Move to top</string>
<string name="appmanager_item_outdated">(outdated)</string>
@@ -1386,7 +1385,6 @@
<!-- Strings related to Pebble Pairing Activity-->
<string name="title_activity_pebble_pairing">Pebble pairing</string>
<string name="pebble_pairing_hint">A pairing dialog will pop up on your Android device. If not, look in the notification drawer and accept the pairing request. Also accept it on your Pebble afterwards.</string>
<string name="weather_notification_label">Make sure that this skin is enabled in the Weather Notification app to get weather information on your Pebble.\n\nNo configuration is needed here.\n\nYou can enable the system weather app of your Pebble from the app management.\n\nSupported watchfaces will show the weather automatically.</string>
<string name="pref_title_setup_bt_pairing">Enable Bluetooth pairing</string>
<string name="pref_summary_setup_bt_pairing">Deactivate this if you have trouble connecting</string>
<string name="unit_metric">Metric</string>