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

Merge branch 'master' into bip-wip

This commit is contained in:
Andreas Shimokawa 2017-12-11 19:30:54 +01:00
commit bfceaf9cc9
59 changed files with 1692 additions and 337 deletions

View File

@ -12,11 +12,11 @@ android:
components:
# Uncomment the lines below if you want to
# use the latest revision of Android SDK Tools
# - platform-tools
- platform-tools
- tools
# The BuildTools version used by your project
- build-tools-25.0.2
- build-tools-26.0.2
# The SDK version used to compile your project
- android-25

View File

@ -1,5 +1,17 @@
### Changelog
#### Version 0.22.5
* Unlock Teclast H10 support using the same code as H30
* Amazfit Bip: Fix installation of 0.1.0.11 Firmware
* Amazfit Bip/Cor: Send three days of weather forecast including (untranslated) conditions
* Workaround for a crash on Android 4.4 when connecting
#### Version 0.22.4
* Mi Band 2/Bip/Cor: Whole day HR support
* Mi Band 2/Bip/Cor: Prevent writing a lot of HR samples to the database when not using the live activity feature
* Pebble: Fix some nasty crashes which occur since 0.22.0
* Workround for non-working notifcations from wechat and outlook
#### Version 0.22.3
* Amazfit Bip: Allow flashing watchfaces
* Amazfit Cor: Fix flashing new .res files

View File

@ -26,8 +26,8 @@ android {
targetSdkVersion 25
// note: always bump BOTH versionCode and versionName!
versionName "0.22.3"
versionCode 111
versionName "0.22.5"
versionCode 113
vectorDrawables.useSupportLibrary = true
}
buildTypes {
@ -60,19 +60,21 @@ dependencies {
// testCompile 'ch.qos.logback:logback-classic:1.1.3'
// testCompile 'ch.qos.logback:logback-core:1.1.3'
testCompile 'junit:junit:4.12'
testCompile "org.mockito:mockito-core:1.9.5"
testCompile "org.robolectric:robolectric:3.3.2"
testCompile "org.mockito:mockito-core:1.10.19"
testCompile "org.robolectric:robolectric:3.5.1"
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.android.support:cardview-v7:25.3.1'
compile 'com.android.support:recyclerview-v7:25.3.1'
compile 'com.android.support:support-v4:25.3.1'
compile 'com.android.support:gridlayout-v7:25.3.1'
compile 'com.android.support:design:25.3.1'
compile 'com.android.support:palette-v7:25.3.1'
compile 'com.github.tony19:logback-android-classic:1.1.1-6'
compile 'org.slf4j:slf4j-api:1.7.7'
compile 'com.android.support:appcompat-v7:25.4.0'
compile 'com.android.support:cardview-v7:25.4.0'
compile 'com.android.support:recyclerview-v7:25.4.0'
compile 'com.android.support:support-v4:25.4.0'
compile 'com.android.support:gridlayout-v7:25.4.0'
compile 'com.android.support:design:25.4.0'
compile 'com.android.support:palette-v7:25.4.0'
compile('com.github.tony19:logback-android-classic:1.1.1-6') {
exclude group: 'com.google.android', module: 'android'
}
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'com.github.PhilJay:MPAndroidChart:v3.0.2'
compile 'com.github.pfichtner:durationformatter:0.1.1'
compile 'de.cketti.library.changelog:ckchangelog:1.2.2'
@ -81,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

@ -236,4 +236,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

@ -68,4 +68,9 @@ public class AmazfitBipCoordinator extends HuamiCoordinator {
public boolean supportsActivityTracks() {
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

@ -63,7 +63,7 @@ public class TeclastH30Coordinator extends AbstractDeviceCoordinator {
@Override
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
String name = candidate.getDevice().getName();
if (name != null && name.startsWith("TECLAST_H30")) {
if (name != null && (name.startsWith("TECLAST_H30") || name.startsWith("TECLAST_H10"))) {
return DeviceType.TECLASTH30;
}
return DeviceType.UNKNOWN;
@ -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

@ -54,7 +54,12 @@ public class AlarmReceiver extends BroadcastReceiver {
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, new Intent("DAILY_ALARM"), 0);
AlarmManager am = (AlarmManager) (context.getSystemService(Context.ALARM_SERVICE));
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 10000, AlarmManager.INTERVAL_DAY, pendingIntent);
if (am != null) {
am.setInexactRepeating(AlarmManager.RTC_WAKEUP, Calendar.getInstance().getTimeInMillis() + 10000, AlarmManager.INTERVAL_DAY, pendingIntent);
}
else {
LOG.warn("could not get alarm manager!");
}
}
@Override

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

@ -394,7 +394,7 @@ public class NotificationListener extends NotificationListenerService {
}
return shouldIgnoreSource(sbn.getPackageName()) || shouldIgnoreNotification(
sbn.getNotification());
sbn.getNotification(), sbn.getPackageName());
}
@ -432,16 +432,21 @@ public class NotificationListener extends NotificationListenerService {
return false;
}
private boolean shouldIgnoreNotification(Notification notification) {
private boolean shouldIgnoreNotification(Notification notification, String source) {
MediaSessionCompat.Token mediaSession = NotificationCompat.getMediaSession(notification);
//try to handle media session notifications
if (mediaSession != null && handleMediaSessionNotification(mediaSession))
return true;
NotificationType type = AppNotificationType.getInstance().get(source);
//ignore notifications marked as LocalOnly https://developer.android.com/reference/android/app/Notification.html#FLAG_LOCAL_ONLY
if (NotificationCompat.getLocalOnly(notification))
//some Apps always mark their notifcations as read-only
if (NotificationCompat.getLocalOnly(notification) &&
type != NotificationType.WECHAT &&
type != NotificationType.OUTLOOK) {
return true;
}
Prefs prefs = GBApplication.getPrefs();
if (!prefs.getBoolean("notifications_generic_whenscreenon", false)) {

View File

@ -26,6 +26,9 @@ import android.os.Bundle;
import android.os.PowerManager;
import android.telephony.SmsMessage;
import java.util.LinkedHashMap;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
@ -54,12 +57,22 @@ public class SMSReceiver extends BroadcastReceiver {
if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
if (pdus != null) {
for (Object pdu1 : pdus) {
byte[] pdu = (byte[]) pdu1;
SmsMessage message = SmsMessage.createFromPdu(pdu);
notificationSpec.body = message.getDisplayMessageBody();
notificationSpec.phoneNumber = message.getOriginatingAddress();
if (notificationSpec.phoneNumber != null) {
int pduSize = pdus.length;
Map<String, StringBuilder> messageMap = new LinkedHashMap<>();
SmsMessage[] messages = new SmsMessage[pduSize];
for (int i = 0; i < pduSize; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);
String originatingAddress = messages[i].getOriginatingAddress();
if (!messageMap.containsKey(originatingAddress)) {
messageMap.put(originatingAddress, new StringBuilder());
}
messageMap.get(originatingAddress).append(messages[i].getMessageBody());
}
for (Map.Entry<String, StringBuilder> entry : messageMap.entrySet()) {
String originatingAddress = entry.getKey();
if (originatingAddress != null) {
notificationSpec.body = entry.getValue().toString();
notificationSpec.phoneNumber = originatingAddress;
switch (GBApplication.getGrantedInterruptionFilter()) {
case NotificationManager.INTERRUPTION_FILTER_ALL:
break;

View File

@ -35,32 +35,25 @@ public class WeatherNotificationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (!intent.getAction().contains("WEATHER_UPDATE_2")) {
if (intent.getAction() == null || !intent.getAction().contains("WEATHER_UPDATE_2")) {
LOG.info("Wrong action");
return;
}
ParcelableWeather2 weather = null;
ParcelableWeather2 parcelableWeather2 = null;
try {
weather = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER");
parcelableWeather2 = intent.getParcelableExtra("ru.gelin.android.weather.notification.EXTRA_WEATHER");
} catch (RuntimeException e) {
e.printStackTrace();
LOG.error("cannot get ParcelableWeather2", e);
}
if (weather != null) {
Weather.getInstance().setWeather2(weather);
LOG.info("weather in " + weather.location + " is " + weather.currentCondition + " (" + (weather.currentTemp - 273) + "°C)");
if (parcelableWeather2 != null) {
Weather weather = Weather.getInstance();
weather.setReconstructedOWMWeather(parcelableWeather2.reconstructedOWMWeather);
weather.setReconstructedOWMForecast(parcelableWeather2.reconstructedOWMForecast);
WeatherSpec weatherSpec = parcelableWeather2.weatherSpec;
LOG.info("weather in " + weatherSpec.location + " is " + weatherSpec.currentCondition + " (" + (weatherSpec.currentTemp - 273) + "°C)");
WeatherSpec weatherSpec = new WeatherSpec();
weatherSpec.timestamp = (int) (weather.queryTime / 1000);
weatherSpec.location = weather.location;
weatherSpec.currentTemp = weather.currentTemp;
weatherSpec.currentCondition = weather.currentCondition;
weatherSpec.currentConditionCode = weather.currentConditionCode;
weatherSpec.todayMaxTemp = weather.todayHighTemp;
weatherSpec.todayMinTemp = weather.todayLowTemp;
weatherSpec.tomorrowConditionCode = weather.forecastConditionCode;
weatherSpec.tomorrowMaxTemp = weather.forecastHighTemp;
weatherSpec.tomorrowMinTemp = weather.forecastLowTemp;
Weather.getInstance().setWeatherSpec(weatherSpec);
GBApplication.deviceService().onSendWeather(weatherSpec);
}

View File

@ -373,16 +373,7 @@ public class GBDeviceService implements DeviceService {
@Override
public void onSendWeather(WeatherSpec weatherSpec) {
Intent intent = createIntent().setAction(ACTION_SEND_WEATHER)
.putExtra(EXTRA_WEATHER_TIMESTAMP, weatherSpec.timestamp)
.putExtra(EXTRA_WEATHER_LOCATION, weatherSpec.location)
.putExtra(EXTRA_WEATHER_CURRENTTEMP, weatherSpec.currentTemp)
.putExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, weatherSpec.currentConditionCode)
.putExtra(EXTRA_WEATHER_CURRENTCONDITION, weatherSpec.currentCondition)
.putExtra(EXTRA_WEATHER_TODAYMAXTEMP, weatherSpec.todayMaxTemp)
.putExtra(EXTRA_WEATHER_TODAYMINTEMP, weatherSpec.todayMinTemp)
.putExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, weatherSpec.tomorrowMaxTemp)
.putExtra(EXTRA_WEATHER_TOMORROWMINTEMP, weatherSpec.tomorrowMinTemp)
.putExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, weatherSpec.tomorrowConditionCode);
.putExtra(EXTRA_WEATHER, weatherSpec);
invokeService(intent);
}

View File

@ -84,6 +84,7 @@ public class AppNotificationType extends HashMap<String, NotificationType> {
// Facebook Messenger
put("com.facebook.orca", NotificationType.FACEBOOK_MESSENGER);
put("com.facebook.mlite", NotificationType.FACEBOOK_MESSENGER);
// WhatsApp
put("com.whatsapp", NotificationType.WHATSAPP);

View File

@ -104,16 +104,7 @@ public interface DeviceService extends EventHandler {
String EXTRA_BOOLEAN_ENABLE = "enable_realtime_steps";
String EXTRA_INTERVAL_SECONDS = "interval_seconds";
String EXTRA_WEATHER_TIMESTAMP = "weather_timestamp";
String EXTRA_WEATHER_LOCATION = "weather_location";
String EXTRA_WEATHER_CURRENTTEMP = "weather_currenttemp";
String EXTRA_WEATHER_CURRENTCONDITIONCODE = "weather_currentconditioncode";
String EXTRA_WEATHER_CURRENTCONDITION = "currentcondition";
String EXTRA_WEATHER_TODAYMAXTEMP = "weather_todaymaxtemp";
String EXTRA_WEATHER_TODAYMINTEMP = "weather_todaymintemp";
String EXTRA_WEATHER_TOMORROWMAXTEMP = "weather_tomorrowmaxtemp";
String EXTRA_WEATHER_TOMORROWMINTEMP = "weather_tomorrowmintemp";
String EXTRA_WEATHER_TOMORROWCONDITIONCODE = "weather_tomorrowconditioncode";
String EXTRA_WEATHER = "weather";
/**
* Use EXTRA_REALTIME_SAMPLE instead

View File

@ -16,19 +16,13 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.model;
import ru.gelin.android.weather.notification.ParcelableWeather2;
import org.json.JSONObject;
public class Weather {
private ParcelableWeather2 weather2 = null;
private WeatherSpec weatherSpec = null;
public ParcelableWeather2 getWeather2() {
return weather2;
}
public void setWeather2(ParcelableWeather2 weather2) {
this.weather2 = weather2;
}
private JSONObject reconstructedOWMWeather = null;
private JSONObject reconstructedOWMForecast = null;
public WeatherSpec getWeatherSpec() {
return weatherSpec;
@ -38,6 +32,22 @@ public class Weather {
this.weatherSpec = weatherSpec;
}
public JSONObject getReconstructedOWMWeather() {
return reconstructedOWMWeather;
}
public void setReconstructedOWMWeather(JSONObject reconstructedOWMWeather) {
this.reconstructedOWMWeather = reconstructedOWMWeather;
}
public JSONObject getReconstructedOWMForecast() {
return reconstructedOWMForecast;
}
public void setReconstructedOWMForecast(JSONObject reconstructedOWMForecast) {
this.reconstructedOWMForecast = reconstructedOWMForecast;
}
private static final Weather weather = new Weather();
public static Weather getInstance() {return weather;}
@ -393,4 +403,164 @@ public class Weather {
return -1;
}
}
public static String getConditionString(int openWeatherMapCondition) {
switch (openWeatherMapCondition) {
case 200:
return "thunderstorm with light rain";
case 201:
return "thunderstorm with rain";
case 202:
return "thunderstorm with heavy rain";
case 210:
return "light thunderstorm:";
case 211:
return "thunderstorm";
case 230:
return "thunderstorm with light drizzle";
case 231:
return "thunderstorm with drizzle";
case 232:
return "thunderstorm with heavy drizzle";
case 212:
return "heavy thunderstorm";
case 221:
return "ragged thunderstorm";
//Group 3xx: Drizzle
case 300:
return "light intensity drizzle";
case 301:
return "drizzle";
case 302:
return "heavy intensity drizzle";
case 310:
return "light intensity drizzle rain";
case 311:
return "drizzle rain";
case 312:
return "heavy intensity drizzle rain";
case 313:
return "shower rain and drizzle";
case 314:
return "heavy shower rain and drizzle";
case 321:
return "shower drizzle";
//Group 5xx: Rain
case 500:
return "light rain";
case 501:
return "moderate rain";
case 502:
return "heavy intensity rain";
case 503:
return "very heavy rain";
case 504:
return "extreme rain";
case 511:
return "freezing rain";
case 520:
return "light intensity shower rain";
case 521:
return "shower rain";
case 522:
return "heavy intensity shower rain";
case 531:
return "ragged shower rain";
//Group 6xx: Snow
case 600:
return "light snow";
case 601:
return "snow";
case 620:
return "light shower snow";
case 602:
return "heavy snow";
case 611:
return "sleet";
case 612:
return "shower sleet";
case 621:
return "shower snow";
case 622:
return "heavy shower snow";
case 615:
return "light rain and snow";
case 616:
return "rain and snow";
//Group 7xx: Atmosphere
case 701:
return "mist";
case 711:
return "smoke";
case 721:
return "haze";
case 731:
return "sandcase dust whirls";
case 741:
return "fog";
case 751:
return "sand";
case 761:
return "dust";
case 762:
return "volcanic ash";
case 771:
return "squalls";
case 781:
return "tornado";
case 900:
return "tornado";
case 800:
return "clear sky";
//Group 80x: Clouds
case 801:
return "few clouds";
case 802:
return "scattered clouds";
case 803:
return "broken clouds";
case 804:
return "overcast clouds";
//Group 90x: Extreme
case 901:
return "tropical storm";
case 903:
return "cold";
case 904:
return "hot";
case 905:
return "windy";
case 906:
return "hail";
//Group 9xx: Additional
case 951:
return "calm";
case 952:
return "light breeze";
case 953:
return "gentle breeze";
case 954:
return "moderate breeze";
case 955:
return "fresh breeze";
case 956:
return "strong breeze";
case 957:
return "high windcase near gale";
case 958:
return "gale";
case 959:
return "severe gale";
case 960:
return "storm";
case 961:
return "violent storm";
case 902:
return "hurricane";
case 962:
return "hurricane";
default:
return "";
}
}
}

View File

@ -16,16 +16,106 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.model;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
// FIXME: document me and my fields, including units
public class WeatherSpec {
public class WeatherSpec implements Parcelable {
public static final Creator<WeatherSpec> CREATOR = new Creator<WeatherSpec>() {
@Override
public WeatherSpec createFromParcel(Parcel in) {
return new WeatherSpec(in);
}
@Override
public WeatherSpec[] newArray(int size) {
return new WeatherSpec[size];
}
};
public int timestamp;
public String location;
public int currentTemp;
public int currentConditionCode;
public int currentConditionCode = 3200;
public String currentCondition;
public int todayMaxTemp;
public int todayMinTemp;
public int tomorrowMaxTemp;
public int tomorrowMinTemp;
public int tomorrowConditionCode;
public ArrayList<Forecast> forecasts = new ArrayList<>();
public WeatherSpec() {
}
protected WeatherSpec(Parcel in) {
timestamp = in.readInt();
location = in.readString();
currentTemp = in.readInt();
currentConditionCode = in.readInt();
currentCondition = in.readString();
todayMaxTemp = in.readInt();
todayMinTemp = in.readInt();
in.readList(forecasts, Forecast.class.getClassLoader());
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(timestamp);
dest.writeString(location);
dest.writeInt(currentTemp);
dest.writeInt(currentConditionCode);
dest.writeString(currentCondition);
dest.writeInt(todayMaxTemp);
dest.writeInt(todayMinTemp);
dest.writeList(forecasts);
}
public static class Forecast implements Parcelable {
public static final Creator<Forecast> CREATOR = new Creator<Forecast>() {
@Override
public Forecast createFromParcel(Parcel in) {
return new Forecast(in);
}
@Override
public Forecast[] newArray(int size) {
return new Forecast[size];
}
};
public int minTemp;
public int maxTemp;
public int conditionCode;
public Forecast() {
}
public Forecast(int minTemp, int maxTemp, int conditionCode) {
this.minTemp = minTemp;
this.maxTemp = maxTemp;
this.conditionCode = conditionCode;
}
Forecast(Parcel in) {
minTemp = in.readInt();
maxTemp = in.readInt();
conditionCode = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(minTemp);
dest.writeInt(maxTemp);
dest.writeInt(conditionCode);
}
}
}

View File

@ -50,6 +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.CalendarReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.MusicPlaybackReceiver;
import nodomain.freeyourgadget.gadgetbridge.externalevents.PebbleReceiver;
@ -149,16 +150,7 @@ import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOT
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_NOTIFICATION_TYPE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_URI;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_VIBRATION_INTENSITY;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITION;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTCONDITIONCODE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_CURRENTTEMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_LOCATION;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TIMESTAMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMAXTEMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TODAYMINTEMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWCONDITIONCODE;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMAXTEMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER_TOMORROWMINTEMP;
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.EXTRA_WEATHER;
public class DeviceCommunicationService extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final Logger LOG = LoggerFactory.getLogger(DeviceCommunicationService.class);
@ -182,6 +174,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
private AlarmReceiver mAlarmReceiver = null;
private CalendarReceiver mCalendarReceiver = null;
private CMWeatherReceiver mCMWeatherReceiver = null;
private Random mRandom = new Random();
private final String[] mMusicActions = {
@ -214,7 +207,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(GBDevice.ACTION_DEVICE_CHANGED)) {
if (GBDevice.ACTION_DEVICE_CHANGED.equals(action)) {
GBDevice device = intent.getParcelableExtra(GBDevice.EXTRA_DEVICE);
if (mGBDevice != null && mGBDevice.equals(device)) {
mGBDevice = device;
@ -540,18 +533,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
break;
}
case ACTION_SEND_WEATHER: {
WeatherSpec weatherSpec = new WeatherSpec();
weatherSpec.timestamp = intent.getIntExtra(EXTRA_WEATHER_TIMESTAMP, 0);
weatherSpec.location = intent.getStringExtra(EXTRA_WEATHER_LOCATION);
weatherSpec.currentTemp = intent.getIntExtra(EXTRA_WEATHER_CURRENTTEMP, 0);
weatherSpec.currentConditionCode = intent.getIntExtra(EXTRA_WEATHER_CURRENTCONDITIONCODE, 0);
weatherSpec.currentCondition = intent.getStringExtra(EXTRA_WEATHER_CURRENTCONDITION);
weatherSpec.todayMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMAXTEMP, 0);
weatherSpec.todayMinTemp = intent.getIntExtra(EXTRA_WEATHER_TODAYMINTEMP, 0);
weatherSpec.tomorrowMaxTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMAXTEMP, 0);
weatherSpec.tomorrowMinTemp = intent.getIntExtra(EXTRA_WEATHER_TOMORROWMINTEMP, 0);
weatherSpec.tomorrowConditionCode = intent.getIntExtra(EXTRA_WEATHER_TOMORROWCONDITIONCODE, 0);
mDeviceSupport.onSendWeather(weatherSpec);
WeatherSpec weatherSpec = intent.getParcelableExtra(EXTRA_WEATHER);
if (weatherSpec != null) {
mDeviceSupport.onSendWeather(weatherSpec);
}
break;
}
}
@ -674,6 +659,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
filter.addAction(AlarmClockReceiver.ALARM_DONE_ACTION);
registerReceiver(mAlarmClockReceiver, filter);
}
if (mCMWeatherReceiver == null && coordinator != null && coordinator.supportsWeather()) {
mCMWeatherReceiver = new CMWeatherReceiver();
registerReceiver(mCMWeatherReceiver, new IntentFilter("GB_UPDATE_WEATHER"));
}
} else {
if (mPhoneCallReceiver != null) {
unregisterReceiver(mPhoneCallReceiver);
@ -708,6 +697,10 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
unregisterReceiver(mAlarmClockReceiver);
mAlarmClockReceiver = null;
}
if (mCMWeatherReceiver != null) {
unregisterReceiver(mCMWeatherReceiver);
mCMWeatherReceiver = null;
}
}
}
@ -725,7 +718,9 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
setDeviceSupport(null);
NotificationManager nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
nm.cancel(GB.NOTIFICATION_ID); // need to do this because the updated notification won't be cancelled when service stops
if (nm != null) {
nm.cancel(GB.NOTIFICATION_ID); // need to do this because the updated notification won't be cancelled when service stops
}
}
@Override

View File

@ -36,12 +36,19 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo {
(byte) 0xa7, 0x26, (byte) 0xd0, (byte) 0xe6, 0x4a, 0x21, (byte) 0x88, (byte) 0xd4
};
// guessed - at least it is the same accross current versions and different from other devices
// guessed - at least it is the same across versions from 0.0.7.x to 0.0.9.x
// and different from other devices
private static final byte[] FW_HEADER = new byte[]{
0x68, 0x46, 0x70, 0x47, 0x68, 0x46, 0x70, 0x47,
0x68, 0x46, 0x70, 0x47, 0x68, 0x46, 0x70, 0x47
};
// guessed - this is true for 0.1.0.11
private static final byte[] FW_HEADER_NEW = new byte[]{
0x60, (byte) 0xeb, 0x03, 0x0c, 0x70, 0x46, 0x31, 0x46,
0x3a, 0x46, 0x63, 0x46, (byte) 0xbd, (byte) 0xe8, (byte) 0xf0, (byte) 0x81
};
private static final int FW_HEADER_OFFSET = 0x9330;
private static final byte[] GPS_ALMANAC_HEADER = new byte[]{ // probably wrong
@ -63,6 +70,9 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo {
crcToVersion.put(55420, "0.0.9.14");
crcToVersion.put(39465, "0.0.9.26");
crcToVersion.put(27394, "0.0.9.40");
crcToVersion.put(24736, "0.0.9.49");
crcToVersion.put(49555, "0.0.9.59");
crcToVersion.put(26714, "0.1.0.11");
// resources
crcToVersion.put(12586, "RES 0.0.8.74");
@ -70,6 +80,7 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo {
crcToVersion.put(59839, "RES 0.0.8.96-98");
crcToVersion.put(50401, "RES 0.0.9.14-26");
crcToVersion.put(22051, "RES 0.0.9.40");
crcToVersion.put(46233, "RES 0.0.9.49-0.1.0.11");
// gps
crcToVersion.put(61520, "GPS 9367,8f79a91,0,0,");
@ -97,7 +108,7 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo {
if (ArrayUtils.startsWith(bytes, GPS_CEP_HEADER)) {
return HuamiFirmwareType.GPS_CEP;
}
if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET)) {
if (ArrayUtils.equals(bytes, FW_HEADER, FW_HEADER_OFFSET) || ArrayUtils.equals(bytes, FW_HEADER_NEW, FW_HEADER_OFFSET)) {
// TODO: this is certainly not a correct validation, but it works for now
return HuamiFirmwareType.FIRMWARE;
}

View File

@ -40,6 +40,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBand2Service;
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
@ -126,31 +127,90 @@ public class AmazfitBipSupport extends MiBand2Support {
if (gbDevice.getFirmwareVersion() == null) {
LOG.warn("Device not initialized yet, so not sending weather info");
return;
}
boolean supportsConditionString = false;
Version version = new Version(gbDevice.getFirmwareVersion());
if (version.compareTo(new Version("0.0.8.74")) >= 0) {
supportsConditionString = true;
}
int tz_offset_hours = SimpleTimeZone.getDefault().getOffset(weatherSpec.timestamp * 1000L) / (1000 * 60 * 60);
try {
TransactionBuilder builder;
builder = performInitialized("Sending current temp");
byte condition = HuamiWeatherConditions.mapToAmazfitBipWeatherCode(weatherSpec.currentConditionCode);
int length = 8;
if (supportsConditionString) {
length += weatherSpec.currentCondition.getBytes().length + 1;
}
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put((byte) 2);
buf.putInt(weatherSpec.timestamp);
buf.put((byte) (tz_offset_hours * 4));
buf.put(condition);
buf.put((byte) (weatherSpec.currentTemp - 273));
if (supportsConditionString) {
buf.put(weatherSpec.currentCondition.getBytes());
buf.put((byte) 0);
}
builder.write(getCharacteristic(AmazfitBipService.UUID_CHARACTERISTIC_WEATHER), buf.array());
builder.queue(getQueue());
} catch (Exception ex) {
LOG.error("Error sending current weather", ex);
}
try {
TransactionBuilder builder;
builder = performInitialized("Sending air quality index");
int length = 8;
String aqiString = "(fake)";
if (supportsConditionString) {
length += aqiString.getBytes().length + 1;
}
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put((byte) 4);
buf.putInt(weatherSpec.timestamp);
buf.put((byte) (tz_offset_hours * 4));
buf.putShort((short) 0);
if (supportsConditionString) {
buf.put(aqiString.getBytes());
buf.put((byte) 0);
}
builder.write(getCharacteristic(AmazfitBipService.UUID_CHARACTERISTIC_WEATHER), buf.array());
builder.queue(getQueue());
} catch (IOException ex) {
LOG.error("Error sending air quality");
}
try {
TransactionBuilder builder = performInitialized("Sending weather forecast");
boolean supportsConditionString = false;
Version version = new Version(gbDevice.getFirmwareVersion());
if (version.compareTo(new Version("0.0.8.74")) >= 0) {
supportsConditionString = true;
}
final byte NR_DAYS = 2;
final byte NR_DAYS = (byte) (1 + weatherSpec.forecasts.size());
int bytesPerDay = 4;
int conditionsLength = 0;
if (supportsConditionString) {
bytesPerDay = 5;
conditionsLength = weatherSpec.currentCondition.getBytes().length;
for (WeatherSpec.Forecast forecast : weatherSpec.forecasts) {
conditionsLength += Weather.getConditionString(forecast.conditionCode).getBytes().length;
}
}
int length = 7 + bytesPerDay * NR_DAYS + conditionsLength;
ByteBuffer buf = ByteBuffer.allocate(length);
buf.order(ByteOrder.LITTLE_ENDIAN);
buf.put((byte) 1);
buf.putInt(weatherSpec.timestamp);
int tz_offset_hours = SimpleTimeZone.getDefault().getOffset(weatherSpec.timestamp * 1000L) / (1000 * 60 * 60);
buf.put((byte) (tz_offset_hours * 4));
buf.put(NR_DAYS);
@ -162,22 +222,26 @@ public class AmazfitBipSupport extends MiBand2Support {
buf.put((byte) (weatherSpec.todayMinTemp - 273));
if (supportsConditionString) {
buf.put(weatherSpec.currentCondition.getBytes());
buf.put((byte) 0); //
buf.put((byte) 0);
}
condition = HuamiWeatherConditions.mapToAmazfitBipWeatherCode(weatherSpec.tomorrowConditionCode);
buf.put(condition);
buf.put(condition);
buf.put((byte) (weatherSpec.tomorrowMaxTemp - 273));
buf.put((byte) (weatherSpec.tomorrowMinTemp - 273));
if (supportsConditionString) {
buf.put((byte) 0); // not yet in weatherspec
for (WeatherSpec.Forecast forecast : weatherSpec.forecasts) {
condition = HuamiWeatherConditions.mapToAmazfitBipWeatherCode(forecast.conditionCode);
buf.put(condition);
buf.put(condition);
buf.put((byte) (forecast.maxTemp - 273));
buf.put((byte) (forecast.minTemp - 273));
if (supportsConditionString) {
buf.put(Weather.getConditionString(forecast.conditionCode).getBytes());
buf.put((byte) 0);
}
}
builder.write(getCharacteristic(AmazfitBipService.UUID_CHARACTERISTIC_WEATHER), buf.array());
builder.queue(getQueue());
} catch (Exception ex) {
LOG.error("Error sending weather information to the Bip", ex);
LOG.error("Error sending weather forecast", ex);
}
}

View File

@ -24,8 +24,10 @@ public class HuamiDeviceEvent {
public static final byte BUTTON_PRESSED = 0x04;
public static final byte START_NONWEAR = 0x06;
public static final byte CALL_REJECT = 0x07;
public static final byte CALL_ACCEPT = 0x09;
public static final byte FIND_PHONE_START = 0x08;
public static final byte CALL_IGNORE = 0x09;
public static final byte ALARM_TOGGLED = 0x0a;
public static final byte BUTTON_PRESSED_LONG = 0x0b;
public static final byte TICK_30MIN = 0x0e; // unsure
public static final byte FIND_PHONE_STOP = 0x0f;
}

View File

@ -17,6 +17,8 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Map;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -41,7 +43,41 @@ public abstract class HuamiFirmwareInfo {
private HuamiFirmwareType firmwareType = HuamiFirmwareType.FIRMWARE;
public String toVersion(int crc16) {
return getCrcMap().get(crc16);
String version = getCrcMap().get(crc16);
if (version == null) {
if (firmwareType == HuamiFirmwareType.FIRMWARE) {
version = searchFirmwareVersion(bytes);
}
else if (firmwareType == HuamiFirmwareType.RES) {
version = "RES " + Integer.toString(bytes[5]);
}
else if (firmwareType == HuamiFirmwareType.RES_NEW) {
version = "RES " + Integer.toString(bytes[14]);
}
}
if (version == null) {
switch (firmwareType) {
case FIRMWARE:
version = "(unknown)";
break;
case FONT:
version = "(unknown font)";
break;
case GPS:
version = "(unknown GPS)";
break;
case GPS_CEP:
version = "(unknown CEP)";
break;
case GPS_ALMANAC:
version = "(unknown ALM)";
break;
case WATCHFACE:
version = "(unknown watchface)";
break;
}
}
return version;
}
public int[] getWhitelistedVersions() {
@ -52,12 +88,9 @@ public abstract class HuamiFirmwareInfo {
private byte[] bytes;
private String firmwareVersion;
public HuamiFirmwareInfo(byte[] bytes) {
this.bytes = bytes;
crc16 = CheckSums.getCRC16(bytes);
firmwareVersion = getCrcMap().get(crc16);
firmwareType = determineFirmwareType(bytes);
}
@ -98,4 +131,28 @@ public abstract class HuamiFirmwareInfo {
protected abstract Map<Integer, String> getCrcMap();
protected abstract HuamiFirmwareType determineFirmwareType(byte[] bytes);
protected String searchFirmwareVersion(byte[] fwbytes) {
ByteBuffer buf = ByteBuffer.wrap(fwbytes);
buf.order(ByteOrder.BIG_ENDIAN);
while (buf.remaining() > 3) {
int word = buf.getInt();
if (word == 0x5625642e) {
word = buf.getInt();
if (word == 0x25642e25) {
word = buf.getInt();
if (word == 0x642e2564) {
word = buf.getInt();
if (word == 0x00000000) {
byte version[] = new byte[8];
buf.get(version);
return new String(version);
}
}
}
}
}
return null;
}
}

View File

@ -47,7 +47,8 @@ public class Mi2FirmwareInfo extends HuamiFirmwareInfo {
private static final int FW_HEADER_OFFSET = 0x150;
protected static Map<Integer,String> crcToVersion = new HashMap<>();
protected static Map<Integer, String> crcToVersion = new HashMap<>();
static {
// firmware
crcToVersion.put(41899, "1.0.0.39");
@ -55,6 +56,7 @@ public class Mi2FirmwareInfo extends HuamiFirmwareInfo {
crcToVersion.put(32450, "1.0.1.28");
crcToVersion.put(51770, "1.0.1.34");
crcToVersion.put(3929, "1.0.1.39");
crcToVersion.put(47364, "1.0.1.54");
// fonts
crcToVersion.put(45624, "Font");
@ -83,4 +85,10 @@ public class Mi2FirmwareInfo extends HuamiFirmwareInfo {
protected Map<Integer, String> getCrcMap() {
return crcToVersion;
}
@Override
protected String searchFirmwareVersion(byte[] fwbytes) {
// does not work for Mi Band 2
return null;
}
}

View File

@ -283,10 +283,6 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_3_CONFIGURATION), enable);
builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_6_BATTERY_INFO), enable);
builder.notify(getCharacteristic(MiBand2Service.UUID_CHARACTERISTIC_DEVICEEVENT), enable);
BluetoothGattCharacteristic heartrateCharacteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT);
if (heartrateCharacteristic != null) {
builder.notify(heartrateCharacteristic, enable);
}
return this;
}
@ -764,11 +760,15 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
}
try {
TransactionBuilder builder = performInitialized("Enable realtime heart rate measurement");
BluetoothGattCharacteristic heartrateCharacteristic = getCharacteristic(GattCharacteristic.UUID_CHARACTERISTIC_HEART_RATE_MEASUREMENT);
if (heartrateCharacteristic != null) {
builder.notify(heartrateCharacteristic, enable);
}
if (enable) {
builder.write(characteristicHRControlPoint, stopHeartMeasurementManual);
builder.write(characteristicHRControlPoint, startHeartMeasurementContinuous);
} else {
builder.write(getCharacteristic(MiBandService.UUID_CHARACTERISTIC_HEART_RATE_CONTROL_POINT), stopHeartMeasurementContinuous);
builder.write(characteristicHRControlPoint, stopHeartMeasurementContinuous);
}
builder.queue(getQueue());
enableRealtimeSamplesTimer(enable);
@ -935,9 +935,10 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
callCmd.event = GBDeviceEventCallControl.Event.REJECT;
evaluateGBDeviceEvent(callCmd);
break;
case HuamiDeviceEvent.CALL_ACCEPT:
callCmd.event = GBDeviceEventCallControl.Event.ACCEPT;
evaluateGBDeviceEvent(callCmd);
case HuamiDeviceEvent.CALL_IGNORE:
LOG.info("ignore call (not yet supported)");
//callCmd.event = GBDeviceEventCallControl.Event.IGNORE;
//evaluateGBDeviceEvent(callCmd);
break;
case HuamiDeviceEvent.BUTTON_PRESSED:
LOG.info("button pressed");
@ -964,6 +965,12 @@ public class MiBand2Support extends AbstractBTLEDeviceSupport {
case HuamiDeviceEvent.TICK_30MIN:
LOG.info("Tick 30 min (?)");
break;
case HuamiDeviceEvent.FIND_PHONE_START:
LOG.info("find phone started (not yet supported)");
break;
case HuamiDeviceEvent.FIND_PHONE_STOP:
LOG.info("find phone stopped (not yet supported)");
break;
default:
LOG.warn("unhandled event " + value[0]);
}

View File

@ -28,7 +28,7 @@ import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.devices.pebble.PebbleColor;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
import ru.gelin.android.weather.notification.ParcelableWeather2;
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
class AppMessageHandlerPebStyle extends AppMessageHandler {
public static final int KEY_AMPM_TEXT = 21;
@ -92,7 +92,7 @@ class AppMessageHandlerPebStyle extends AppMessageHandler {
//WEATHER
ParcelableWeather2 weather = Weather.getInstance().getWeather2();
WeatherSpec weather = Weather.getInstance().getWeatherSpec();
if (weather != null) {
//comment the same key in the general section above!
pairs.add(new Pair<>(KEY_LOCATION_SERVICE, (Object) 0)); //0 auto, 1 manual

View File

@ -141,7 +141,12 @@ class AppMessageHandlerTimeStylePebble extends AppMessageHandler {
pairs.add(new Pair<>(messageKeys.get("WeatherUseNightIcon"), (Object) (isNight ? 1 : 0)));
pairs.add(new Pair<>(messageKeys.get("WeatherTemperature"), (Object) (weatherSpec.currentTemp - 273)));
pairs.add(new Pair<>(messageKeys.get("WeatherCondition"), (Object) (getIconForConditionCode(weatherSpec.currentConditionCode, isNight))));
pairs.add(new Pair<>(messageKeys.get("WeatherForecastCondition"), (Object) (getIconForConditionCode(weatherSpec.tomorrowConditionCode, isNight))));
if (weatherSpec.forecasts.size() > 0) {
WeatherSpec.Forecast tomorrow = weatherSpec.forecasts.get(0);
pairs.add(new Pair<>(messageKeys.get("WeatherForecastCondition"), (Object) (getIconForConditionCode(tomorrow.conditionCode, isNight))));
}
pairs.add(new Pair<>(messageKeys.get("WeatherForecastHighTemp"), (Object) (weatherSpec.todayMaxTemp - 273)));
pairs.add(new Pair<>(messageKeys.get("WeatherForecastLowTemp"), (Object) (weatherSpec.todayMinTemp - 273)));

View File

@ -45,9 +45,9 @@ class PebbleKitSupport {
private static final String PEBBLEKIT_ACTION_APP_STOP = "com.getpebble.action.app.STOP";
private static final String PEBBLEKIT_ACTION_DL_RECEIVE_DATA_NEW = "com.getpebble.action.dl.RECEIVE_DATA_NEW";
private static final String PEBBLEKIT_ACTION_DL_RECEIVE_DATA = "com.getpebble.action.dl.RECEIVE_DATA";
//private static final String PEBBLEKIT_ACTION_DL_RECEIVE_DATA = "com.getpebble.action.dl.RECEIVE_DATA";
private static final String PEBBLEKIT_ACTION_DL_ACK_DATA = "com.getpebble.action.dl.ACK_DATA";
private static final String PEBBLEKIT_ACTION_DL_REQUEST_DATA = "com.getpebble.action.dl.REQUEST_DATA";
//private static final String PEBBLEKIT_ACTION_DL_REQUEST_DATA = "com.getpebble.action.dl.REQUEST_DATA";
private static final String PEBBLEKIT_ACTION_DL_FINISH_SESSION = "com.getpebble.action.dl.FINISH_SESSION_NEW";
private static final Logger LOG = LoggerFactory.getLogger(PebbleKitSupport.class);
@ -62,6 +62,10 @@ class PebbleKitSupport {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
LOG.warn("got empty action from PebbleKit Intent - ignoring");
return;
}
LOG.info("Got action: " + action);
UUID uuid;
switch (action) {
@ -85,7 +89,7 @@ class PebbleKitSupport {
sendAppMessageAck(transaction_id);
// }
} catch (JSONException e) {
e.printStackTrace();
LOG.error("failed decoding JSON", e);
}
break;
case PEBBLEKIT_ACTION_APP_ACK:
@ -101,7 +105,9 @@ class PebbleKitSupport {
case PEBBLEKIT_ACTION_DL_ACK_DATA:
LOG.info("GOT DL DATA ACK");
break;
default:
LOG.warn("Unhandled PebbleKit action: " + action);
break;
}
}
};

View File

@ -1227,8 +1227,16 @@ public class PebbleProtocol extends GBDeviceProtocol {
short currentTemp = (short) (weatherSpec.currentTemp - 273);
short todayMax = (short) (weatherSpec.todayMaxTemp - 273);
short todayMin = (short) (weatherSpec.todayMinTemp - 273);
short tomorrowMax = (short) (weatherSpec.tomorrowMaxTemp - 273);
short tomorrowMin = (short) (weatherSpec.tomorrowMinTemp - 273);
short tomorrowMax = 0;
short tomorrowMin = 0;
int tomorrowConditionCode = 0;
if (weatherSpec.forecasts.size() > 0) {
WeatherSpec.Forecast tomorrow = weatherSpec.forecasts.get(0);
tomorrowMax = (short) (tomorrow.maxTemp - 273);
tomorrowMin = (short) (tomorrow.minTemp - 273);
tomorrowConditionCode = tomorrow.conditionCode;
}
String units = GBApplication.getPrefs().getString(SettingsActivity.PREF_MEASUREMENT_SYSTEM, GBApplication.getContext().getString(R.string.p_unit_metric));
if (units.equals(GBApplication.getContext().getString(R.string.p_unit_imperial))) {
currentTemp = (short) (currentTemp * 1.8f + 32);
@ -1261,7 +1269,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
buf.put(Weather.mapToPebbleCondition(weatherSpec.currentConditionCode));
buf.putShort(todayMax);
buf.putShort(todayMin);
buf.put(Weather.mapToPebbleCondition(weatherSpec.tomorrowConditionCode));
buf.put(Weather.mapToPebbleCondition(tomorrowConditionCode));
buf.putShort(tomorrowMax);
buf.putShort(tomorrowMin);
buf.putInt(weatherSpec.timestamp);
@ -1986,7 +1994,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
}
}
idLookup[last_id] = ext_id;
idLookup[last_id & 0xff] = ext_id;
return buf.array();
}
@ -2023,6 +2031,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
break;
}
} catch (JSONException e) {
LOG.error("error decoding JSON", e);
return null;
}
}
@ -2632,14 +2641,14 @@ public class PebbleProtocol extends GBDeviceProtocol {
LOG.info("got APPLICATIONMESSAGE/LAUNCHER (EP " + endpoint + ") NACK");
}
GBDeviceEventAppMessage evtAppMessage = null;
if (endpoint == ENDPOINT_APPLICATIONMESSAGE && idLookup[last_id] != null) {
if (endpoint == ENDPOINT_APPLICATIONMESSAGE && idLookup[last_id & 0xff] != null) {
evtAppMessage = new GBDeviceEventAppMessage();
if (pebbleCmd == APPLICATIONMESSAGE_ACK) {
evtAppMessage.type = GBDeviceEventAppMessage.TYPE_ACK;
} else {
evtAppMessage.type = GBDeviceEventAppMessage.TYPE_NACK;
}
evtAppMessage.id = idLookup[last_id];
evtAppMessage.id = idLookup[last_id & 0xff];
evtAppMessage.appUUID = currentRunningApp;
}
devEvts = new GBDeviceEvent[]{evtAppMessage};

View File

@ -30,13 +30,16 @@ import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
class CurrentPosition {
public class CurrentPosition {
private static final Logger LOG = LoggerFactory.getLogger(CurrentPosition.class);
private Location lastKnownLocation;
private float latitude, longitude;
long timestamp;
double altitude;
float latitude, longitude, accuracy, speed;
float accuracy, speed;
float getLatitude() {
return latitude;
@ -46,10 +49,19 @@ class CurrentPosition {
return longitude;
}
CurrentPosition() {
public Location getLastKnownLocation() {
return lastKnownLocation;
}
public CurrentPosition() {
Prefs prefs = GBApplication.getPrefs();
this.latitude = prefs.getFloat("location_latitude", 0);
this.longitude = prefs.getFloat("location_longitude", 0);
lastKnownLocation = new Location("preferences");
lastKnownLocation.setLatitude(this.latitude);
lastKnownLocation.setLongitude(this.longitude);
LOG.info("got longitude/latitude from preferences: " + latitude + "/" + longitude);
this.timestamp = System.currentTimeMillis() - 86400000; //let accessor know this value is really old
@ -58,10 +70,14 @@ class CurrentPosition {
prefs.getBoolean("use_updated_location_if_available", false)) {
LocationManager locationManager = (LocationManager) GBApplication.getContext().getSystemService(Context.LOCATION_SERVICE);
Criteria criteria = new Criteria();
String provider = locationManager.getBestProvider(criteria, false);
String provider = null;
if (locationManager != null) {
provider = locationManager.getBestProvider(criteria, false);
}
if (provider != null) {
Location lastKnownLocation = locationManager.getLastKnownLocation(provider);
if (lastKnownLocation != null) {
this.lastKnownLocation = lastKnownLocation;
this.timestamp = lastKnownLocation.getTime();
this.timestamp = System.currentTimeMillis() - 1000; //TODO: request updating the location and don't fake its age

View File

@ -132,7 +132,7 @@ public class GBWebClient extends WebViewClient {
private static WebResourceResponse mimicOpenWeatherMapResponse(String type, String units) {
if (Weather.getInstance() == null || Weather.getInstance().getWeather2() == null) {
if (Weather.getInstance() == null) {
LOG.warn("WEBVIEW - Weather instance is null, cannot update weather");
return null;
}
@ -142,8 +142,8 @@ public class GBWebClient extends WebViewClient {
try {
JSONObject resp;
if ("/data/2.5/weather".equals(type) && Weather.getInstance().getWeather2().reconstructedWeather != null) {
resp = new JSONObject(Weather.getInstance().getWeather2().reconstructedWeather.toString());
if ("/data/2.5/weather".equals(type) && Weather.getInstance().getReconstructedOWMWeather() != null) {
resp = new JSONObject(Weather.getInstance().getReconstructedOWMWeather().toString());
JSONObject main = resp.getJSONObject("main");
@ -152,8 +152,8 @@ public class GBWebClient extends WebViewClient {
resp.put("cod", 200);
resp.put("coord", coordObject(currentPosition));
resp.put("sys", sysObject(currentPosition));
// } else if ("/data/2.5/forecast".equals(type) && Weather.getInstance().getWeather2().reconstructedForecast != null) { //this is wrong, as we only have daily data. Unfortunately it looks like daily forecasts cannot be reconstructed
// resp = new JSONObject(Weather.getInstance().getWeather2().reconstructedForecast.toString());
// } else if ("/data/2.5/forecast".equals(type) && Weather.getInstance().getWeather2().reconstructedOWMForecast != null) { //this is wrong, as we only have daily data. Unfortunately it looks like daily forecasts cannot be reconstructed
// resp = new JSONObject(Weather.getInstance().getWeather2().reconstructedOWMForecast.toString());
//
// JSONObject city = resp.getJSONObject("city");
// city.put("coord", coordObject(currentPosition));

View File

@ -227,8 +227,8 @@ public class JSInterface {
geoPosition.put("timestamp", currentPosition.timestamp);
coords.put("latitude", currentPosition.latitude);
coords.put("longitude", currentPosition.longitude);
coords.put("latitude", currentPosition.getLatitude());
coords.put("longitude", currentPosition.getLongitude());
coords.put("accuracy", currentPosition.accuracy);
coords.put("altitude", currentPosition.altitude);
coords.put("speed", currentPosition.speed);

View File

@ -96,7 +96,7 @@ public class GB {
deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_DISCONNECT);
PendingIntent disconnectPendingIntent = PendingIntent.getService(context, 0, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT);
builder.addAction(R.drawable.ic_notification_disconnected, context.getString(R.string.controlcenter_disconnect), disconnectPendingIntent);
if (DeviceHelper.getInstance().getCoordinator(device).supportsActivityDataFetching()) {
if (GBApplication.isRunningLollipopOrLater() && DeviceHelper.getInstance().getCoordinator(device).supportsActivityDataFetching()) { //for some reason this fails on KK
deviceCommunicationServiceIntent.setAction(DeviceService.ACTION_FETCH_ACTIVITY_DATA);
PendingIntent fetchPendingIntent = PendingIntent.getService(context, 1, deviceCommunicationServiceIntent, PendingIntent.FLAG_ONE_SHOT);
builder.addAction(R.drawable.ic_action_fetch_activity_data, context.getString(R.string.controlcenter_fetch_activity_data), fetchPendingIntent);
@ -122,6 +122,7 @@ public class GB {
.setContentText(text)
.setSmallIcon(R.drawable.ic_notification_disconnected)
.setContentIntent(getContentIntent(context))
.setColor(context.getResources().getColor(R.color.accent))
.setOngoing(true);
if (GBApplication.getPrefs().getString("last_device_address", null) != null) {
Intent deviceCommunicationServiceIntent = new Intent(context, DeviceCommunicationService.class);

View File

@ -27,92 +27,86 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.model.Weather;
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 long time = 0;
public long queryTime = 0;
public int version = 0;
public String location = "";
public int currentTemp = 0;
public String currentCondition = "";
private String[] currentConditionType = null;
public int currentConditionCode = 3200;
private String[] forecastConditionType = null;
public int forecastConditionCode = 3200;
public int todayLowTemp = 0;
public int todayHighTemp = 0;
public int forecastLowTemp = 0;
public int forecastHighTemp = 0;
public JSONObject reconstructedWeather = null;
public JSONObject reconstructedForecast = null;
public JSONObject reconstructedOWMWeather = null;
public JSONObject reconstructedOWMForecast = null;
private ParcelableWeather2(Parcel in) {
int version = in.readInt();
if (version != 2) {
return;
}
Bundle bundle = in.readBundle();
Bundle bundle = in.readBundle(getClass().getClassLoader());
location = bundle.getString("weather_location");
time = bundle.getLong("weather_time");
queryTime = bundle.getLong("weather_query_time");
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();
reconstructedWeather = new JSONObject();
Bundle conditionBundle = in.readBundle(getClass().getClassLoader());
reconstructedOWMWeather = new JSONObject();
JSONArray weather = new JSONArray();
JSONObject condition = new JSONObject();
JSONObject main = new JSONObject();
currentCondition = conditionBundle.getString("weather_condition_text");
weatherSpec.currentCondition = conditionBundle.getString("weather_condition_text");
conditionBundle.getStringArray("weather_condition_types");
currentTemp = conditionBundle.getInt("weather_current_temp");
weatherSpec.currentTemp = conditionBundle.getInt("weather_current_temp");
currentConditionType = conditionBundle.getStringArray("weather_condition_types");
currentConditionCode = weatherConditionTypesToOpenWeatherMapIds(currentConditionType[0]);
todayLowTemp = conditionBundle.getInt("weather_low_temp");
todayHighTemp = conditionBundle.getInt("weather_high_temp");
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");
try {
condition.put("id", currentConditionCode);
condition.put("main", currentCondition);
condition.put("icon", Weather.mapToOpenWeatherMapIcon(currentConditionCode));
condition.put("id", weatherSpec.currentConditionCode);
condition.put("main", weatherSpec.currentCondition);
condition.put("icon", Weather.mapToOpenWeatherMapIcon(weatherSpec.currentConditionCode));
weather.put(condition);
main.put("temp", currentTemp);
main.put("temp", weatherSpec.currentTemp);
main.put("humidity", conditionBundle.getInt("weather_humidity_value"));
main.put("temp_min", todayLowTemp);
main.put("temp_max", todayHighTemp);
main.put("name", location);
main.put("temp_min", weatherSpec.todayMinTemp);
main.put("temp_max", weatherSpec.todayMaxTemp);
main.put("name", weatherSpec.location);
reconstructedWeather.put("weather", weather);
reconstructedWeather.put("main", main);
reconstructedOWMWeather.put("weather", weather);
reconstructedOWMWeather.put("main", main);
} catch (JSONException e) {
e.printStackTrace();
}
LOG.debug("Weather JSON for WEBVIEW: " + reconstructedWeather.toString());
//fetch immediate next forecast
if (--conditions > 0) {
int timeOffset = 86400000; //manually determined
reconstructedForecast = new JSONObject();
JSONArray list = new JSONArray();
JSONObject city = new JSONObject();
LOG.debug("Weather JSON for WEBVIEW: " + reconstructedOWMWeather.toString());
//fetch forecasts
int timeOffset = 0;
JSONArray list = new JSONArray();
JSONObject city = new JSONObject();
while (--conditions > 0) {
timeOffset += 86400000; //manually determined
JSONObject item = new JSONObject();
condition = new JSONObject();
main = new JSONObject();
weather = new JSONArray();
Bundle forecastBundle = in.readBundle();
forecastConditionType = forecastBundle.getStringArray("weather_condition_types");
forecastConditionCode = weatherConditionTypesToOpenWeatherMapIds(forecastConditionType[0]);
forecastLowTemp = forecastBundle.getInt("weather_low_temp");
forecastHighTemp = forecastBundle.getInt("weather_high_temp");
Bundle forecastBundle = in.readBundle(getClass().getClassLoader());
String[] forecastConditionType = forecastBundle.getStringArray("weather_condition_types");
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));
try {
condition.put("id", forecastConditionCode);
condition.put("main", forecastBundle.getString("weather_condition_text"));
@ -125,58 +119,29 @@ public class ParcelableWeather2 implements Parcelable {
main.put("temp_max", forecastHighTemp);
//forecast
//"city":{"id":3181913,"name":"Bolzano","coord":{"lat":46.4927,"lon":11.3336},"country":"IT"}
city.put("name", location);
city.put("country", "World");
reconstructedForecast.put("city", city);
item.put("dt", (time / 1000) + timeOffset);
item.put("main", main);
item.put("weather", weather);
list.put(item);
} catch (JSONException e) {
e.printStackTrace();
LOG.error("error while construction JSON", e);
}
// get the rest
while (--conditions > 0) {
conditionBundle = in.readBundle();
conditionBundle.getString("weather_condition_text");
weatherConditionTypesToOpenWeatherMapIds(conditionBundle.getStringArray("weather_condition_types")[0]);
conditionBundle.getInt("weather_current_temp");
item = new JSONObject();
condition = new JSONObject();
main = new JSONObject();
weather = new JSONArray();
timeOffset += 86400000;
try {
condition.put("id", weatherConditionTypesToOpenWeatherMapIds(conditionBundle.getStringArray("weather_condition_types")[0]));
condition.put("main", conditionBundle.getString("weather_condition_text"));
condition.put("icon", Weather.mapToOpenWeatherMapIcon(weatherConditionTypesToOpenWeatherMapIds(conditionBundle.getStringArray("weather_condition_types")[0])));
weather.put(condition);
main.put("temp", conditionBundle.getInt("weather_current_temp"));
main.put("humidity", conditionBundle.getInt("weather_humidity_value"));
main.put("temp_min", conditionBundle.getInt("weather_low_temp"));
main.put("temp_max", conditionBundle.getInt("weather_high_temp"));
item.put("dt", (time / 1000) + timeOffset);
item.put("main", main);
item.put("weather", weather);
list.put(item);
} catch (JSONException e) {
e.printStackTrace();
}
}
try {
reconstructedForecast.put("cnt", list.length());
reconstructedForecast.put("list", list);
} catch (JSONException e) {
e.printStackTrace();
}
LOG.debug("Forecast JSON for WEBVIEW: " + reconstructedForecast.toString());
}
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.toString());
}
}
@ -309,4 +274,5 @@ public class ParcelableWeather2 implements Parcelable {
}
return 3200;
}
}

View File

@ -441,4 +441,18 @@
\n
\nNICHT GETESTET, DIES KÖNNTE DEIN GERÄT UNBENUTZBAR MACHEN, INSTALLATION AUF EIGENE GEFAHR!</string>
<string name="mi2_prefs_button_press_count">Anzahl an Tastendrücken</string>
<string name="pref_title_charts_swipe">Seitwärts-Wischgesten in der Statistik-Anzeige</string>
<string name="pref_summary_pebble_enable_bgjs">Wenn aktiviert, können Watchfaces Informationen zu Wetter, Ladezustand etc. anzeigen.</string>
<string name="prefs_title_heartrate_measurement_interval">ganztägige Pulsmessung</string>
<string name="interval_one_minute">minütlich</string>
<string name="interval_five_minutes">alle 5 Minuten</string>
<string name="interval_ten_minutes">alle 10 Minuten</string>
<string name="interval_thirty_minutes">alle 30 Minuten</string>
<string name="interval_one_hour">stündlich</string>
<string name="automatic">automatisch</string>
<string name="activity_web_view">Web View Aktivität</string>
</resources>

View File

@ -451,4 +451,11 @@
<string name="traditional_chinese">Chino tradicional</string>
<string name="english">Inglés</string>
<string name="prefs_title_heartrate_measurement_interval">Medición de pulso todo el día</string>
<string name="interval_one_minute">Cada minuto</string>
<string name="interval_five_minutes">Cada 5 minutos</string>
<string name="interval_ten_minutes">Cada 10 minutos</string>
<string name="interval_thirty_minutes">Cada 30 minutos</string>
<string name="interval_one_hour">Cada hora</string>
</resources>

View File

@ -455,4 +455,11 @@ NOTE: la base de données sera bien évidement plus grande !</string>
<string name="traditional_chinese">Chinois traditionnel</string>
<string name="english">Anglais</string>
<string name="prefs_title_heartrate_measurement_interval">Mesure du pouls toute la journée</string>
<string name="interval_one_minute">Une fois par minute</string>
<string name="interval_five_minutes">Toutes les 5 minutes</string>
<string name="interval_ten_minutes">Toutes les 10 minutes</string>
<string name="interval_thirty_minutes">Toutes les 30 minutes</string>
<string name="interval_one_hour">Une fois par heure</string>
</resources>

View File

@ -456,4 +456,11 @@
<string name="traditional_chinese">סינית מסורתית</string>
<string name="english">אנגלית</string>
<string name="prefs_title_heartrate_measurement_interval">מדד דופק ליום</string>
<string name="interval_one_minute">פעם בדקה</string>
<string name="interval_five_minutes">כל 5 דקות</string>
<string name="interval_ten_minutes">כל 10 דקות</string>
<string name="interval_thirty_minutes">כל חצי שעה</string>
<string name="interval_one_hour">פעם בשעה</string>
</resources>

View File

@ -441,4 +441,19 @@
<string name="amazfitcor_firmware">Amazfit Cor ファームウェア %1$s</string>
<string name="activity_web_view">Web View アクティビティ</string>
<string name="pref_title_charts_swipe">チャートアクティビティで左/右のスワイプを有効にする</string>
<string name="preferences_amazfitbip_settings">Amazfit Bip 設定</string>
<string name="prefs_title_heartrate_measurement_interval">終日心拍数計測</string>
<string name="interval_one_minute">1分間に 1 回</string>
<string name="interval_five_minutes">5 分ごと</string>
<string name="interval_ten_minutes">10 分ごと</string>
<string name="interval_thirty_minutes">30 分ごと</string>
<string name="interval_one_hour">1 時間に 1 回</string>
<string name="automatic">自動</string>
<string name="simplified_chinese">簡体中国語</string>
<string name="traditional_chinese">繁体中国語</string>
<string name="english">英語</string>
</resources>

View File

@ -0,0 +1,483 @@
<?xml version='1.0' encoding='UTF-8'?>
<resources><string name="action_settings">Innstillinger</string>
<string name="action_debug">Feilretting</string>
<string name="action_quit">Avslutt</string>
<string name="action_donate">Doner</string>
<string name="controlcenter_fetch_activity_data">Synkroniser</string>
<string name="controlcenter_start_sleepmonitor">Søvnmonitor (Alfa)</string>
<string name="controlcenter_find_device">Finn mistet enhet</string>
<string name="controlcenter_take_screenshot">Utfør skjermavbildning</string>
<string name="controlcenter_connect">Koble til</string>
<string name="controlcenter_disconnect">Koble fra</string>
<string name="controlcenter_delete_device">Slett enhet</string>
<string name="controlcenter_delete_device_name">Slett %1$s</string>
<string name="controlcenter_navigation_drawer_open">Åpne navigasjonsskuff</string>
<string name="controlcenter_navigation_drawer_close">Lukk navigasjonsskuf</string>
<string name="controlcenter_snackbar_need_longpress">Trykk lenge på kortet for å koble fra</string>
<string name="controlcenter_snackbar_disconnecting">Kobler fra</string>
<string name="controlcenter_snackbar_connecting">Kobler til</string>
<string name="controlcenter_snackbar_requested_screenshot">Utfører skjermavbildning av enheten</string>
<string name="title_activity_debug">Feilretting</string>
<string name="title_activity_appmanager">Programbehandler</string>
<string name="appmanager_cached_watchapps_watchfaces">Programmer i hurtiglager</string>
<string name="appmanager_installed_watchapps">Installerte programmer</string>
<string name="appmanager_installed_watchfaces">Installerte urskiver</string>
<string name="appmananger_app_delete">Slett</string>
<string name="appmananger_app_delete_cache">Slett og fjern fra hurtiglager</string>
<string name="appmananger_app_reinstall">Reinstaller</string>
<string name="appmanager_app_openinstore">Søk i Pebble-programbutikk</string>
<string name="appmanager_health_activate">Aktiver</string>
<string name="appmanager_health_deactivate">Deaktiver</string>
<string name="appmanager_hrm_activate">Skru på HRM</string>
<string name="appmanager_hrm_deactivate">Skru av HRM</string>
<string name="appmanager_weather_activate">Skru på systemværprogram</string>
<string name="appmanager_weather_deactivate">Skru av systemværprogram</string>
<string name="appmanager_weather_install_provider">Installer værmeldingsprogrammet</string>
<string name="app_configure">Sett opp</string>
<string name="app_move_to_top">Flytt til toppen</string>
<string name="title_activity_appblacklist">Merknadssvarteliste</string>
<string name="title_activity_calblacklist">Svartelistede kalendere</string>
<string name="title_activity_fw_app_insaller">Fastvare-/program-installerer</string>
<string name="fw_upgrade_notice">Du er i ferd med å installere fastvaren %s i stedet for den som er installert på ditt Mi Band nå.</string>
<string name="app_name">Gadgetbru</string>
<string name="title_activity_controlcenter">Gadgetbru</string>
<string name="controlcenter_delete_device_dialogmessage">Dette vil slette enheten og all tilknyttet data</string>
<string name="fw_upgrade_notice_amazfitbip">Du er i ferd med å installere fastvaren %s på din Amazfit Bip.
\n
\nForsikre deg om at du installerer .gps-fastvaren, så .res-fila, og til sist .fw-fila. Armbåndsuret ditt vil starte på nytt etter at .fw-fila er installert.
\n
\nMerk: Du må ikke installere .res og .gps hvis disse er akkurat de samme som dem som allerede er installert.
\n
\nFORTSETT PÅ EGEN RISIKO!</string>
<string name="fw_upgrade_notice_amazfitcor">Du er i ferd med å installere fastvaren %s på din Amazfit Cor.
\n
\nForsikre deg om at du installerer .res-fila, og så .fw-fila. Armbåndsuret ditt vil starte på nytt etter at .fw-fila er installert.
\n
\nMerk: Du må ikke installere .res og .gps hvis disse er akkurat de samme som dem som allerede er installert.
\n
\nUTESTET, KAN HAVARERE ENHETEN DIN, FORTSETT PÅ EGEN RISIKO!</string>
<string name="fw_multi_upgrade_notice">Du er i ferd med å installere fastvarene %1$s og %2$s i steden for dem som er installert nå på ditt Mi Band.</string>
<string name="miband_firmware_known">Denne fastvaren har blitt testet og er kompatibel med Gadgetbru.</string>
<string name="miband_firmware_unknown_warning">Denne fastvaren er utestet og er kanskje ikke kompatibel med Gadgetbru.
\n
\nDu oppfordres IKKE til å skrive den til ditt Mi Band!</string>
<string name="miband_firmware_suggest_whitelist">Hvis du fremdeles ønsker å fortsette og ting fungerer etterpå, fortell Gadgetbru-utviklerne at de skal hvitliste fastvareversjon: %s</string>
<string name="title_activity_settings">Innstillinger</string>
<string name="pref_header_general">Hovedinnstillinger</string>
<string name="pref_title_general_autoconnectonbluetooth">Koble til enhet når Blåtann slås på</string>
<string name="pref_title_general_autostartonboot">Start automatisk</string>
<string name="pref_title_general_autocreonnect">Koble til igjen automatisk</string>
<string name="pref_title_audo_player">Foretrukken lydspiller</string>
<string name="pref_default">Forvalg</string>
<string name="pref_header_datetime">Dato og tid</string>
<string name="pref_title_datetime_syctimeonconnect">Synkroniser tid</string>
<string name="pref_summary_datetime_syctimeonconnect">Synkroniser tid til enhet ved tilknobling og når tid eller tidssone endres på Android</string>
<string name="pref_title_theme">Drakt</string>
<string name="pref_theme_light">Lys</string>
<string name="pref_theme_dark">Mørk</string>
<string name="pref_title_language">Språk</string>
<string name="pref_title_minimize_priority">Skjul Gadgetbro-merknaden</string>
<string name="pref_summary_minimize_priority_off">Ikonet i statusfeltet og merknaden på låseskjermen vises</string>
<string name="pref_summary_minimize_priority_on">Ikonet i statusfeltet og merknaden på låseskjermen er skjult</string>
<string name="pref_header_notifications">Merknader</string>
<string name="pref_title_notifications_repetitions">Gjentakelser</string>
<string name="pref_title_notifications_call">Telefonsamtaler</string>
<string name="pref_title_notifications_sms">SMS</string>
<string name="pref_title_notifications_pebblemsg">Pebble-meldinger</string>
<string name="pref_summary_notifications_pebblemsg">Støtte for alle programmer som sender merknader til Pebble via PebbleKit.</string>
<string name="pref_title_notifications_generic">Generisk merknadsstøtte</string>
<string name="pref_title_whenscreenon">…også når skjermen er på</string>
<string name="pref_title_notification_filter">Ikke forstyrr</string>
<string name="pref_summary_notification_filter">Stopp uønskede merkander fra å bli sendt i \"Ikke forstyrr\"-modus</string>
<string name="pref_title_transliteration">Translitterasjon</string>
<string name="pref_summary_transliteration">Skru på hvis din enhet ikke har noen støtte for ditt språks skrift</string>
<string name="always">Alltid</string>
<string name="when_screen_off">Når skjermen er av</string>
<string name="never">Aldri</string>
<string name="pref_header_privacy">Personvern</string>
<string name="pref_title_call_privacy_mode">Ringepersonvernsmodus</string>
<string name="pref_call_privacy_mode_off">Vis navn og nummer</string>
<string name="pref_call_privacy_mode_name">Skjul navn, men vis nummer</string>
<string name="pref_call_privacy_mode_number">Skjul nummer, men vis navn</string>
<string name="pref_call_privacy_mode_complete">Skjul navn og nummer</string>
<string name="pref_blacklist">Svartelist programmer</string>
<string name="pref_blacklist_calendars">Svartelist kalendre</string>
<string name="pref_title_canned_replies">Svar</string>
<string name="pref_title_canned_messages_set">Oppdater på Pebble</string>
<string name="pref_header_development">Utviklervalg</string>
<string name="pref_title_development_miaddr">Mi Band-adresse</string>
<string name="pref_title_pebble_settings">Pebble-innstillinger</string>
<string name="pref_header_activitytrackers">Aktivitetssporere</string>
<string name="pref_title_pebble_activitytracker">Foretrukket aktivitetssporer</string>
<string name="pref_title_pebble_sync_health">Synkroniser Pebble-helse</string>
<string name="pref_title_pebble_sync_misfit">Misfit-synkronisering</string>
<string name="pref_title_pebble_sync_morpheuz">Morpheuz-synkronisering</string>
<string name="pref_title_enable_outgoing_call">Støtte for utgående anrop</string>
<string name="pref_summary_enable_outgoing_call">Å skru av dette vil også forhindre Pebble 2/LE fra å vibrere under utgående anrop</string>
<string name="pref_title_enable_pebblekit">Tillat tredjepartstilgang fra Android-programmer</string>
<string name="pref_summary_enable_pebblekit">Skru på eksperimentell støte for Androidprogrammer som bruker PebbleKit</string>
<string name="pref_header_pebble_timeline">Pebble-tidslinje</string>
<string name="pref_title_sunrise_sunset">Soloppgang og solnedgang</string>
<string name="pref_summary_sunrise_sunset">Send soloppgang og solnedgangstider basert på plasseringen til Pebble-tidslinjen</string>
<string name="pref_title_enable_calendar_sync">Synkroniser kalender</string>
<string name="pref_summary_enable_calendar_sync">Send kalenderhendelser til tidslinjen</string>
<string name="pref_title_autoremove_notifications">Fjern forkastede merknader automatisk</string>
<string name="pref_summary_autoremove_notifications">Merknader blir automatisk fjernet fra Pebble-enheten når de forkastes fra Android-enheten</string>
<string name="pref_title_pebble_privacy_mode">Personvernsmodus</string>
<string name="pref_pebble_privacy_mode_off">Normale merknader</string>
<string name="pref_pebble_privacy_mode_content">Vis merknadsteksten utenfor skjermen</string>
<string name="pref_pebble_privacy_mode_complete">Kun vis merknadsikoner</string>
<string name="pref_header_location">Plassering</string>
<string name="pref_title_location_aquire">Hent plassering</string>
<string name="pref_title_location_latitude">Breddegrad</string>
<string name="pref_title_location_longitude">Lengdegrad</string>
<string name="pref_title_location_keep_uptodate">Hold plasseringen oppdatert</string>
<string name="pref_summary_location_keep_uptodate">Prøv å hent gjeldende plassering ved kjøring, bruk lagret plassering som andrevalg</string>
<string name="toast_enable_networklocationprovider">Skru på nettverksplassering</string>
<string name="toast_aqurired_networklocation">plassering innhentet</string>
<string name="pref_title_pebble_forceprotocol">Tving gjennom merknadsprotokoll</string>
<string name="pref_summary_pebble_forceprotocol">Dette valget tvinger bruk av siste merknadskotroll avhengig av fastvareversjon. KUN SKRU PÅ DETTE HVIS DU VET HVA DU GJØR!</string>
<string name="pref_title_pebble_forceuntested">Skru på utestede funksjoner</string>
<string name="pref_summary_pebble_forceuntested">Skru på utestede funksjoner. KUN SKRU PÅ DETTE HVIS DU VET HVA DU GJØR!</string>
<string name="pref_title_pebble_forcele">Alltid foretrekk BLE</string>
<string name="pref_summary_pebble_forcele">Bruk eksperimentell Pebble LE-støtte for alle Pebble-klokker istedenfor BT classic, som krever parring av en Pebble LE etter at noe som ikke var en LE har vært tilkoblet én gang</string>
<string name="pref_title_pebble_mtu_limit">Pebble 2/LE GATT MTU-grense</string>
<string name="pref_summary_pebble_mtu_limit">Hvis din Pebble 2/Pebble LE ikke fungerer som forventet, prøv å sette denne grensen for å begrense MTU (gyldig rekkevidde 20-512)</string>
<string name="pref_title_pebble_enable_bgjs">Skru på bakgrunns-JS</string>
<string name="pref_summary_pebble_enable_bgjs">Tillater når påskrudd, værvarsel på urskive, batteriinfo, osv.</string>
<string name="pref_title_pebble_reconnect_attempts">Forsøk på tilkoblingsgjenopprettelse</string>
<string name="pref_title_unit_system">Enheter</string>
<string name="pref_title_timeformat">Tidsformat</string>
<string name="prefs_title_all_day_heart_rate">Heldagspulsmåling</string>
<string name="preferences_hplus_settings">HPlus/Makibes-innstillinger</string>
<string name="not_connected">Ikke tilkoblet</string>
<string name="connecting">Kobler til</string>
<string name="connected">Tilkoblet</string>
<string name="unknown_state">Ukjent tilstand</string>
<string name="_unknown_">(ukjent)</string>
<string name="test">Test</string>
<string name="test_notification">Send testmerknad</string>
<string name="this_is_a_test_notification_from_gadgetbridge">Dette er en testmerknad fra Gadgetbru</string>
<string name="bluetooth_is_not_supported_">Blåtann støttes ikke.</string>
<string name="bluetooth_is_disabled_">Blåtann avskrudd.</string>
<string name="tap_connected_device_for_app_mananger">Trykk på tilkoblet enhet for programbehandler</string>
<string name="tap_connected_device_for_activity">Trykk på tilkoblet enhet for aktivtet</string>
<string name="tap_connected_device_for_vibration">Trykk på tilkoblet enhet for vibrasjon</string>
<string name="tap_a_device_to_connect">Trykk på en enhet for å koble til</string>
<string name="cannot_connect_bt_address_invalid_">Kan ikke koble til. Ugyldig Blåtannsadresse?</string>
<string name="gadgetbridge_running">Gadgetbro kjører</string>
<string name="installing_binary_d_d">Installerer binærfil %1$d/%2$d</string>
<string name="installation_failed_">Installasjon mislyktes</string>
<string name="installation_successful">Installert</string>
<string name="firmware_install_warning">DU PRØVER Å INSTALLERE EN FASTVARE, FORTSETT PÅ EGEN RISIKO.
\n
\nDENNE FASTVAREN ER FOR MASKINVAREVERSJON: %s</string>
<string name="app_install_info">Du er i ferd med å installere følgende program:
\n
\n%1$s version %2$s av %3$s
\n</string>
<string name="n_a">I/T</string>
<string name="initialized">igangsatt</string>
<string name="appversion_by_creator">%1$s av %2$s</string>
<string name="title_activity_discovery">Enhetsoppdaging</string>
<string name="discovery_stop_scanning">Stopp skanning</string>
<string name="discovery_start_scanning">Start oppdagning</string>
<string name="action_discover">Koble til ny enhet</string>
<string name="device_with_rssi">%1$s (%2$)</string>
<string name="title_activity_android_pairing">Parr enhet</string>
<string name="android_pairing_hint">Bruk parringsdialogen for Blåtann i Android til å parre enheten.</string>
<string name="title_activity_mi_band_pairing">Parr ditt Mi Band</string>
<string name="pairing">Parrer med %s…</string>
<string name="pairing_creating_bond_with">Oppretter tilknytning til %1$s (%2$s)</string>
<string name="pairing_unable_to_pair_with">Klarte ikke å parre med %1$s (%2$s)</string>
<string name="pairing_in_progress">Parring underveis: %1$s (%2$s)</string>
<string name="pairing_already_bonded">Allerede tilknyttet %1$s (%2$s), tilkobler…</string>
<string name="message_cannot_pair_no_mac">Ingen MAC-adresse sendt, kan ikke parre.</string>
<string name="preferences_category_device_specific_settings">Enhetsspesifikke innstillinger</string>
<string name="preferences_miband_settings">Mi Band / Amazfit -innstillinger</string>
<string name="preferences_amazfitbip_settings">Amazfit Bip-innstillinger</string>
<string name="male">Mann</string>
<string name="female">Kvinne</string>
<string name="other">Annet</string>
<string name="left">Venstre</string>
<string name="right">Høyre</string>
<string name="miband_pairing_using_dummy_userdata">Ingen gyldig brukerdata angitt, bruker testbrukerdata midlertidig.</string>
<string name="miband_pairing_tap_hint">Når ditt Mi Band vibrerer og blinker, trykk på det et par ganger på rad.</string>
<string name="appinstaller_install">Installer</string>
<string name="discovery_connected_devices_hint">Gjør enheten din oppdagbar. Enheter som er tilkoblet vil antagelig ikke bli oppdaget. Aktiver plassering (GPS bl. a.) på Android 6+. Skru av Privacy Guard for Gadgetbru, siden det kan kræsje og medføre omstart av telefonen. Hvis ingen enhet blir funnet etter et par minutter, prøv igjen etter å ha startet din mobile enhet på nytt.</string>
<string name="discovery_note">Merk:</string>
<string name="candidate_item_device_image">Enhetsavbildning</string>
<string name="miband_prefs_alias">Navn/alias</string>
<string name="pref_header_vibration_count">Vibrasjonsantall</string>
<string name="title_activity_sleepmonitor">Søvnmonitor</string>
<string name="pref_write_logfiles">Skriv loggfiler</string>
<string name="initializing">Igangsetter</string>
<string name="busy_task_fetch_activity_data">Henter aktivitetsdato</string>
<string name="sleep_activity_date_range">Fra %1$s til %2$s</string>
<string name="miband_prefs_wearside">Venstre- eller høyre-hånd?</string>
<string name="pref_screen_vibration_profile">Vibrasjonsprofil</string>
<string name="vibration_profile_staccato">Stakkato</string>
<string name="vibration_profile_short">Kort</string>
<string name="vibration_profile_medium">Middels</string>
<string name="vibration_profile_long">Lang</string>
<string name="vibration_profile_waterdrop">Vanndråpe</string>
<string name="vibration_profile_ring">Ring</string>
<string name="vibration_profile_alarm_clock">Alarmklokke</string>
<string name="miband_prefs_vibration">Vibrasjon</string>
<string name="vibration_try">Prøv</string>
<string name="pref_screen_notification_profile_sms">SMS-merknad</string>
<string name="pref_header_vibration_settings">Vibrasjonsinnstillinger</string>
<string name="pref_screen_notification_profile_generic">Generisk merknad</string>
<string name="pref_screen_notification_profile_email">E-postmerknad</string>
<string name="pref_screen_notification_profile_incoming_call">Innkommende ringemerknad</string>
<string name="pref_screen_notification_profile_generic_chat">Sludre</string>
<string name="pref_screen_notification_profile_generic_navigation">Navigasjon</string>
<string name="pref_screen_notification_profile_generic_social">Sosialt nettverk</string>
<string name="prefs_title_heartrate_measurement_interval">Heldagspulsmåling</string>
<string name="interval_one_minute">én gang i minuttet</string>
<string name="interval_five_minutes">hvert femte minutt</string>
<string name="interval_ten_minutes">hvert tiende minutt</string>
<string name="interval_thirty_minutes">hver halvtime</string>
<string name="interval_one_hour">én gang i timen</string>
<string name="stats_title">Fartssoner</string>
<string name="stats_x_axis_label">Totalt antall minutter</string>
<string name="stats_y_axis_label">Steg per minutt</string>
<string name="control_center_find_lost_device">Finn tapt enhet</string>
<string name="control_center_cancel_to_stop_vibration">Avbryt for å stoppe vibrasjon.</string>
<string name="title_activity_charts">Din aktivitet</string>
<string name="title_activity_set_alarm">Sett opp alarmer</string>
<string name="controlcenter_start_configure_alarms">Sett opp alarmer</string>
<string name="title_activity_alarm_details">Alarmdetaljer</string>
<string name="alarm_sun_short">Søn</string>
<string name="alarm_mon_short">Man</string>
<string name="alarm_tue_short">Tir</string>
<string name="alarm_wed_short">Ons</string>
<string name="alarm_thu_short">Tor</string>
<string name="alarm_fri_short">Fre</string>
<string name="alarm_sat_short">Lør</string>
<string name="alarm_smart_wakeup">Smart oppvåkning</string>
<string name="user_feedback_miband_set_alarms_failed">Feil ved setting av alarm, prøv igjen.</string>
<string name="user_feedback_miband_set_alarms_ok">Alarmer sendt til enhet.</string>
<string name="chart_no_data_synchronize">Ingen data. Synkroniser enhet?</string>
<string name="user_feedback_miband_activity_data_transfer">I ferd med å overføre %1$d med data fra %2$s</string>
<string name="miband_prefs_fitness_goal">Stegmål</string>
<string name="dbaccess_error_executing">Feil under kjøring av \"%1$s\"</string>
<string name="controlcenter_start_activitymonitor">Din aktivitet (alfa)</string>
<string name="cannot_connect">Kan ikke koble til: %1$s</string>
<string name="installer_activity_unable_to_find_handler">Kan ikke finne en behandler for installasjon av denne fila.</string>
<string name="pbw_install_handler_unable_to_install">Klarte ikke å installere gitt fil: %1$s</string>
<string name="pbw_install_handler_hw_revision_mismatch">Klarte ikke å installere angitt fastvare. Den passer ikke for maskinvareversjonen for din Pebble.</string>
<string name="installer_activity_wait_while_determining_status">Vent mens installasjonsstatus fastsettes…</string>
<string name="notif_battery_low_title">Lite batteri på gadget!</string>
<string name="notif_battery_low_percent">%1$s batteri gjenstår: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Siste oppladning: %s
\n</string>
<string name="notif_battery_low_bigtext_number_of_charges">Antall ladinger: %s</string>
<string name="sleepchart_your_sleep">Din søvn</string>
<string name="weeksleepchart_sleep_a_week">Søvn per uke</string>
<string name="weeksleepchart_today_sleep_description">Søvn i dag, mål: %1$s</string>
<string name="weekstepschart_steps_a_week">Steg per uke</string>
<string name="activity_sleepchart_activity_and_sleep">Din aktivitet og søvn</string>
<string name="updating_firmware">Oppgraderer fastvare…</string>
<string name="fwapp_install_device_not_ready">Kan ikke installere fil, enheten er ikke klar.</string>
<string name="miband_installhandler_miband_firmware">Mi Band-fastvare %1$s</string>
<string name="amazfitbip_firmware">Amazfit Bip-fastvare %1$s</string>
<string name="amazfitcor_firmware">Amazfit Cor-fastvare %1$s</string>
<string name="miband_fwinstaller_compatible_version">Kompatibel versjon</string>
<string name="miband_fwinstaller_untested_version">Utestet versjon!</string>
<string name="fwappinstaller_connection_state">Tilkobling til enhet: %1$s</string>
<string name="pbw_installhandler_pebble_firmware">Pebble-fastvare %1$s</string>
<string name="pbwinstallhandler_correct_hw_revision">Korrekt maskinvareversjon</string>
<string name="pbwinstallhandler_incorrect_hw_revision">Det er ikke samsvar mellom maskinvarerevisjonene!</string>
<string name="pbwinstallhandler_app_item">%1$s (%2$s)</string>
<string name="updatefirmwareoperation_updateproblem_do_not_reboot">Problem med fastvareoverføring. IKKE SKRU AV ditt Mi Band!</string>
<string name="updatefirmwareoperation_metadata_updateproblem">Problem ved overføring av fastvaremetadata</string>
<string name="updatefirmwareoperation_update_complete">Fastvareinstallasjon fullført</string>
<string name="updatefirmwareoperation_update_complete_rebooting">Fastvareinstallasjon fullført, starter enhet på nytt…</string>
<string name="updatefirmwareoperation_write_failed">Fastvareskriving mislyktes</string>
<string name="chart_steps">Steg</string>
<string name="calories">Kalorier</string>
<string name="distance">Distanse</string>
<string name="clock">Klokke</string>
<string name="heart_rate">Puls</string>
<string name="battery">Batteri</string>
<string name="liveactivity_live_activity">Aktivitet i sanntid</string>
<string name="weeksteps_today_steps_description">Steg i dag, mål: %1$s</string>
<string name="pref_title_dont_ack_transfer">Ikke send bekreftelse på aktivitetsdataoverføring</string>
<string name="pref_summary_dont_ack_transfers">Hvis aktivitetsdataen ikke bekreftes til bandet, vil de ikke bli tømt. Nyttig hvis Gb brukes sammen med andre programmer.</string>
<string name="pref_summary_keep_data_on_device">Beholder aktivitetsdata på Mi Band-et, selv etter synkronisering. Nyttig hvis Gb brukes sammen med andre programmer.</string>
<string name="pref_title_low_latency_fw_update">Bruk lav-latens -modus for fastvareoppgraderinger</string>
<string name="pref_summary_low_latency_fw_update">Dette kan hjelpe på enheter der fastvareoppgraderinger mislykkes.</string>
<string name="live_activity_steps_history">Steghistorikk</string>
<string name="live_activity_current_steps_per_minute">Gjeldende steg/min</string>
<string name="live_activity_total_steps">Totalt antall steg</string>
<string name="live_activity_steps_per_minute_history">Historisk, steg per minutt</string>
<string name="live_activity_start_your_activity">Start din aktivitet</string>
<string name="abstract_chart_fragment_kind_activity">Aktivitet</string>
<string name="abstract_chart_fragment_kind_light_sleep">Lett søvn</string>
<string name="abstract_chart_fragment_kind_deep_sleep">Dyp søvn</string>
<string name="abstract_chart_fragment_kind_not_worn">Ikke brukt</string>
<string name="device_not_connected">Ikke tilkoblet.</string>
<string name="user_feedback_all_alarms_disabled">Alle alarmer avskrudd</string>
<string name="pref_title_keep_data_on_device">Behold aktivitetsdata på enhet</string>
<string name="miband_fwinstaller_incompatible_version">Ukompatibel fastvare</string>
<string name="fwinstaller_firmware_not_compatible_to_device">Fastvaren er ikke kompatibel med enheten</string>
<string name="miband_prefs_reserve_alarm_calendar">Alarmer å holde av for kommende hendelser</string>
<string name="miband_prefs_hr_sleep_detection">Bruk pulsmåler for å forbedre bestemmelse av søvnmønster</string>
<string name="miband2_prefs_dateformat">Mi2: Datoformat</string>
<string name="dateformat_time">Tid</string>
<string name="dateformat_date_time">Tid og dato</string>
<string name="mi2_prefs_button_actions">Knappevalg</string>
<string name="mi2_prefs_button_actions_summary">Angi handlinger for Mi Band 2 knappetrykk</string>
<string name="mi2_prefs_button_press_count">Antall trykk på knapp</string>
<string name="mi2_prefs_button_press_count_summary">Antall trykk på knapp for å utløse meldingskringkasting</string>
<string name="mi2_prefs_button_press_broadcast">Kringkastingsmelding å sende</string>
<string name="mi2_prefs_goal_notification">Målmerknad</string>
<string name="mi2_prefs_goal_notification_summary">Båndet vil vibrere når daglig stegmål nås</string>
<string name="mi2_prefs_display_items">Vis elementer</string>
<string name="mi2_prefs_display_items_summary">Velg elementene som skal vises på båndskjermen</string>
<string name="mi2_prefs_rotate_wrist_to_switch_info">Roter håndledd for å bytte info</string>
<string name="mi2_prefs_do_not_disturb">Ikke forstyrr</string>
<string name="mi2_prefs_do_not_disturb_summary">Båndet mottar ikke merknader når det er aktivt</string>
<string name="mi2_prefs_inactivity_warnings">Inaktivitetsadvarsler</string>
<string name="mi2_prefs_inactivity_warnings_summary">Båndet vil vibrere når du har vært inaktiv en stund</string>
<string name="mi2_prefs_inactivity_warnings_threshold">Inaktivitetsterskel (i minutter)</string>
<string name="mi2_prefs_inactivity_warnings_dnd_summary">Skru av inaktivitetsadvarsel for en tidsperiode</string>
<string name="mi2_prefs_do_not_disturb_start">Starttid</string>
<string name="mi2_prefs_do_not_disturb_end">Sluttid</string>
<string name="automatic">Automatisk</string>
<string name="simplified_chinese">Forenklet kinesisk</string>
<string name="traditional_chinese">Tradisjonell kinesisk</string>
<string name="english">Engelsk</string>
<string name="FetchActivityOperation_about_to_transfer_since">I ferd med å overføre data siden %1$s</string>
<string name="waiting_for_reconnect">Venter på ny tilkobling</string>
<string name="activity_prefs_about_you">Om deg</string>
<string name="activity_prefs_year_birth">Fødselsår</string>
<string name="activity_prefs_gender">Kjønn</string>
<string name="activity_prefs_height_cm">Høyde i cm</string>
<string name="activity_prefs_weight_kg">Vekt i kg</string>
<string name="authenticating">Autentiserer</string>
<string name="authentication_required">Autentisering kreves</string>
<string name="appwidget_text">Zzz</string>
<string name="add_widget">Legg til miniprogram</string>
<string name="activity_prefs_sleep_duration">Foretrukket søvn i timer</string>
<string name="appwidget_alarms_set">En alarm ble satt for %1$02d:%2$02d</string>
<string name="device_hw">Maskinvarerevisjon: %1$s</string>
<string name="device_fw">Fastvareversjon: %1$s</string>
<string name="error_creating_directory_for_logfiles">Feil under opprettelse av mappe for loggfiler: %1$s</string>
<string name="DEVINFO_HR_VER">"HR: "</string>
<string name="updatefirmwareoperation_update_in_progress">Fastvareoppgradering underveis</string>
<string name="updatefirmwareoperation_firmware_not_sent">Fastvare ikke sendt</string>
<string name="charts_legend_heartrate">Puls</string>
<string name="live_activity_heart_rate">Puls</string>
<string name="pref_title_pebble_health_store_raw">Lagre rådata i databasen</string>
<string name="pref_summary_pebble_health_store_raw">Hvis valgt blir dataen lagret \"som den er\" og er tilgjengelig for senere fortolkning. NB: Databasen kan bli større i sådant fall!</string>
<string name="action_db_management">Databasebehandling</string>
<string name="title_activity_db_management">Databasebehandling</string>
<string name="dbmanagementactivity_exported_to">Eksporter til: %1$s</string>
<string name="dbmanagementactivity_error_exporting_db">Feil ved eksport av DB: %1$s</string>
<string name="dbmanagementactivity_error_exporting_shared">Feil ved eksport av innstilling: %1$s</string>
<string name="dbmanagementactivity_import_data_title">Importer data?</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Vil du virkelig overskrive gjeldende database? All nåværende aktivitetsdata (hvis noen) vil gå tapt.</string>
<string name="dbmanagementactivity_import_successful">Importert</string>
<string name="dbmanagementactivity_error_importing_db">Feil ved import av DB: %1$s</string>
<string name="dbmanagementactivity_error_importing_shared">Feil ved import av innstilling: %1$s</string>
<string name="dbmanagementactivity_delete_activity_data_title">Slett aktivitetsdata?</string>
<string name="dbmanagementactivity_really_delete_entire_db">Vil du virkelig slette hele databasen? All din aktivitetsdata og informasjon om dine enheter vil gå tapt.</string>
<string name="dbmanagementactivity_database_successfully_deleted">Data slettet.</string>
<string name="dbmanagementactivity_db_deletion_failed">Databasesletting mislyktes.</string>
<string name="dbmanagementactivity_delete_old_activity_db">Slett gammel aktivitetsdatabase?</string>
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">Vil du virkelig slette den gamle aktivitetsdatabasen? Aktivietetsdata som ikke ble importert vil gå tapt.</string>
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Gammel aktivitetsdata slettet.</string>
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Sletting av gammel aktivitetsdatabase mislyktes.</string>
<string name="dbmanagementactivity_overwrite">Overskriv</string>
<string name="Cancel">Avbryt</string>
<string name="Delete">Slett</string>
<string name="title_activity_vibration">Vibrasjon</string>
<string name="title_activity_pebble_pairing">Pebble-parring</string>
<string name="pebble_pairing_hint">En parringslogg bør sprette opp på din Android-enhet. Hvis det ikke skjer, se i navigasjonsskuffen, og godta parringsforespørselen. Etter det godtar du parringsforespørselen på din Pebble</string>
<string name="pref_title_setup_bt_pairing">Skru på Blåtannsparring</string>
<string name="pref_summary_setup_bt_pairing">Skru dette av hvis du har problemer med å koble til</string>
<string name="unit_metric">Metrisk</string>
<string name="unit_imperial">Imperial</string>
<string name="timeformat_24h">24t</string>
<string name="timeformat_am_pm">AM/PM</string>
<string name="pref_screen_notification_profile_alarm_clock">Ringeklokke</string>
<string name="StringUtils_sender">(%1$s)</string>
<string name="find_device_you_found_it">Du fant den!</string>
<string name="miband2_prefs_timeformat">Mi2: Tidsformat</string>
<string name="mi2_fw_installhandler_fw53_hint">Du må installere versjon %1$s før du installerer denne fastvaren!</string>
<string name="mi2_enable_text_notifications">Tekstmerknader</string>
<string name="mi2_enable_text_notifications_summary">Trenger fastvare &lt;=1.0.1.28 og Mili_pro.ft* installert.</string>
<string name="off">Av</string>
<string name="mi2_dnd_off"></string>
<string name="mi2_dnd_automatic">Automatisk (søvnoppdagelse)</string>
<string name="mi2_dnd_scheduled">Planlagt (tidsperiode)</string>
<string name="discovery_attempting_to_pair">Prøver å parre med %1$s</string>
<string name="discovery_bonding_failed_immediately">Tilknytning til %1$s mislyktes umiddelbart.</string>
<string name="discovery_trying_to_connect_to">Prøver å koble til: %1$s</string>
<string name="discovery_enable_bluetooth">Skru på Blåtann for å oppdage enheter.</string>
<string name="discovery_successfully_bonded">Tilknyttet %1$s.</string>
<string name="discovery_pair_title">Parr med %1$s?</string>
<string name="discovery_pair_question">Velg \"Parr\" for å parre enhetene dine. Hvis dette mislykkes, prøv igjen uten å parre.</string>
<string name="discovery_yes_pair">Parr</string>
<string name="discovery_dont_pair">Ikke parr</string>
<string name="_pebble_watch_open_on_phone">Åpne på telefonen</string>
<string name="_pebble_watch_mute">Forstum</string>
<string name="_pebble_watch_reply">Svar</string>
</resources>

View File

@ -7,21 +7,21 @@
<string name="action_quit">Выход</string>
<string name="controlcenter_fetch_activity_data">Синхронизировать</string>
<string name="controlcenter_start_sleepmonitor">Анализ сна (АЛЬФА)</string>
<string name="controlcenter_find_device">Найти устройство...</string>
<string name="controlcenter_find_device">Найти устройство</string>
<string name="controlcenter_take_screenshot">Сделать снимок экрана</string>
<string name="controlcenter_disconnect">Отключиться</string>
<string name="controlcenter_disconnect">Отключить</string>
<string name="controlcenter_delete_device">Удалить устройство</string>
<string name="controlcenter_delete_device_name">Удалить %1$s</string>
<string name="controlcenter_delete_device_dialogmessage">Устройство и вся связанная с ним информация будут удалены!</string>
<string name="controlcenter_navigation_drawer_open">Открыть панель навигации</string>
<string name="controlcenter_navigation_drawer_close">Закрыть панель навигации</string>
<string name="controlcenter_snackbar_need_longpress">Выполните долгое нажатие на карту для разъединения.</string>
<string name="controlcenter_snackbar_need_longpress">Чтобы разъединиться, нажмите на карточку устройства и удержите</string>
<string name="controlcenter_snackbar_disconnecting">Разъединение</string>
<string name="controlcenter_snackbar_connecting">Соединение</string>
<string name="controlcenter_snackbar_requested_screenshot">Сделать снимок устройства</string>
<string name="title_activity_debug">Отладка</string>
<!--Strings related to AppManager-->
<string name="title_activity_appmanager">App Manager</string>
<string name="title_activity_appmanager">Управление приложением</string>
<string name="appmanager_cached_watchapps_watchfaces">Приложения в памяти</string>
<string name="appmanager_installed_watchapps">Установленные приложения</string>
<string name="appmanager_installed_watchfaces">Установленный циферблаты</string>
@ -43,7 +43,7 @@
<!--Strings related to CalBlacklist-->
<!--Strings related to FwAppInstaller-->
<string name="title_activity_fw_app_insaller">Установщик прошивки/приложений</string>
<string name="fw_upgrade_notice">Вы собираетесь установить прошивку %s заместо текущей на вашем Mi Band.</string>
<string name="fw_upgrade_notice">Вы собираетесь установить прошивку %s вместо текущей на вашем Mi Band.</string>
<string name="fw_multi_upgrade_notice">Вы собираетесь установить прошивки %1$s и %2$s вместо текущей на вашем Mi Band.</string>
<string name="miband_firmware_known">Эта прошивка была проверена и совместима с Gadgetbridge.</string>
<string name="miband_firmware_unknown_warning">Эта прошивка не протестирована и может быть несовместима с Gadgetbridge.\n\nНе рекомендуется устанавливать её на ваш Mi Band!</string>
@ -55,7 +55,7 @@
<string name="pref_title_general_autostartonboot">Запускать автоматически</string>
<string name="pref_title_general_autocreonnect">Переподключаться автоматически</string>
<string name="pref_title_audo_player">Предпочтительный музыкальный плеер</string>
<string name="pref_default">По-умолчанию</string>
<string name="pref_default">По умолчанию</string>
<string name="pref_header_datetime">Дата и время</string>
<string name="pref_title_datetime_syctimeonconnect">Синхронизировать время при подключении</string>
<string name="pref_summary_datetime_syctimeonconnect">Синхронизировать время при подключении к устройству, а также при изменении времени или временной зоны в системе</string>
@ -77,10 +77,10 @@
<string name="pref_title_notification_filter">Не беспокоить</string>
<string name="pref_summary_notification_filter">Предотвращать отправку нежелательных уведомлений в режиме \"Не беспокоить\"</string>
<string name="pref_title_transliteration">Транслитерация</string>
<string name="always">всегда</string>
<string name="always">Всегда</string>
<string name="pref_summary_transliteration">Включите эту функцию, если ваше устройство не имеет поддержки шрифта на вашем языке</string>
<string name="when_screen_off">когда экран выключен</string>
<string name="never">никогда</string>
<string name="when_screen_off">Когда экран выключен</string>
<string name="never">Никогда</string>
<string name="pref_header_privacy">Конфиденциальность</string>
<string name="pref_title_call_privacy_mode">Вызов режима конфиденциальности</string>
<string name="pref_call_privacy_mode_off">Отображать имя и номер</string>
@ -103,10 +103,10 @@
<string name="pref_title_pebble_sync_morpheuz">Синхронизация с Morpheuz</string>
<string name="pref_title_enable_outgoing_call">Поддержка исходящих вызовов</string>
<string name="pref_summary_enable_outgoing_call">При отключении данного пункта, Pebble 2/LE также не будет вибрировать при исходящих вызовах</string>
<string name="pref_title_enable_pebblekit">Разрешить доступ приложениям третьих лиц</string>
<string name="pref_title_enable_pebblekit">Разрешить доступ посторонним приложениям</string>
<string name="pref_summary_enable_pebblekit">Добавить экспериментальную поддержку приложений Android, использующих PebbleKit</string>
<string name="pref_title_sunrise_sunset">Восход и закат солнца</string>
<string name="pref_summary_sunrise_sunset">Показывать время восхода и захода солнца в зависимости от местоположения на временной шкале pebble</string>
<string name="pref_summary_sunrise_sunset">Показывать время восхода и захода солнца в зависимости от местоположения на временной шкале Pebble</string>
<string name="pref_title_enable_calendar_sync">Синхронизация календаря</string>
<string name="pref_summary_enable_calendar_sync">Отображать события календаря на временной шкале pebble</string>
<string name="pref_title_autoremove_notifications">Автоматическое удаление отклонённых уведомлений</string>
@ -124,7 +124,7 @@
<string name="toast_enable_networklocationprovider">Пожалуйста, включите сетевое расположение</string>
<string name="toast_aqurired_networklocation">Месторасположение определено</string>
<string name="pref_title_pebble_forceprotocol">Принудительный протокол уведомлений</string>
<string name="pref_summary_pebble_forceprotocol">Эта настройка заставляет принудительно использовать самый новый протокол уведомлений, зависящий от версии прошивки. ВКЛЮЧАЙТЕ, ТОЛЬКО ЕСЛИ ЗНАЕТЕ НА ЧТО ВЫ ИДЁТЕ.</string>
<string name="pref_summary_pebble_forceprotocol">Эта настройка принудительно использует самый новый протокол уведомлений, (зависит от версии прошивки). ВКЛЮЧАЙТЕ, ЕСЛИ ТОЧНО ЗНАЕТЕ, ЗАЧЕМ ВАМ ЭТО!</string>
<string name="pref_title_pebble_forceuntested">Включить непроверенные функции</string>
<string name="pref_summary_pebble_forceuntested">Включить функции, которые не протестированы. ВКЛЮЧАЙТЕ НА СВОЙ СТРАХ И РИСК!</string>
<string name="pref_title_pebble_forcele">Всегда отдавать предпочтение BLE</string>
@ -141,32 +141,32 @@
<string name="pref_title_screentime">Продолжительность работы экрана</string>
<string name="prefs_title_all_day_heart_rate">Измерение сердечного ритма в течение всего дня</string>
<string name="preferences_hplus_settings">Настройки HPlus/Makibes</string>
<string name="not_connected">нет соединения</string>
<string name="connecting">соединение</string>
<string name="connected">соединено</string>
<string name="unknown_state">неизвестное состояние</string>
<string name="not_connected">Нет соединения</string>
<string name="connecting">Соединение</string>
<string name="connected">Соединено</string>
<string name="unknown_state">Непонятное состояние</string>
<string name="_unknown_">(неизвестно)</string>
<string name="test">Тест</string>
<string name="test_notification">Тест уведомлений</string>
<string name="test_notification">Тестовое уведомлений</string>
<string name="this_is_a_test_notification_from_gadgetbridge">Это тестовое уведомление от Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">Bluetooth не поддерживается.</string>
<string name="bluetooth_is_disabled_">Bluetooth отключён.</string>
<string name="tap_connected_device_for_app_mananger">Коснитесь подключённого устройства для вызова Менеджера приложений</string>
<string name="tap_connected_device_for_app_mananger">Коснитесь подключённого устройства для вызова Управления приложениями</string>
<string name="tap_connected_device_for_activity">Коснитесь подключённого устройства для показа Активностей</string>
<string name="tap_connected_device_for_vibration">Коснитесь подключённого устройства для Вибрации</string>
<string name="tap_a_device_to_connect">Коснитесь подключённого устройства для соединения</string>
<string name="cannot_connect_bt_address_invalid_">Не удалось соединиться. Неверен адрес BT?</string>
<string name="tap_a_device_to_connect">Коснитесь устройства для соединения</string>
<string name="cannot_connect_bt_address_invalid_">Не удалось соединиться. Невереный адрес Bluetooth?</string>
<string name="gadgetbridge_running">Gadgetbridge запущен</string>
<string name="installing_binary_d_d">установки бинарного файла %1$d/%2$d</string>
<string name="installation_failed_">установка не удалась!</string>
<string name="installation_successful">установка завершена</string>
<string name="installing_binary_d_d">установка бинарного файла %1$d/%2$d</string>
<string name="installation_failed_">Установка не удалась</string>
<string name="installation_successful">Установка завершена</string>
<string name="firmware_install_warning">ВЫ ПЫТАЕТЕСЬ УСТАНОВИТЬ ПРОШИВКУ, ПРОДОЛЖАЙТЕ НА СВОЙ СТРАХ И РИСК.\n\n\n Эта прошивка для ревизии устройства: %s</string>
<string name="app_install_info">Вы собираетесь установить приложение:\n\n\n%1$s версия %2$s от %3$s\n</string>
<string name="n_a">Недоступно</string>
<string name="initialized">Инициализировано</string>
<string name="appversion_by_creator">%1$s от %2$s</string>
<string name="title_activity_discovery">Поиск устройства</string>
<string name="discovery_stop_scanning">Остановить поиск</string>
<string name="discovery_stop_scanning">Остановить поиск устройств</string>
<string name="discovery_start_scanning">Умный поиск</string>
<string name="action_discover">Подключиться к новому устройству</string>
<string name="device_with_rssi">%1$s (%2$s)</string>
@ -177,13 +177,13 @@
<string name="pairing_creating_bond_with">Привязываюсь к %1$s (%2$s)</string>
<string name="pairing_unable_to_pair_with">Невозможно выполнить сопряжение с %1$s (%2$s)</string>
<string name="pairing_in_progress">Выполняется привязка: %1$s (%2$s)</string>
<string name="pairing_already_bonded">Уже привязан к %1$s (%2$s), выполняется соединение...</string>
<string name="message_cannot_pair_no_mac">MAC-адрес не был передан, сопряжение не удалось.</string>
<string name="pairing_already_bonded">Уже привязан к %1$s (%2$s), выполняется соединение</string>
<string name="message_cannot_pair_no_mac">MAC-адреса нет, сопряжение не удалось.</string>
<string name="preferences_category_device_specific_settings">Настройки устройства</string>
<string name="preferences_miband_settings">Настройки Mi Band</string>
<string name="male">мужской</string>
<string name="female">женский</string>
<string name="other">другой</string>
<string name="preferences_miband_settings">Настройки Mi Band и Amazfit</string>
<string name="male">Мужчина</string>
<string name="female">Женщина</string>
<string name="other">Другой</string>
<string name="left">слева</string>
<string name="right">справа</string>
<string name="miband_pairing_using_dummy_userdata">Не предоставлено действительных данных пользователя. Используются данные по-умолчанию.</string>
@ -194,13 +194,13 @@
<string name="candidate_item_device_image">Изображение устройства</string>
<string name="miband_prefs_alias">Имя/псевдоним</string>
<string name="pref_header_vibration_count">Количество вибраций</string>
<string name="title_activity_sleepmonitor">Анализ сна</string>
<string name="pref_write_logfiles">Сохранять файл журнала</string>
<string name="initializing">Инициализация</string>
<string name="title_activity_sleepmonitor">Анализ фаз сна</string>
<string name="pref_write_logfiles">Сохранять файлы журнала</string>
<string name="initializing">Запускается</string>
<string name="busy_task_fetch_activity_data">Получение данных активности</string>
<string name="sleep_activity_date_range">От %1$s до %2$s</string>
<string name="miband_prefs_wearside">Носите на левой или правой руке?</string>
<string name="pref_screen_vibration_profile">Профиль вибро</string>
<string name="pref_screen_vibration_profile">Профиль настроек вибрации</string>
<string name="vibration_profile_staccato">Стаккато</string>
<string name="vibration_profile_short">Короткий</string>
<string name="vibration_profile_medium">Средний</string>
@ -211,19 +211,19 @@
<string name="miband_prefs_vibration">Вибро</string>
<string name="vibration_try">Попробовать</string>
<string name="pref_screen_notification_profile_sms">SMS-уведомление</string>
<string name="pref_header_vibration_settings">Настройки вибро</string>
<string name="pref_header_vibration_settings">Настройки вибрации</string>
<string name="pref_screen_notification_profile_generic">Общие уведомления</string>
<string name="pref_screen_notification_profile_email">Уведомление по электронной почте</string>
<string name="pref_screen_notification_profile_incoming_call">Уведомления о входящем звонке</string>
<string name="pref_screen_notification_profile_email">Уведомление электронной почты</string>
<string name="pref_screen_notification_profile_incoming_call">Уведомления о входящих звонках</string>
<string name="pref_screen_notification_profile_generic_chat">Чат</string>
<string name="pref_screen_notification_profile_generic_navigation">Навигация</string>
<string name="pref_screen_notification_profile_generic_social">Социальные сети</string>
<string name="control_center_find_lost_device">Найти потерянное устройство</string>
<string name="control_center_cancel_to_stop_vibration">Отмените, чтобы остановить вибро</string>
<string name="control_center_cancel_to_stop_vibration">Отмените, чтобы прекратить вибрацию.</string>
<string name="title_activity_charts">Ваша активность</string>
<string name="title_activity_set_alarm">Завести Будильник</string>
<string name="controlcenter_start_configure_alarms">Завести будильник</string>
<string name="title_activity_alarm_details">Свойства будильника</string>
<string name="controlcenter_start_configure_alarms">Настроить будильники</string>
<string name="title_activity_alarm_details">Настройки будильника</string>
<string name="alarm_sun_short">Вс</string>
<string name="alarm_mon_short">Пн</string>
<string name="alarm_tue_short">Вт</string>
@ -232,7 +232,7 @@
<string name="alarm_fri_short">Пт</string>
<string name="alarm_sat_short">Сб</string>
<string name="alarm_smart_wakeup">умное пробуждение</string>
<string name="user_feedback_miband_set_alarms_failed">Произошла ошибка при настройке будильника, попробуйте ещё!</string>
<string name="user_feedback_miband_set_alarms_failed">Произошла ошибка при настройке будильника, попробуйте ещё раз!</string>
<string name="user_feedback_miband_set_alarms_ok">Будильник был послан на устройство!</string>
<string name="chart_no_data_synchronize">Нет данных. Синхронизировать устройство?</string>
<string name="user_feedback_miband_activity_data_transfer">Будет передано %1$s данных, начиная с %2$s</string>
@ -242,8 +242,8 @@
<string name="cannot_connect">Подключиться не удалось: %1$s</string>
<string name="installer_activity_unable_to_find_handler">Не удалось найти обработчик для установки этого файла.</string>
<string name="pbw_install_handler_unable_to_install">Не удалось установить данный файл: %1$s</string>
<string name="pbw_install_handler_hw_revision_mismatch">Не удалось установить данную прошивку: она не совпадает с версией устройства вашего Pebble</string>
<string name="installer_activity_wait_while_determining_status">Пожалуйста подождите, идёт определение статуса установки...</string>
<string name="pbw_install_handler_hw_revision_mismatch">Не удалось установить прошивку: она не совпадает с версией вашего устройства Pebble.</string>
<string name="installer_activity_wait_while_determining_status">Пожалуйста подождите, проверяется статус установки…</string>
<string name="notif_battery_low_title">Низкий заряд устройства!</string>
<string name="notif_battery_low_percent">%1$s осталось заряда: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Последний раз устройство заряжалось: %s \n</string>
@ -252,8 +252,8 @@
<string name="weeksleepchart_sleep_a_week">Сон за неделю</string>
<string name="weeksleepchart_today_sleep_description">Сон сегодня, цель: %1$s</string>
<string name="weekstepschart_steps_a_week">Шагов в неделю</string>
<string name="activity_sleepchart_activity_and_sleep">Ваша активность и сон</string>
<string name="updating_firmware">Обновление прошивки...</string>
<string name="activity_sleepchart_activity_and_sleep">Ваши активность и сон</string>
<string name="updating_firmware">Обновление прошивки</string>
<string name="fwapp_install_device_not_ready">Файл не может быть установлен, устройство не готово.</string>
<string name="miband_installhandler_miband_firmware">Версия прошивки Mi Band: %1$s</string>
<string name="miband_fwinstaller_compatible_version">Совместимая версия</string>
@ -266,7 +266,7 @@
<string name="updatefirmwareoperation_updateproblem_do_not_reboot">Проблема с передачей прошивки. НЕ ПЕРЕЗАГРУЖАЙТЕ ваш Mi Band!</string>
<string name="updatefirmwareoperation_metadata_updateproblem">Проблема с передачей метаданных прошивки</string>
<string name="updatefirmwareoperation_update_complete">Установка прошивки завершена</string>
<string name="updatefirmwareoperation_update_complete_rebooting">Установка прошивки завершена, устройство перезагружается...</string>
<string name="updatefirmwareoperation_update_complete_rebooting">Установка прошивки завершена, устройство перезагружается</string>
<string name="updatefirmwareoperation_write_failed">Запись прошивки завершилась неудачей</string>
<string name="chart_steps">Шаги</string>
<string name="calories">Калории</string>
@ -284,12 +284,12 @@
<string name="live_activity_steps_per_minute_history">История шагов за минуту</string>
<string name="live_activity_start_your_activity">Начните вашу активность</string>
<string name="abstract_chart_fragment_kind_activity">Активность</string>
<string name="abstract_chart_fragment_kind_light_sleep">Неглубокий сон</string>
<string name="abstract_chart_fragment_kind_light_sleep">Быстрый сон</string>
<string name="abstract_chart_fragment_kind_deep_sleep">Глубокий сон</string>
<string name="abstract_chart_fragment_kind_not_worn">Не носилось</string>
<string name="device_not_connected">Не подключен.</string>
<string name="user_feedback_all_alarms_disabled">Все будильники отключены</string>
<string name="pref_title_keep_data_on_device">Храните данные о деятельности на устройстве</string>
<string name="pref_title_keep_data_on_device">Хранить данные об активности на устройстве</string>
<string name="miband_fwinstaller_incompatible_version">Несовместимая прошивка</string>
<string name="fwinstaller_firmware_not_compatible_to_device">Эта прошивка не совместима с устройством</string>
<string name="miband_prefs_reserve_alarm_calendar">Резервные сигналы для предстоящих событий</string>
@ -297,7 +297,7 @@
<string name="miband_prefs_device_time_offset_hours">Смещение времени в часах (для тех, кто работает по ночам)</string>
<string name="miband2_prefs_dateformat">Mi2: Формат даты</string>
<string name="dateformat_time">Время</string>
<string name="dateformat_date_time"><![CDATA[Время и Дата]]></string>
<string name="dateformat_date_time">Время и дата</string>
<string name="mi2_prefs_activate_display_on_lift">Активировать экран при подъёме</string>
<string name="FetchActivityOperation_about_to_transfer_since">Готов к передачи данных с %1$s</string>
<string name="waiting_for_reconnect">Ожидание переподключения</string>
@ -308,71 +308,163 @@
<string name="activity_prefs_weight_kg">Вес в кг</string>
<string name="authenticating">Авторизация</string>
<string name="authentication_required">Требуется авторизация</string>
<string name="appwidget_text">Zzz</string>
<string name="appwidget_text">Хрр</string>
<string name="add_widget">Добавить виджет</string>
<string name="activity_prefs_sleep_duration">Желаемая продолжительность сна</string>
<string name="appwidget_alarms_set">Будильник был установлен на %1$02d:%2$02d</string>
<string name="device_hw">Версия устройства: %1$s</string>
<string name="device_fw"> Версия ПО: %1$s</string>
<string name="device_fw">Версия прошивки: %1$s</string>
<string name="error_creating_directory_for_logfiles">Ошибка создания каталога для лог-файлов: %1$s</string>
<string name="DEVINFO_HR_VER">HR:</string>
<string name="updatefirmwareoperation_update_in_progress">Обновление прошивки в процессе</string>
<string name="DEVINFO_HR_VER">"Версия устройства: "</string>
<string name="updatefirmwareoperation_update_in_progress">Происходит обновление прошивки</string>
<string name="updatefirmwareoperation_firmware_not_sent">Прошивка не отправлена</string>
<string name="charts_legend_heartrate">Пульс</string>
<string name="live_activity_heart_rate">Пульс</string>
<string name="pref_title_pebble_health_store_raw">Хранить необработанные записи в базе данных</string>
<string name="pref_summary_pebble_health_store_raw">Если флажок установлен, данные сохраняются «как есть» и доступны для последующей интерпретации. NB: база данных будет занимать больше места в этом случае!</string>
<string name="pref_summary_pebble_health_store_raw">Если флажок установлен, данные сохраняются как есть, в дальнейшем их можно обрабатывать. Обратите внимание: в этом случае база данных будет занимать больше места!</string>
<string name="action_db_management">Управление базой данных</string>
<string name="title_activity_db_management">Управление базой данных</string>
<string name="activity_db_management_import_export_explanation">Операции с базой данных используют на вашем устройстве следующий путь. \n Этот путь доступен для других приложений Android и вашего компьютера. \n Вы можете найти вашу экспортированную базу данных (или разместить базу данных, которую вы хотите импортировать) здесь:</string>
<string name="activity_db_management_merge_old_title">Удаление устаревшей базой данных</string>
<string name="dbmanagementactivvity_cannot_access_export_path">Невозможно получить доступ к пути экспорта. Обратитесь пожалуйста к разработчикам.</string>
<string name="activity_db_management_import_export_explanation">"Операции с базой данных используют этот путь на вашем устройстве.
\nОн доступен для других приложений Android и вашего компьютера.
\nВы можете найти экспортированную базу данных (или разместить базу данных, которую вы хотите импортировать) здесь:"</string>
<string name="activity_db_management_merge_old_title">Удаление устаревшей базы данных</string>
<string name="dbmanagementactivvity_cannot_access_export_path">Нет доступа к пути экспорта. Обратитесь, пожалуйста, к разработчикам.</string>
<string name="dbmanagementactivity_exported_to">Экспортировано в: %1$s</string>
<string name="dbmanagementactivity_error_exporting_db">Ошибка экспорта базы данных: %1$s</string>
<string name="dbmanagementactivity_error_exporting_shared">Ошибка экспорта настроек: %1$s</string>
<string name="dbmanagementactivity_import_data_title">Импортировать данные?</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Действительно перезаписать текущую базу данных? Все ваши текущие данные по вашей активности (если они есть) будут потеряны.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Точно перезаписать текущую базу данных? Все текущие данные вашей активности (если они есть) будут утеряны.</string>
<string name="dbmanagementactivity_import_successful">Импорт успешно завершён.</string>
<string name="dbmanagementactivity_error_importing_db">Ошибка импорта БД: %1$s</string>
<string name="dbmanagementactivity_error_importing_db">Ошибка импорта базы данных: %1$s</string>
<string name="dbmanagementactivity_error_importing_shared">Ошибка импорта настроек: %1$s</string>
<string name="dbmanagementactivity_delete_activity_data_title">Удалить данные по вашей активности?</string>
<string name="dbmanagementactivity_really_delete_entire_db">Действительно удалить всю базу данных? Все данные о вашей активности и информация о ваших устройствах будут потеряны.</string>
<string name="dbmanagementactivity_really_delete_entire_db">Действительно удалить всю базу данных? Все данные о вашей активности и информация о ваших устройствах будут утеряны.</string>
<string name="dbmanagementactivity_database_successfully_deleted">Данные успешно удалены.</string>
<string name="dbmanagementactivity_db_deletion_failed">Не удалось удалить базу данных.</string>
<string name="dbmanagementactivity_delete_old_activity_db">Удалить данные по вашей активности?</string>
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">Вы действительно хотите удалить устаревшие данные по вашей активности? Все данные о вашей активности, которые не были импортированы, будут потеряны.</string>
<string name="dbmanagementactivity_db_deletion_failed">Удалить базу данных не получилось.</string>
<string name="dbmanagementactivity_delete_old_activity_db">Удалить данные по предыдущей активности?</string>
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">Точно удалить старые данные об активности? Все не импортированные данные об активности будут утеряны.</string>
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Устаревшие данные по вашей активности успешно удалены.</string>
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Не удалось удалить устаревшие данные по вашей активности.</string>
<string name="dbmanagementactivity_old_activity_db_deletion_failed">Удалить устаревшие данные по вашей активности не получилось.</string>
<string name="dbmanagementactivity_overwrite">Перезаписать</string>
<string name="Cancel">Отмена</string>
<string name="Delete">Удалить</string>
<!--Strings related to Vibration Activity-->
<string name="title_activity_vibration">Вибрация</string>
<!--Strings related to Pebble Pairing Activity-->
<string name="title_activity_pebble_pairing">Pebble Сопряжение</string>
<string name="pebble_pairing_hint">На вашем Android устройстве должно появиться всплывающее окно с предложением сопряжения устройств. Если этого не произошло, загляните в ящик уведомлений и примите запрос на сопряжение. После этого примите запрос сопряжения на вашем Pebble</string>
<string name="weather_notification_label">Убедитесь, что оболочка выбрана в приложении «Уведомление о погоде», чтобы получать информацию о погоде на вашем Pebble.\n\nНикакой настройки здесь не требуется.\n\nВы можете включить приложение погоды вашего Pebble из управления приложениями.\n\nПоддерживаемые циферблаты покажут погоду автоматически.</string>
<string name="title_activity_pebble_pairing">Сопряжение с Pebble</string>
<string name="pebble_pairing_hint">На вашем Android устройстве должно появиться всплывающее окно с запросом на сопряжение устройств. Если этого не произошло, загляните в ящик уведомлений и примите запрос на сопряжение. После этого примите запрос сопряжения на вашем устройстве Pebble</string>
<string name="weather_notification_label">Чтобы получать информацию о погоде на вашем Pebble, убедитесь, что выбрали эту тему в приложении «Уведомление о погоде».
\n
\nДополнительная настройка не нужна.
\n
\nВключить приложение погоды на вашем Pebble можно из \"Управления приложениями\".
\n
\nПоддерживаемые циферблаты покажут погоду автоматически.</string>
<string name="pref_title_setup_bt_pairing">Включить сопряжение по Bluetooth</string>
<string name="pref_summary_setup_bt_pairing">Выключите данный пункт, если у вас возникли проблемы с подключением</string>
<string name="unit_metric">Метрическая система</string>
<string name="unit_imperial">Приоритетный</string>
<string name="timeformat_24h">24ч</string>
<string name="timeformat_am_pm">12ч</string>
<string name="pref_summary_setup_bt_pairing">Отключите, если вам не удалось подключиться</string>
<string name="unit_metric">Метрическая система мер</string>
<string name="unit_imperial">Английская система мер</string>
<string name="timeformat_24h">24 ч</string>
<string name="timeformat_am_pm">12 ч</string>
<string name="pref_screen_notification_profile_alarm_clock">Будильник</string>
<string name="StringUtils_sender">(%1$s)</string>
<string name="find_device_you_found_it">Вы нашли!</string>
<string name="miband2_prefs_timeformat">Mi2: Формат Времени</string>
<string name="mi2_fw_installhandler_fw53_hint">Вам необходимо установить версию %1$s до того как установить данную прошивку!</string>
<string name="find_device_you_found_it">Нашёлся!</string>
<string name="miband2_prefs_timeformat">Mi2: Формат времени</string>
<string name="mi2_fw_installhandler_fw53_hint">До того как установить эту прошивку, нужно установить предыдущую версию %1$s!</string>
<string name="mi2_enable_text_notifications">Текстовые уведомления</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Требуется прошивка >= 1.0.1.28 и установленный Mili_pro.ft* .]]></string>
<string name="off">Выкл.</string>
<string name="discovery_attempting_to_pair">Попытка сопряжения с %1$s</string>
<string name="discovery_bonding_failed_immediately">Не удалось выполнить привязку к %1$s</string>
<string name="discovery_bonding_failed_immediately">Не удалось выполнить привязку к %1$s.</string>
<string name="discovery_trying_to_connect_to">Попытка соединения с: %1$s</string>
<string name="discovery_enable_bluetooth">Включить Bluetooth для обнаружения устройств.</string>
<string name="discovery_successfully_bonded">Привязка к %1$s успешно выполнена.</string>
<string name="discovery_pair_title">Выполнить сопряжение с %1$s ?</string>
<string name="discovery_pair_question">Выберите \"Сопряжение\" для сопряжения ваших устройств, если этого сделать не получилось, попробуйте снова без сопряжения.</string>
<string name="discovery_pair_question">Выберите \"Сопряжение\" для сопряжения ваших устройств. Если не получилось, попробуйте снова без сопряжения.</string>
<string name="discovery_yes_pair">Сопряжение</string>
<string name="discovery_dont_pair">Не выполнять сопряжение</string>
</resources>
<string name="action_donate">Пожертвовать</string>
<string name="controlcenter_connect">Подключить</string>
<string name="title_activity_calblacklist">Заблокированные календари</string>
<string name="fw_upgrade_notice_amazfitbip">"Вы собираетесь установить прошивку %s на ваш Amazfit Bip.
\n
\nПеред этим, пожалуйста, установите файл .gps, файл .res и последним — .fw файл. После установки .fw файла устройство перезагрузится.
\n
\nОбратите внимание: если файлы .gps и .res такие же, как в текущей версии, их не нужно переустанавливать.
\n
\nВы действуете на свой страх и риск!"</string>
<string name="fw_upgrade_notice_amazfitcor">Вы собираетесь установить прошивку %s на ваш Amazonfit Cor.
\n
\nПеред этим, пожалуйста, установите файл .res и файл .fw. После установки файла .fw ваше устройство перезагрузится.
\n
\nОбратие внимание: если версия файла .res совпадает с предыдущей, его не нужно переустанавливать.
\n
\nЭту прошивку не проверяли, поэтому есть вероятность сломать ваше устройство. Действуйте на свой страх и риск!</string>
<string name="pref_title_charts_swipe">Включить жесты \"провести направо и налево\" в графиках активности</string>
<string name="pref_blacklist_calendars">Заблокировать Календари</string>
<string name="pref_header_pebble_timeline">Временной график Pebble</string>
<string name="pref_title_pebble_enable_bgjs">Включить JS в фоновом режиме</string>
<string name="pref_summary_pebble_enable_bgjs">Включают, чтобы видеть погоду, заряд батарейки и т.д. на циферблате.</string>
<string name="activity_web_view">Веб-отчёт активности</string>
<string name="mi2_dnd_off">Выкл.</string>
<string name="mi2_dnd_automatic">Автоматически (определяет режим сна)</string>
<string name="mi2_dnd_scheduled">Запланировано (промежуток времени)</string>
<string name="_pebble_watch_open_on_phone">Открыть в устройстве</string>
<string name="_pebble_watch_mute">Отключить звук</string>
<string name="_pebble_watch_reply">Ответить</string>
<string name="preferences_amazfitbip_settings">Настройки Amazfit Bip</string>
<string name="stats_title">Зоны скорости</string>
<string name="stats_x_axis_label">Всего минут</string>
<string name="stats_y_axis_label">Шагов в минуту</string>
<string name="amazfitbip_firmware">Прошивка Amazfit Bip версии %1$s</string>
<string name="amazfitcor_firmware">Прошивка Amazfit Cor версии %1$s</string>
<string name="clock">Часы</string>
<string name="heart_rate">Пульс</string>
<string name="battery">Заряд батарейки</string>
<string name="mi2_prefs_button_actions">Действия кнопки</string>
<string name="mi2_prefs_button_actions_summary">Настройте действия при нажатии на кнопку вашего Mi Band 2</string>
<string name="mi2_prefs_button_press_count">Нажатий на кнопку</string>
<string name="mi2_prefs_button_press_count_summary">Количество нажатий, необходимое чтобы запустить трансляцию сообщений</string>
<string name="mi2_prefs_button_press_broadcast">Сообщение для трансляции</string>
<string name="mi2_prefs_button_press_broadcast_summary">Заданное количество нажатий для трансляции сообщения выполнено</string>
<string name="mi2_prefs_button_action">Включить действия при нажатии на кнопку</string>
<string name="mi2_prefs_button_action_summary">Включить действия для заданного количества нажатий на кнопку</string>
<string name="mi2_prefs_button_action_vibrate">Включить вибрацию</string>
<string name="mi2_prefs_button_action_vibrate_summary">Включить вибрацию браслета в ответ на исполняющееся при нажатии действие</string>
<string name="mi2_prefs_button_press_count_max_delay">Максимальная задержка между нажатиями</string>
<string name="mi2_prefs_button_press_count_max_delay_summary">Максимальная задержка между нажатиями в миллисекундах</string>
<string name="mi2_prefs_button_press_count_match_delay">Задержка после действия при нажатии</string>
<string name="mi2_prefs_button_press_count_match_delay_summary">Задержка при выполнении заданного количества нажатий для однократного действия (число указано в button_id). Это число равно нулю для действий без задержки</string>
<string name="mi2_prefs_goal_notification">Уведомления о достижении цели</string>
<string name="mi2_prefs_goal_notification_summary">Браслет завибрирует, когда будет выполнена дневная норма шагов</string>
<string name="mi2_prefs_display_items">Что показывать на экране</string>
<string name="mi2_prefs_display_items_summary">Выберите, что показывать на экране браслета</string>
<string name="mi2_prefs_rotate_wrist_to_switch_info">Поверните запястье, чтобы переключиться на другую информацию</string>
<string name="mi2_prefs_do_not_disturb">Не беспокоить</string>
<string name="mi2_prefs_do_not_disturb_summary">Браслет не будет получать уведомления, даже если включён</string>
<string name="mi2_prefs_inactivity_warnings">Напоминания о низкой активности</string>
<string name="mi2_prefs_inactivity_warnings_summary">Когда вы мало двигаетесь, браслет время от времени вибрирует</string>
<string name="mi2_prefs_inactivity_warnings_threshold">Период низкой активности (в минутах)</string>
<string name="mi2_prefs_inactivity_warnings_dnd_summary">Отключить уведомления о низкой активности во время режима \"Не беспокоить\"</string>
<string name="mi2_prefs_do_not_disturb_start">Начало режим \"Не беспокоить\"</string>
<string name="mi2_prefs_do_not_disturb_end">Окончание режима \"Не беспокоить\"</string>
<string name="automatic">Автоматически</string>
<string name="simplified_chinese">Упрощённый китайский язык</string>
<string name="traditional_chinese">Традиционный китайский язык</string>
<string name="english">Английский язык</string>
<string name="prefs_title_heartrate_measurement_interval">Измерение пульса в течение целого дня</string>
<string name="interval_one_minute">раз в минуту</string>
<string name="interval_five_minutes">раз в 5 минут</string>
<string name="interval_ten_minutes">раз в 10 минут</string>
<string name="interval_thirty_minutes">раз в полчаса</string>
<string name="interval_one_hour">раз в час</string>
</resources>

View File

@ -236,4 +236,6 @@
<!--Strings related to Pebble Pairing Activity-->
<string name="timeformat_24h">24г</string>
<string name="timeformat_am_pm">ДП/ПП</string>
</resources>
<string name="action_donate">Пожертвувати</string>
<string name="controlcenter_connect">З\'єднати</string>
</resources>

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

@ -1,5 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
<release version="0.22.5" versioncode="113">
<change>Unlock Teclast H10 support using the same code as H30</change>
<change>Amazfit Bip: Fix installation of 0.1.0.11 Firmware</change>
<change>Amazfit Bip/Cor: Send three days of weather forecast including (untranslated) conditions</change>
<change>Workaround for a crash on Android 4.4 when connecting</change>
</release>
<release version="0.22.4" versioncode="112">
<change>Mi Band 2/Bip/Cor: Whole day HR support</change>
<change>Mi Band 2/Bip/Cor: Prevent writing a lot of HR samples to the database when not using the live activity feature</change>
<change>Pebble: Fix some nasty crashes which occur since 0.22.0</change>
<change>Workround for non-working notifcations from wechat and outlook</change>
</release>
<release version="0.22.3" versioncode="111">
<change>Amazfit Bip: Allow flashing watchfaces</change>
<change>Amazfit Cor: Fix flashing new .res files</change>

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"

View File

@ -3,9 +3,10 @@
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.android.tools.build:gradle:3.0.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@ -18,5 +19,6 @@ allprojects {
maven {
url "https://jitpack.io"
}
google()
}
}

View File

@ -0,0 +1,4 @@
* Mi Band 2/Bip/Cor: Whole day HR support
* Mi Band 2/Bip/Cor: Prevent writing a lot of HR samples to the database when not using the live activity feature
* Pebble: Fix some nasty crashes which occur since 0.22.0
* Workround for non-working notifcations from wechat and outlook

View File

@ -0,0 +1,4 @@
* Unlock Teclast H10 support using the same code as H30
* Amazfit Bip: Fix installation of 0.1.0.11 Firmware
* Amazfit Bip/Cor: Send three days of weather forecast including (untranslated) conditions
* Workaround for a crash on Android 4.4 when connecting

View File

@ -16,4 +16,5 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# org.gradle.parallel=true
android.enableAapt2=false