1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-07-22 14:52:25 +02:00

Initial support for cyanogenmod/lineage weather provider

TODO:
- also reconstruct json for Pebble background js fake replies
- find a better location for settings
- interatively display candidates when looking up location
- grey out setting on non-cm/los devices
This commit is contained in:
Andreas Shimokawa 2017-12-11 19:09:37 +01:00
parent b7b96b5ab5
commit f0ac296492
21 changed files with 300 additions and 15 deletions

View File

@ -83,6 +83,7 @@ dependencies {
// version contains way too much and our custom patches are in the generator only.
compile 'org.greenrobot:greendao:2.2.1'
compile 'org.apache.commons:commons-lang3:3.5'
compile 'org.cyanogenmod:platform.sdk:6.0'
// compile project(":DaoCore")
}

View File

@ -19,6 +19,9 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="cyanogenmod.permission.ACCESS_WEATHER_MANAGER" />
<uses-permission android:name="cyanogenmod.permission.READ_WEATHER" />
<uses-feature
android:name="android.hardware.bluetooth"
android:required="true" />

View File

@ -47,6 +47,7 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandPreferencesActivity;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CMWeatherReceiver;
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
@ -259,6 +260,21 @@ public class SettingsActivity extends AbstractSettingsActivity {
}
});
pref = findPreference("weather_city");
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newVal) {
// reset city id and force a new lookup
GBApplication.getPrefs().getPreferences().edit().putString("weather_cityid",null).apply();
preference.setSummary(newVal.toString());
Intent intent = new Intent("GB_UPDATE_WEATHER");
intent.setPackage(CMWeatherReceiver.class.getCanonicalName());
sendBroadcast(intent);
return true;
}
});
// Get all receivers of Media Buttons
Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
@ -338,6 +354,7 @@ public class SettingsActivity extends AbstractSettingsActivity {
PREF_USER_WEIGHT_KG,
PREF_USER_SLEEP_DURATION,
PREF_USER_STEPS_GOAL,
"weather_city",
};
}

View File

@ -228,5 +228,10 @@ public interface DeviceCoordinator {
* This can be live HR, steps etc.
*/
boolean supportsRealtimeData();
/**
* Indicates whether the device supports current weather and/or weather
* forecast display.
*/
boolean supportsWeather();
}

View File

@ -176,4 +176,9 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
public boolean supportsRealtimeData() {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
}

View File

@ -98,6 +98,11 @@ public class HPlusCoordinator extends AbstractDeviceCoordinator {
return true;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
public DeviceType getDeviceType() {
return DeviceType.HPLUS;

View File

@ -63,4 +63,9 @@ public class AmazfitBipCoordinator extends HuamiCoordinator {
public boolean supportsHeartRateMeasurement(GBDevice device) {
return true;
}
@Override
public boolean supportsWeather() {
return true;
}
}

View File

@ -63,4 +63,9 @@ public class AmazfitCorCoordinator extends HuamiCoordinator {
public boolean supportsHeartRateMeasurement(GBDevice device) {
return true;
}
@Override
public boolean supportsWeather() {
return true;
}
}

View File

@ -73,4 +73,9 @@ public class MiBand2Coordinator extends HuamiCoordinator {
public boolean supportsHeartRateMeasurement(GBDevice device) {
return true;
}
@Override
public boolean supportsWeather() {
return false;
}
}

View File

@ -68,4 +68,9 @@ public class MiBand2HRXCoordinator extends HuamiCoordinator {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
}

View File

@ -84,6 +84,11 @@ public class TeclastH30Coordinator extends AbstractDeviceCoordinator {
return true;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
public DeviceType getDeviceType() {
return DeviceType.TECLASTH30;

View File

@ -23,7 +23,6 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
@ -35,6 +34,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
public class LiveviewCoordinator extends AbstractDeviceCoordinator {
@NonNull
@Override
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
String name = candidate.getDevice().getName();
@ -119,6 +119,11 @@ public class LiveviewCoordinator extends AbstractDeviceCoordinator {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
// nothing to delete, yet

View File

@ -171,6 +171,11 @@ public class MiBandCoordinator extends AbstractDeviceCoordinator {
return true;
}
@Override
public boolean supportsWeather() {
return false;
}
public static boolean hasValidUserInfo() {
String dummyMacAddress = MiBandService.MAC_ADDRESS_FILTER_1_1A + ":00:00:00";
try {

View File

@ -147,6 +147,11 @@ public class No1F1Coordinator extends AbstractDeviceCoordinator {
return false;
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
Long deviceId = device.getId();

View File

@ -155,4 +155,9 @@ public class PebbleCoordinator extends AbstractDeviceCoordinator {
public boolean supportsRealtimeData() {
return false;
}
@Override
public boolean supportsWeather() {
return true;
}
}

View File

@ -120,6 +120,11 @@ public class VibratissimoCoordinator extends AbstractDeviceCoordinator {
return false; // hmmm well, it has a temperature sensor :D
}
@Override
public boolean supportsWeather() {
return false;
}
@Override
protected void deleteDevice(@NonNull GBDevice gbDevice, @NonNull Device device, @NonNull DaoSession session) throws GBException {
// nothing to delete, yet

View File

@ -0,0 +1,194 @@
package nodomain.freeyourgadget.gadgetbridge.externalevents;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import cyanogenmod.weather.CMWeatherManager;
import cyanogenmod.weather.WeatherInfo;
import cyanogenmod.weather.WeatherLocation;
import cyanogenmod.weather.util.WeatherUtils;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.TempUnit.FAHRENHEIT;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.WeatherCode.ISOLATED_THUNDERSHOWERS;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.WeatherCode.NOT_AVAILABLE;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.WeatherCode.SCATTERED_SNOW_SHOWERS;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.WeatherCode.SCATTERED_THUNDERSTORMS;
import static cyanogenmod.providers.WeatherContract.WeatherColumns.WeatherCode.SHOWERS;
public class CMWeatherReceiver extends BroadcastReceiver implements CMWeatherManager.WeatherUpdateRequestListener, CMWeatherManager.LookupCityRequestListener {
private static final Logger LOG = LoggerFactory.getLogger(CMWeatherReceiver.class);
private WeatherLocation weatherLocation = null;
private Context mContext;
private PendingIntent mPendingIntent = null;
public CMWeatherReceiver() {
mContext = GBApplication.getContext();
final CMWeatherManager weatherManager = CMWeatherManager.getInstance(mContext);
if (weatherManager == null) {
return;
}
Prefs prefs = GBApplication.getPrefs();
String city = prefs.getString("weather_city", null);
String cityId = prefs.getString("weather_cityid", null);
if ((cityId == null || cityId.equals("")) && city != null && !city.equals("")) {
lookupCity(city);
} else if (city != null && cityId != null) {
weatherLocation = new WeatherLocation.Builder(cityId, city).build();
enablePeriodicAlarm(true);
}
}
private void lookupCity(String city) {
final CMWeatherManager weatherManager = CMWeatherManager.getInstance(mContext);
if (weatherManager == null) {
return;
}
if (city != null && !city.equals("")) {
if (weatherManager.getActiveWeatherServiceProviderLabel() != null) {
weatherManager.lookupCity(city, this);
}
}
}
private void enablePeriodicAlarm(boolean enable) {
if ((mPendingIntent != null && enable) || (mPendingIntent == null && !enable)) {
return;
}
AlarmManager am = (AlarmManager) (mContext.getSystemService(Context.ALARM_SERVICE));
if (am == null) {
LOG.warn("could not get alarm manager!");
return;
}
if (enable) {
mPendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("GB_UPDATE_WEATHER"), 0);
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 10000, AlarmManager.INTERVAL_HOUR, mPendingIntent);
} else {
am.cancel(mPendingIntent);
mPendingIntent = null;
}
}
@Override
public void onReceive(Context context, Intent intent) {
Prefs prefs = GBApplication.getPrefs();
String city = prefs.getString("weather_city", null);
String cityId = prefs.getString("weather_cityid", null);
if (city != null && !city.equals("") && cityId == null) {
lookupCity(city);
} else {
requestWeather();
}
}
private void requestWeather() {
final CMWeatherManager weatherManager = CMWeatherManager.getInstance(GBApplication.getContext());
if (weatherManager.getActiveWeatherServiceProviderLabel() != null && weatherLocation != null) {
weatherManager.requestWeatherUpdate(weatherLocation, this);
}
}
@Override
public void onWeatherRequestCompleted(int status, WeatherInfo weatherInfo) {
if (weatherInfo != null) {
LOG.info("weather: " + weatherInfo.toString());
WeatherSpec weatherSpec = new WeatherSpec();
weatherSpec.timestamp = (int) (weatherInfo.getTimestamp() / 1000);
weatherSpec.location = weatherInfo.getCity();
if (weatherInfo.getTemperatureUnit() == FAHRENHEIT) {
weatherSpec.currentTemp = (int) WeatherUtils.fahrenheitToCelsius(weatherInfo.getTemperature()) + 273;
weatherSpec.todayMaxTemp = (int) WeatherUtils.fahrenheitToCelsius(weatherInfo.getTodaysHigh()) + 273;
weatherSpec.todayMinTemp = (int) WeatherUtils.fahrenheitToCelsius(weatherInfo.getTodaysLow()) + 273;
} else {
weatherSpec.currentTemp = (int) weatherInfo.getTemperature() + 273;
weatherSpec.todayMaxTemp = (int) weatherInfo.getTodaysHigh() + 273;
weatherSpec.todayMinTemp = (int) weatherInfo.getTodaysLow() + 273;
}
weatherSpec.currentConditionCode = Weather.mapToOpenWeatherMapCondition(CMtoYahooCondintion(weatherInfo.getConditionCode()));
weatherSpec.currentCondition = Weather.getConditionString(weatherSpec.currentConditionCode);
weatherSpec.forecasts = new ArrayList<>();
List<WeatherInfo.DayForecast> forecasts = weatherInfo.getForecasts();
for (int i = 1; i < forecasts.size(); i++) {
WeatherInfo.DayForecast cmForecast = forecasts.get(i);
WeatherSpec.Forecast gbForecast = new WeatherSpec.Forecast();
if (weatherInfo.getTemperatureUnit() == FAHRENHEIT) {
gbForecast.maxTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getHigh()) + 273;
gbForecast.minTemp = (int) WeatherUtils.fahrenheitToCelsius(cmForecast.getLow()) + 273;
} else {
gbForecast.maxTemp = (int) cmForecast.getHigh() + 273;
gbForecast.minTemp = (int) cmForecast.getLow() + 273;
}
gbForecast.conditionCode = Weather.mapToOpenWeatherMapCondition(CMtoYahooCondintion(cmForecast.getConditionCode()));
weatherSpec.forecasts.add(gbForecast);
}
Weather.getInstance().setWeatherSpec(weatherSpec);
GBApplication.deviceService().onSendWeather(weatherSpec);
} else {
LOG.info("request has returned null for WeatherInfo");
}
}
/**
* @param cmCondition
* @return
*/
private int CMtoYahooCondintion(int cmCondition) {
int yahooCondition;
if (cmCondition <= SHOWERS) {
yahooCondition = cmCondition;
} else if (cmCondition <= SCATTERED_THUNDERSTORMS) {
yahooCondition = cmCondition + 1;
} else if (cmCondition <= SCATTERED_SNOW_SHOWERS) {
yahooCondition = cmCondition + 2;
} else if (cmCondition <= ISOLATED_THUNDERSHOWERS) {
yahooCondition = cmCondition + 3;
} else {
yahooCondition = NOT_AVAILABLE;
}
return yahooCondition;
}
@Override
public void onLookupCityRequestCompleted(int result, List<WeatherLocation> list) {
if (list != null) {
weatherLocation = list.get(0);
String cityId = weatherLocation.getCityId();
String city = weatherLocation.getCity();
SharedPreferences.Editor editor = GBApplication.getPrefs().getPreferences().edit();
editor.putString("weather_city", city).apply();
editor.putString("weather_cityid", cityId).apply();
enablePeriodicAlarm(true);
requestWeather();
} else {
enablePeriodicAlarm(false);
}
}
}

View File

@ -50,7 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmClockReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.AlarmReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothConnectReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.BluetoothPairingRequestReceiver;
//import nodomain.freeyourgadget.gadgetbridge.externalevents.CMWeatherReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CMWeatherReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver;
@ -174,7 +174,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
private AlarmReceiver mAlarmReceiver = null;
private CalendarReceiver mCalendarReceiver = null;
//private CMWeatherReceiver mCMWeatherReceiver = null;
private CMWeatherReceiver mCMWeatherReceiver = null;
private Random mRandom = new Random();
private final String[] mMusicActions = {
@ -659,12 +659,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
filter.addAction(AlarmClockReceiver.ALARM_DONE_ACTION);
registerReceiver(mAlarmClockReceiver, filter);
}
/*
if (mCMWeatherReceiver == null) {
if (mCMWeatherReceiver == null && coordinator != null && coordinator.supportsWeather()) {
mCMWeatherReceiver = new CMWeatherReceiver();
registerReceiver(mCMWeatherReceiver, new IntentFilter("HOURLY_ALARM"));
registerReceiver(mCMWeatherReceiver, new IntentFilter("GB_UPDATE_WEATHER"));
}
*/
} else {
if (mPhoneCallReceiver != null) {
unregisterReceiver(mPhoneCallReceiver);
@ -699,12 +697,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
unregisterReceiver(mAlarmClockReceiver);
mAlarmClockReceiver = null;
}
/*
if (mCMWeatherReceiver != null) {
unregisterReceiver(mCMWeatherReceiver);
mCMWeatherReceiver = null;
}
*/
}
}

View File

@ -43,7 +43,7 @@ public class ParcelableWeather2 implements Parcelable {
if (version != 2) {
return;
}
Bundle bundle = in.readBundle();
Bundle bundle = in.readBundle(getClass().getClassLoader());
weatherSpec.location = bundle.getString("weather_location");
long time = bundle.getLong("weather_time");
@ -52,7 +52,7 @@ public class ParcelableWeather2 implements Parcelable {
bundle.getString("weather_forecast_url");
int conditions = bundle.getInt("weather_conditions");
if (conditions > 0) {
Bundle conditionBundle = in.readBundle();
Bundle conditionBundle = in.readBundle(getClass().getClassLoader());
reconstructedOWMWeather = new JSONObject();
JSONArray weather = new JSONArray();
JSONObject condition = new JSONObject();
@ -63,7 +63,9 @@ public class ParcelableWeather2 implements Parcelable {
weatherSpec.currentTemp = conditionBundle.getInt("weather_current_temp");
String[] currentConditionType = conditionBundle.getStringArray("weather_condition_types");
weatherSpec.currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]);
if (currentConditionType != null) {
weatherSpec.currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]);
}
weatherSpec.todayMinTemp = conditionBundle.getInt("weather_low_temp");
weatherSpec.todayMaxTemp = conditionBundle.getInt("weather_high_temp");
try {
@ -96,9 +98,12 @@ public class ParcelableWeather2 implements Parcelable {
condition = new JSONObject();
main = new JSONObject();
weather = new JSONArray();
Bundle forecastBundle = in.readBundle();
Bundle forecastBundle = in.readBundle(getClass().getClassLoader());
String[] forecastConditionType = forecastBundle.getStringArray("weather_condition_types");
int forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]);
int forecastConditionCode = 0;
if (forecastConditionType != null) {
forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]);
}
int forecastLowTemp = forecastBundle.getInt("weather_low_temp");
int forecastHighTemp = forecastBundle.getInt("weather_high_temp");
weatherSpec.forecasts.add(new WeatherSpec.Forecast(forecastLowTemp, forecastHighTemp, forecastConditionCode));

View File

@ -110,6 +110,7 @@
<string name="pref_call_privacy_mode_number">Hide number but display name</string>
<string name="pref_call_privacy_mode_complete">Hide name and number</string>
<string name="pref_title_weather_location">Weather location</string>
<string name="pref_blacklist">Blacklist Apps</string>
<string name="pref_blacklist_calendars">Blacklist Calendars</string>

View File

@ -41,6 +41,9 @@
android:key="measurement_system"
android:summary="%s"
android:title="@string/pref_title_unit_system" />
<EditTextPreference
android:key="weather_city"
android:title="@string/pref_title_weather_location" />
<CheckBoxPreference
android:defaultValue="false"
android:key="minimize_priority"