mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-25 11:26:47 +01:00
Merge branch 'master' of https://codeberg.org/Freeyourgadget/Gadgetbridge into fossil-q-hr
This commit is contained in:
commit
6f012c2109
@ -1,6 +1,12 @@
|
||||
### Changelog
|
||||
|
||||
#### Version 0.40.0 (WIP)
|
||||
#### Version 0.40.1
|
||||
* Mi Band/Amazfit: Recogize changes when toggling alarm on device (immediately when connected, else when connecting)
|
||||
* Mi Band/Amazfit: Fix some bugs with stuck connection when re-connecting
|
||||
* Mi Band 4: Support higher MTU for multiple times faster firmware transfer (probably also Amazfit GTR/GTS)
|
||||
* Amazfit Cor: Fix setting language to Chinese manually
|
||||
|
||||
#### Version 0.40.0
|
||||
* Fossil Q Hybrid: Initial support
|
||||
* Bangle.js: Initial support
|
||||
* Reserve Alarm for Calendar feature restricted to Mi Band 1/2 and moved to per-device settings
|
||||
|
@ -15,8 +15,6 @@
|
||||
*/
|
||||
package nodomain.freeyourgadget.gadgetbridge.daogen;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import de.greenrobot.daogenerator.DaoGenerator;
|
||||
import de.greenrobot.daogenerator.Entity;
|
||||
import de.greenrobot.daogenerator.Index;
|
||||
@ -45,7 +43,7 @@ public class GBDaoGenerator {
|
||||
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Schema schema = new Schema(21, MAIN_PACKAGE + ".entities");
|
||||
Schema schema = new Schema(22, MAIN_PACKAGE + ".entities");
|
||||
|
||||
Entity userAttributes = addUserAttributes(schema);
|
||||
Entity user = addUserInfo(schema, userAttributes);
|
||||
@ -378,6 +376,7 @@ public class GBDaoGenerator {
|
||||
);
|
||||
alarm.addIntProperty("hour").notNull();
|
||||
alarm.addIntProperty("minute").notNull();
|
||||
alarm.addBooleanProperty("unused").notNull();
|
||||
alarm.addToOne(user, userId);
|
||||
alarm.addToOne(device, deviceId);
|
||||
}
|
||||
|
@ -80,6 +80,7 @@ Please see [FEATURES.md](https://codeberg.org/Freeyourgadget/Gadgetbridge/src/ma
|
||||
* Johannes Schmitt (BFH-16)
|
||||
* Lukas Schwichtenberg (Makibes HR3)
|
||||
* Daniel Dakhno (Fossil Q Hybrid)
|
||||
* Gordon Williams (Bangle.js)
|
||||
|
||||
## Contribute
|
||||
|
||||
|
@ -25,8 +25,8 @@ android {
|
||||
targetSdkVersion 27
|
||||
|
||||
// Note: always bump BOTH versionCode and versionName!
|
||||
versionName "0.40.0"
|
||||
versionCode 163
|
||||
versionName "0.40.1"
|
||||
versionCode 164
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
}
|
||||
buildTypes {
|
||||
|
@ -17,18 +17,23 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.GBAlarmListAdapter;
|
||||
@ -40,6 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.User;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AlarmUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
|
||||
@ -59,6 +65,10 @@ public class ConfigureAlarms extends AbstractGBActivity {
|
||||
|
||||
setContentView(R.layout.activity_configure_alarms);
|
||||
|
||||
IntentFilter filterLocal = new IntentFilter();
|
||||
filterLocal.addAction(DeviceService.ACTION_SAVE_ALARMS);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||
|
||||
gbDevice = getIntent().getParcelableExtra(GBDevice.EXTRA_DEVICE);
|
||||
|
||||
mGBAlarmListAdapter = new GBAlarmListAdapter(this);
|
||||
@ -136,7 +146,7 @@ public class ConfigureAlarms extends AbstractGBActivity {
|
||||
}
|
||||
|
||||
private Alarm createDefaultAlarm(@NonNull Device device, @NonNull User user, int position) {
|
||||
return new Alarm(device.getId(), user.getId(), position, false, false,0, 6, 30);
|
||||
return new Alarm(device.getId(), user.getId(), position, false, false, 0, 6, 30, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -165,4 +175,25 @@ public class ConfigureAlarms extends AbstractGBActivity {
|
||||
private void sendAlarmsToDevice() {
|
||||
GBApplication.deviceService().onSetAlarms(mGBAlarmListAdapter.getAlarmList());
|
||||
}
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
switch (action) {
|
||||
case DeviceService.ACTION_SAVE_ALARMS: {
|
||||
updateAlarmsFromDB();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
LocalBroadcastManager.getInstance(this).unregisterReceiver(mReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -27,12 +27,13 @@ import android.widget.CompoundButton;
|
||||
import android.widget.Switch;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.cardview.widget.CardView;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ConfigureAlarms;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
@ -71,7 +72,7 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
|
||||
public void onBindViewHolder(@NonNull final ViewHolder holder, final int position) {
|
||||
|
||||
final Alarm alarm = alarmList.get(position);
|
||||
|
||||
@ -82,7 +83,7 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
holder.alarmDayFriday.setChecked(alarm.getRepetition(Alarm.ALARM_FRI));
|
||||
holder.alarmDaySaturday.setChecked(alarm.getRepetition(Alarm.ALARM_SAT));
|
||||
holder.alarmDaySunday.setChecked(alarm.getRepetition(Alarm.ALARM_SUN));
|
||||
|
||||
holder.container.setAlpha(alarm.getUnused() ? 0.5f : 1.0f);
|
||||
holder.isEnabled.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
@ -97,6 +98,16 @@ public class GBAlarmListAdapter extends RecyclerView.Adapter<GBAlarmListAdapter.
|
||||
((ConfigureAlarms) mContext).configureAlarm(alarm);
|
||||
}
|
||||
});
|
||||
holder.container.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
alarm.setUnused(!alarm.getUnused());
|
||||
holder.container.setAlpha(alarm.getUnused() ? 0.5f : 1.0f);
|
||||
updateInDB(alarm);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
holder.alarmTime.setText(DateTimeUtils.formatTime(alarm.getHour(), alarm.getMinute()));
|
||||
holder.isEnabled.setChecked(alarm.getEnabled());
|
||||
if (alarm.getSmartWakeup()) {
|
||||
|
@ -0,0 +1,39 @@
|
||||
/* Copyright (C) 2019 Andreas Shimokawa
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.database.schema;
|
||||
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.AlarmDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.No1F1ActivitySampleDao;
|
||||
|
||||
public class GadgetbridgeUpdate_22 implements DBUpdateScript {
|
||||
@Override
|
||||
public void upgradeSchema(SQLiteDatabase db) {
|
||||
if (!DBHelper.existsColumn(AlarmDao.TABLENAME, AlarmDao.Properties.Unused.columnName, db)) {
|
||||
String ADD_COLUMN_UNUSED = "ALTER TABLE " + AlarmDao.TABLENAME + " ADD COLUMN "
|
||||
+ AlarmDao.Properties.Unused.columnName + " INTEGER NOT NULL DEFAULT 0;";
|
||||
db.execSQL(ADD_COLUMN_UNUSED);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void downgradeSchema(SQLiteDatabase db) {
|
||||
}
|
||||
}
|
@ -1,3 +1,19 @@
|
||||
/* Copyright (C) 2019 Gordon Williams
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.banglejs;
|
||||
|
||||
import java.util.UUID;
|
||||
|
@ -1,3 +1,20 @@
|
||||
/* Copyright (C) 2016-2019 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||
Gobbetti, Gordon Williams, José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.banglejs;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
|
@ -59,6 +59,7 @@ public class HuamiService {
|
||||
public static final int ALERT_LEVEL_PHONE_CALL = 2;
|
||||
public static final int ALERT_LEVEL_VIBRATE_ONLY = 3;
|
||||
|
||||
|
||||
// set metric distance
|
||||
// set 12 hour time mode
|
||||
|
||||
@ -158,6 +159,9 @@ public class HuamiService {
|
||||
public static final byte[] COMMAND_ENABLE_DISCONNECT_NOTIFCATION = new byte[]{ENDPOINT_DISPLAY, 0x0c, 0x00, 0x01, 0, 0, 0, 0};
|
||||
public static final byte[] COMMAND_DISABLE_DISCONNECT_NOTIFCATION = new byte[]{ENDPOINT_DISPLAY, 0x0c, 0x00, 0x00, 0, 0, 0, 0};
|
||||
|
||||
public static final byte[] COMMAND_REQUEST_ALARMS = new byte[]{0x0d};
|
||||
public static final byte[] COMMAND_REQUEST_GPS_VERSION = new byte[]{0x0e};
|
||||
|
||||
// The third byte controls the threshold, in minutes
|
||||
// The last 8 bytes represent 2 separate time intervals for the inactivity warnings
|
||||
// If there is no do not disturb interval, the last 4 bytes (the second interval) are 0
|
||||
|
@ -26,9 +26,6 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService.EN
|
||||
public class AmazfitBipService {
|
||||
public static final UUID UUID_CHARACTERISTIC_WEATHER = UUID.fromString("0000000e-0000-3512-2118-0009af100700");
|
||||
|
||||
// goes to UUID_CHARACTERISTIC_3_CONFIGURATION, TODO: validate this for Mi Band 2, it maybe triggers more than only GPS version...
|
||||
public static final byte[] COMMAND_REQUEST_GPS_VERSION = new byte[]{0x0e};
|
||||
|
||||
public static final byte COMMAND_ACTIVITY_DATA_TYPE_DEBUGLOGS = 0x07;
|
||||
|
||||
public static final byte[] COMMAND_SET_LANGUAGE_SIMPLIFIED_CHINESE = new byte[]{ENDPOINT_DISPLAY, 0x13, 0x00, 0x00};
|
||||
|
@ -37,6 +37,8 @@ public interface Alarm extends Serializable {
|
||||
|
||||
boolean getEnabled();
|
||||
|
||||
boolean getUnused();
|
||||
|
||||
boolean getSmartWakeup();
|
||||
|
||||
int getRepetition();
|
||||
|
@ -53,6 +53,7 @@ public interface DeviceService extends EventHandler {
|
||||
String ACTION_FIND_DEVICE = PREFIX + ".action.find_device";
|
||||
String ACTION_SET_CONSTANT_VIBRATION = PREFIX + ".action.set_constant_vibration";
|
||||
String ACTION_SET_ALARMS = PREFIX + ".action.set_alarms";
|
||||
String ACTION_SAVE_ALARMS = PREFIX + ".action.save_alarms";
|
||||
String ACTION_ENABLE_REALTIME_STEPS = PREFIX + ".action.enable_realtime_steps";
|
||||
String ACTION_REALTIME_SAMPLES = PREFIX + ".action.realtime_samples";
|
||||
String ACTION_ENABLE_REALTIME_HEARTRATE_MEASUREMENT = PREFIX + ".action.realtime_hr_measurement";
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Copyright (C) 2015-2019 Andreas Böhler, Andreas Shimokawa, Carsten
|
||||
Pfeiffer, Cre3per, Daniel Dakhno, Daniele Gobbetti, Jean-François Greffier,
|
||||
João Paulo Barraca, José Rebelo, Kranz, ladbsoft, Manuel Ruß, maxirnilian,
|
||||
protomors, Quallenauge, Sami Alaoui, Sebastian Kranz, Sophanimus, tiparega,
|
||||
Vadim Kaushan
|
||||
Pfeiffer, Cre3per, Daniel Dakhno, Daniele Gobbetti, Gordon Williams,
|
||||
Jean-François Greffier, João Paulo Barraca, José Rebelo, Kranz, ladbsoft,
|
||||
Manuel Ruß, maxirnilian, protomors, Quallenauge, Sami Alaoui, Sebastian
|
||||
Kranz, Sophanimus, tiparega, Vadim Kaushan
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
|
@ -287,7 +287,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
|
||||
if (mDeviceSupport == null || (!isInitialized() && !mDeviceSupport.useAutoConnect())) {
|
||||
if (mDeviceSupport == null || (!isInitialized() && !action.equals(ACTION_DISCONNECT) && (!mDeviceSupport.useAutoConnect() || isConnected()))) {
|
||||
// trying to send notification without valid Bluetooth connection
|
||||
if (mGBDevice != null) {
|
||||
// at least send back the current device state
|
||||
@ -814,6 +814,7 @@ public class DeviceCommunicationService extends Service implements SharedPrefere
|
||||
}
|
||||
if (mAutoConnectInvervalReceiver != null) {
|
||||
unregisterReceiver(mAutoConnectInvervalReceiver);
|
||||
mAutoConnectInvervalReceiver.destroy();
|
||||
mAutoConnectInvervalReceiver = null;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* Copyright (C) 2015-2019 0nse, Andreas Böhler, Andreas Shimokawa, Carsten
|
||||
Pfeiffer, Cre3per, criogenic, Daniel Dakhno, Daniele Gobbetti, Jean-François
|
||||
Greffier, João Paulo Barraca, José Rebelo, Kranz, ladbsoft, Manuel Ruß,
|
||||
maxirnilian, protomors, Quallenauge, Sami Alaoui, Sergey Trofimov, Sophanimus,
|
||||
tiparega, Vadim Kaushan
|
||||
Pfeiffer, Cre3per, criogenic, Daniel Dakhno, Daniele Gobbetti, Gordon Williams,
|
||||
Jean-François Greffier, João Paulo Barraca, José Rebelo, Kranz, ladbsoft,
|
||||
Manuel Ruß, maxirnilian, protomors, Quallenauge, Sami Alaoui, Sergey Trofimov,
|
||||
Sophanimus, tiparega, Vadim Kaushan
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
|
@ -265,9 +265,6 @@ public final class BtLEQueue {
|
||||
|
||||
mGbDevice.setState(newState);
|
||||
mGbDevice.sendDeviceUpdateIntent(mContext);
|
||||
if (mConnectionLatch != null && newState == State.CONNECTED) {
|
||||
mConnectionLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect() {
|
||||
@ -516,6 +513,9 @@ public final class BtLEQueue {
|
||||
// only propagate the successful event
|
||||
getCallbackToUse().onServicesDiscovered(gatt);
|
||||
}
|
||||
if (mConnectionLatch != null) {
|
||||
mConnectionLatch.countDown();
|
||||
}
|
||||
} else {
|
||||
LOG.warn("onServicesDiscovered received: " + status);
|
||||
}
|
||||
|
@ -1,3 +1,19 @@
|
||||
/* Copyright (C) 2015-2019 Andreas Shimokawa, Carsten Pfeiffer, Daniel Dakhno
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
|
@ -1,3 +1,19 @@
|
||||
/* Copyright (C) 2019 Andreas Shimokawa, Gordon Williams
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.banglejs;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
|
@ -30,5 +30,6 @@ public class HuamiDeviceEvent {
|
||||
public static final byte BUTTON_PRESSED_LONG = 0x0b;
|
||||
public static final byte TICK_30MIN = 0x0e; // unsure
|
||||
public static final byte FIND_PHONE_STOP = 0x0f;
|
||||
public static final byte MTU_REQUEST = 0x16;
|
||||
public static final byte MUSIC_CONTROL = (byte) 0xfe;
|
||||
}
|
||||
|
@ -143,6 +143,7 @@ import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.ge
|
||||
import static nodomain.freeyourgadget.gadgetbridge.devices.miband.MiBandConst.getNotificationPrefStringValue;
|
||||
import static nodomain.freeyourgadget.gadgetbridge.service.btle.GattCharacteristic.UUID_CHARACTERISTIC_ALERT_LEVEL;
|
||||
|
||||
|
||||
public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
|
||||
// We introduce key press counter for notification purposes
|
||||
@ -164,7 +165,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
};
|
||||
|
||||
private BluetoothGattCharacteristic characteristicHRControlPoint;
|
||||
protected BluetoothGattCharacteristic characteristicChunked;
|
||||
private BluetoothGattCharacteristic characteristicChunked;
|
||||
|
||||
private boolean needsAuth;
|
||||
private volatile boolean telephoneRinging;
|
||||
@ -181,6 +182,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
private MusicSpec bufferMusicSpec = null;
|
||||
private MusicStateSpec bufferMusicStateSpec = null;
|
||||
private boolean heartRateNotifyEnabled;
|
||||
private int mMTU = 23;
|
||||
|
||||
public HuamiSupport() {
|
||||
this(LOG);
|
||||
@ -293,15 +295,16 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
builder.notify(getCharacteristic(GattService.UUID_SERVICE_CURRENT_TIME), enable);
|
||||
// Notify CHARACTERISTIC9 to receive random auth code
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_AUTH), enable);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public HuamiSupport enableFurtherNotifications(TransactionBuilder builder, boolean enable) {
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), enable);
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_6_BATTERY_INFO), enable);
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_DEVICEEVENT), enable);
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_AUDIO), enable);
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_AUDIODATA), enable);
|
||||
builder.notify(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_DEVICEEVENT), enable);
|
||||
|
||||
return this;
|
||||
}
|
||||
@ -1150,6 +1153,9 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
break;
|
||||
case HuamiDeviceEvent.ALARM_TOGGLED:
|
||||
LOG.info("An alarm was toggled");
|
||||
TransactionBuilder builder = new TransactionBuilder("requestAlarms");
|
||||
requestAlarms(builder);
|
||||
builder.queue(getQueue());
|
||||
break;
|
||||
case HuamiDeviceEvent.FELL_ASLEEP:
|
||||
LOG.info("Fell asleep");
|
||||
@ -1212,11 +1218,34 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
evaluateGBDeviceEvent(deviceEventMusicControl);
|
||||
break;
|
||||
case HuamiDeviceEvent.MTU_REQUEST:
|
||||
int mtu = (value[2] & 0xff) << 8 | value[1] & 0xff;
|
||||
LOG.info("device announced MTU of " + mtu);
|
||||
mMTU = mtu;
|
||||
/*
|
||||
* not really sure if this would make sense, is this event already a proof of a successful MTU
|
||||
* negotiation initiated by the Huami device, and acknowledged by the phone? do we really have to
|
||||
* requestMTU() from our side after receiving this?
|
||||
* /
|
||||
if (mMTU != mtu) {
|
||||
requestMTU(mtu);
|
||||
}
|
||||
*/
|
||||
break;
|
||||
default:
|
||||
LOG.warn("unhandled event " + value[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestMTU(int mtu) {
|
||||
if (GBApplication.isRunningLollipopOrLater()) {
|
||||
new TransactionBuilder("requestMtu")
|
||||
.requestMtu(mtu)
|
||||
.queue(getQueue());
|
||||
mMTU = mtu;
|
||||
}
|
||||
}
|
||||
|
||||
private void acknowledgeFindPhone() {
|
||||
try {
|
||||
TransactionBuilder builder = performInitialized("acknowledge find phone");
|
||||
@ -1300,6 +1329,9 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_7_REALTIME_STEPS.equals(characteristicUUID)) {
|
||||
handleRealtimeSteps(characteristic.getValue());
|
||||
return true;
|
||||
} else if (HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION.equals(characteristicUUID)) {
|
||||
handleConfigurationInfo(characteristic.getValue());
|
||||
return true;
|
||||
} else {
|
||||
LOG.info("Unhandled characteristic changed: " + characteristicUUID);
|
||||
logMessageContent(characteristic.getValue());
|
||||
@ -1394,6 +1426,53 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
private void handleConfigurationInfo(byte[] value) {
|
||||
if (value == null || value.length < 4) {
|
||||
return;
|
||||
}
|
||||
if (value[0] == 0x10 && value[2] == 0x01) {
|
||||
if (value[1] == 0x0e) {
|
||||
String gpsVersion = new String(value, 3, value.length - 3);
|
||||
LOG.info("got gps version = " + gpsVersion);
|
||||
gbDevice.setFirmwareVersion2(gpsVersion);
|
||||
} else if (value[1] == 0x0d) {
|
||||
LOG.info("got alarms from watch");
|
||||
decodeAndUpdateAlarmStatus(value);
|
||||
} else {
|
||||
LOG.warn("got configuration info we do not handle yet " + GB.hexdump(value, 3, -1));
|
||||
}
|
||||
} else {
|
||||
LOG.warn("error received from configuration request " + GB.hexdump(value, 0, -1));
|
||||
}
|
||||
}
|
||||
|
||||
private void decodeAndUpdateAlarmStatus(byte[] response) {
|
||||
List<nodomain.freeyourgadget.gadgetbridge.entities.Alarm> alarms = DBHelper.getAlarms(gbDevice);
|
||||
boolean[] alarmsInUse = new boolean[10];
|
||||
boolean[] alarmsEnabled = new boolean[10];
|
||||
int nr_alarms = response[8];
|
||||
for (int i = 0; i < nr_alarms; i++) {
|
||||
byte alarm_data = response[9 + i];
|
||||
int index = alarm_data & 0xf;
|
||||
alarmsInUse[index] = true;
|
||||
boolean enabled = (alarm_data & 0x10) == 0x10;
|
||||
alarmsEnabled[index] = enabled;
|
||||
LOG.info("alarm " + index + " is enabled:" + enabled);
|
||||
}
|
||||
for (nodomain.freeyourgadget.gadgetbridge.entities.Alarm alarm : alarms) {
|
||||
boolean enabled = alarmsEnabled[alarm.getPosition()];
|
||||
boolean unused = !alarmsInUse[alarm.getPosition()];
|
||||
if (alarm.getEnabled() != enabled || alarm.getUnused() != unused) {
|
||||
LOG.info("updating alarm index " + alarm.getPosition() + " unused=" + unused + ", enabled=" + enabled);
|
||||
alarm.setEnabled(enabled);
|
||||
alarm.setUnused(unused);
|
||||
DBHelper.store(alarm);
|
||||
Intent intent = new Intent(DeviceService.ACTION_SAVE_ALARMS);
|
||||
LocalBroadcastManager.getInstance(getContext()).sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enableRealtimeSamplesTimer(boolean enable) {
|
||||
if (enable) {
|
||||
getRealtimeSamplesSupport().start();
|
||||
@ -1487,13 +1566,17 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
|
||||
int base = 0;
|
||||
if (alarm.getEnabled()) {
|
||||
int daysMask = 0;
|
||||
if (alarm.getEnabled() && !alarm.getUnused()) {
|
||||
base = 128;
|
||||
}
|
||||
int daysMask = alarm.getRepetition();
|
||||
if (!alarm.isRepetitive()) {
|
||||
daysMask = 128;
|
||||
if (!alarm.getUnused()) {
|
||||
daysMask = alarm.getRepetition();
|
||||
if (!alarm.isRepetitive()) {
|
||||
daysMask = 128;
|
||||
}
|
||||
}
|
||||
|
||||
byte[] alarmMessage = new byte[] {
|
||||
(byte) 0x2, // TODO what is this?
|
||||
(byte) (base + alarm.getPosition()), // 128 is the base, alarm slot is added
|
||||
@ -2170,8 +2253,8 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
return this;
|
||||
}
|
||||
|
||||
protected void writeToChunked(TransactionBuilder builder, int type, byte[] data) {
|
||||
final int MAX_CHUNKLENGTH = 17;
|
||||
private void writeToChunked(TransactionBuilder builder, int type, byte[] data) {
|
||||
final int MAX_CHUNKLENGTH = mMTU - 6;
|
||||
int remaining = data.length;
|
||||
byte count = 0;
|
||||
while (remaining > 0) {
|
||||
@ -2198,6 +2281,19 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected HuamiSupport requestGPSVersion(TransactionBuilder builder) {
|
||||
LOG.info("Requesting GPS version");
|
||||
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.COMMAND_REQUEST_GPS_VERSION);
|
||||
return this;
|
||||
}
|
||||
|
||||
private HuamiSupport requestAlarms(TransactionBuilder builder) {
|
||||
LOG.info("Requesting alarms");
|
||||
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), HuamiService.COMMAND_REQUEST_ALARMS);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String customStringFilter(String inputString) {
|
||||
if (HuamiCoordinator.getUseCustomFont(gbDevice.getAddress())) {
|
||||
@ -2258,6 +2354,7 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
setDisconnectNotification(builder);
|
||||
setExposeHRThridParty(builder);
|
||||
setHeartrateMeasurementInterval(builder, getHeartRateMeasurementInterval());
|
||||
requestAlarms(builder);
|
||||
}
|
||||
|
||||
private int getHeartRateMeasurementInterval() {
|
||||
@ -2271,4 +2368,8 @@ public class HuamiSupport extends AbstractBTLEDeviceSupport {
|
||||
public UpdateFirmwareOperation createUpdateFirmwareOperation(Uri uri) {
|
||||
return new UpdateFirmwareOperation(uri, this);
|
||||
}
|
||||
|
||||
public int getMTU() {
|
||||
return mMTU;
|
||||
}
|
||||
}
|
||||
|
@ -159,9 +159,11 @@ public class AmazfitBipFirmwareInfo extends HuamiFirmwareInfo {
|
||||
|
||||
// BipOS FW
|
||||
crcToVersion.put(28373, "1.1.2.05 (BipOS 0.5)");
|
||||
crcToVersion.put(62977, "1.1.2.05 (BipOS 0.5.1)");
|
||||
|
||||
// BipOS RES
|
||||
crcToVersion.put(16303, "1.1.2.05 (BipOS 0.5)");
|
||||
crcToVersion.put(61135, "1.1.2.05 (BipOS 0.5.1)");
|
||||
}
|
||||
|
||||
public AmazfitBipFirmwareInfo(byte[] bytes) {
|
||||
|
@ -17,11 +17,7 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.service.devices.huami.amazfitbip;
|
||||
|
||||
import android.bluetooth.BluetoothGatt;
|
||||
import android.bluetooth.BluetoothGattCharacteristic;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
@ -29,7 +25,6 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiFWHelper;
|
||||
@ -37,21 +32,14 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipFWHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.huami.amazfitbip.AmazfitBipService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertCategory;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.AlertNotificationProfile;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.btle.profiles.alertnotification.NewAlert;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiIcon;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.HuamiSupport;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchActivityOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.FetchSportsSummaryOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.huami.operations.HuamiFetchDebugLogsOperation;
|
||||
import nodomain.freeyourgadget.gadgetbridge.service.devices.miband.NotificationStrategy;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
|
||||
|
||||
public class AmazfitBipSupport extends HuamiSupport {
|
||||
|
||||
@ -162,39 +150,6 @@ public class AmazfitBipSupport extends HuamiSupport {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCharacteristicChanged(BluetoothGatt gatt,
|
||||
BluetoothGattCharacteristic characteristic) {
|
||||
boolean handled = super.onCharacteristicChanged(gatt, characteristic);
|
||||
if (!handled) {
|
||||
UUID characteristicUUID = characteristic.getUuid();
|
||||
if (HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION.equals(characteristicUUID)) {
|
||||
return handleConfigurationInfo(characteristic.getValue());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean handleConfigurationInfo(byte[] value) {
|
||||
if (value == null || value.length < 4) {
|
||||
return false;
|
||||
}
|
||||
if (value[0] == 0x10 && value[1] == 0x0e && value[2] == 0x01) {
|
||||
String gpsVersion = new String(value, 3, value.length - 3);
|
||||
LOG.info("got gps version = " + gpsVersion);
|
||||
gbDevice.setFirmwareVersion2(gpsVersion);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// this probably does more than only getting the GPS version...
|
||||
private AmazfitBipSupport requestGPSVersion(TransactionBuilder builder) {
|
||||
LOG.info("Requesting GPS version");
|
||||
builder.write(getCharacteristic(HuamiService.UUID_CHARACTERISTIC_3_CONFIGURATION), AmazfitBipService.COMMAND_REQUEST_GPS_VERSION);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void phase2Initialize(TransactionBuilder builder) {
|
||||
super.phase2Initialize(builder);
|
||||
|
@ -44,6 +44,7 @@ public class AmazfitCorFirmwareInfo extends HuamiFirmwareInfo {
|
||||
crcToVersion.put(51575, "1.0.7.88");
|
||||
crcToVersion.put(6346, "1.2.5.00");
|
||||
crcToVersion.put(24277, "1.2.7.20");
|
||||
crcToVersion.put(10078, "1.2.7.32");
|
||||
|
||||
// resources
|
||||
crcToVersion.put(46341, "RES 1.0.5.60");
|
||||
@ -53,6 +54,7 @@ public class AmazfitCorFirmwareInfo extends HuamiFirmwareInfo {
|
||||
crcToVersion.put(31263, "RES 1.0.7.77-91");
|
||||
crcToVersion.put(20920, "RES 1.2.5.00-69");
|
||||
crcToVersion.put(25397, "RES 1.2.7.20");
|
||||
crcToVersion.put(54167, "RES 1.2.7.32");
|
||||
|
||||
// font
|
||||
crcToVersion.put(61054, "8");
|
||||
|
@ -61,6 +61,7 @@ public class MiBand3FirmwareInfo extends HuamiFirmwareInfo {
|
||||
crcToVersion.put(40949, "2.3.0.28");
|
||||
crcToVersion.put(59213, "2.4.0.12");
|
||||
crcToVersion.put(10810, "2.4.0.20");
|
||||
crcToVersion.put(18271, "2.4.0.32");
|
||||
|
||||
// firmware (Mi Band 3 NFC)
|
||||
crcToVersion.put(46724, "1.7.0.4");
|
||||
@ -74,7 +75,7 @@ public class MiBand3FirmwareInfo extends HuamiFirmwareInfo {
|
||||
crcToVersion.put(1815, "2.0.0.4");
|
||||
crcToVersion.put(7225, "2.2.0.12-2.3.0.6");
|
||||
crcToVersion.put(52754, "2.3.0.28");
|
||||
crcToVersion.put(17930, "2.4.0.12-20");
|
||||
crcToVersion.put(17930, "2.4.0.12-32");
|
||||
|
||||
// font
|
||||
crcToVersion.put(19775, "1");
|
||||
|
@ -41,12 +41,14 @@ public class MiBand4FirmwareInfo extends HuamiFirmwareInfo {
|
||||
crcToVersion.put(43437, "1.0.5.66");
|
||||
crcToVersion.put(31632, "1.0.6.00");
|
||||
crcToVersion.put(6856, "1.0.7.14");
|
||||
crcToVersion.put(50145, "1.0.7.60");
|
||||
|
||||
// resources
|
||||
crcToVersion.put(27412, "1.0.5.22");
|
||||
crcToVersion.put(5466, "1.0.5.66");
|
||||
crcToVersion.put(20047, "1.0.6.00");
|
||||
crcToVersion.put(62914, "1.0.7.14");
|
||||
crcToVersion.put(17303, "1.0.7.60");
|
||||
|
||||
// font
|
||||
crcToVersion.put(31978, "1");
|
||||
|
@ -139,8 +139,8 @@ public class InitOperation extends AbstractBTLEOperation<HuamiSupport> {
|
||||
value[2] == HuamiService.AUTH_SUCCESS) {
|
||||
TransactionBuilder builder = createTransactionBuilder("Authenticated, now initialize phase 2");
|
||||
builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZING, getContext()));
|
||||
huamiSupport.requestDeviceInfo(builder);
|
||||
huamiSupport.enableFurtherNotifications(builder, true);
|
||||
huamiSupport.requestDeviceInfo(builder);
|
||||
huamiSupport.phase2Initialize(builder);
|
||||
huamiSupport.phase3Initialize(builder);
|
||||
huamiSupport.setInitialized(builder);
|
||||
|
@ -232,7 +232,7 @@ public class UpdateFirmwareOperation extends AbstractHuamiOperation {
|
||||
private boolean sendFirmwareData(HuamiFirmwareInfo info) {
|
||||
byte[] fwbytes = info.getBytes();
|
||||
int len = fwbytes.length;
|
||||
final int packetLength = 20;
|
||||
final int packetLength = getSupport().getMTU() - 3;
|
||||
int packets = len / packetLength;
|
||||
|
||||
try {
|
||||
|
@ -103,4 +103,8 @@ public class AutoConnectIntervalReceiver extends BroadcastReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
LocalBroadcastManager.getInstance(service).unregisterReceiver(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ public class AlarmUtils {
|
||||
* @return
|
||||
*/
|
||||
public static nodomain.freeyourgadget.gadgetbridge.model.Alarm createSingleShot(int index, boolean smartWakeup, Calendar calendar) {
|
||||
return new Alarm(-1, -1, index, true, smartWakeup, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE));
|
||||
return new Alarm(-1, -1, index, true, smartWakeup, Alarm.ALARM_ONCE, calendar.get(Calendar.HOUR_OF_DAY), calendar.get(Calendar.MINUTE), false);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -127,7 +127,7 @@ public class AlarmUtils {
|
||||
int hour = Integer.parseInt(tokens[4]);
|
||||
int minute = Integer.parseInt(tokens[5]);
|
||||
|
||||
return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, repetition, hour, minute);
|
||||
return new Alarm(device.getId(), user.getId(), index, enabled, smartWakeup, repetition, hour, minute, false);
|
||||
}
|
||||
|
||||
private static Comparator<Alarm> createComparator() {
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* Copyright (C) 2015-2019 0nse, Andreas Böhler, Andreas Shimokawa, Carsten
|
||||
Pfeiffer, Cre3per, Daniel Dakhno, Daniele Gobbetti, Jean-François Greffier,
|
||||
João Paulo Barraca, José Rebelo, Kranz, ladbsoft, Manuel Ruß, maxirnilian,
|
||||
protomors, Quallenauge, Sami Alaoui, Sophanimus, tiparega, Vadim Kaushan
|
||||
/* Copyright (C) 2015-2019 0nse, Andreas Böhler, Andreas Shimokawa,
|
||||
Carsten Pfeiffer, Cre3per, Daniel Dakhno, Daniele Gobbetti, Gordon Williams,
|
||||
Jean-François Greffier, João Paulo Barraca, José Rebelo, Kranz, ladbsoft,
|
||||
Manuel Ruß, maxirnilian, protomors, Quallenauge, Sami Alaoui, Sophanimus,
|
||||
tiparega, Vadim Kaushan
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
|
@ -307,7 +307,7 @@
|
||||
<string name="activity_prefs_weight_kg">Váha v kg</string>
|
||||
<string name="authenticating">Ověřování</string>
|
||||
<string name="authentication_required">Ověřování vyžadováno</string>
|
||||
<string name="appwidget_text">Spí…</string>
|
||||
<string name="appwidget_text">Spí</string>
|
||||
<string name="add_widget">Přidat widget</string>
|
||||
<string name="activity_prefs_sleep_duration">Preferovaná doba spánku v hodinách</string>
|
||||
<string name="appwidget_setting_alarm">Budík nastaven na %1$02d:%2$02d</string>
|
||||
@ -356,7 +356,7 @@
|
||||
<string name="unit_metric">Metrické</string>
|
||||
<string name="unit_imperial">Imperiální</string>
|
||||
<string name="timeformat_24h">24h</string>
|
||||
<string name="timeformat_am_pm">dop./odp.</string>
|
||||
<string name="timeformat_am_pm">Dop./Odp.</string>
|
||||
<string name="pref_screen_notification_profile_alarm_clock">Budík</string>
|
||||
<string name="StringUtils_sender">(%1$s)</string>
|
||||
<string name="find_device_you_found_it">Nalezeno!</string>
|
||||
@ -576,7 +576,7 @@
|
||||
<string name="ok">Ok</string>
|
||||
<string name="mi3_night_mode_sunset">Při západu slunce</string>
|
||||
<string name="controlcenter_start_activity_tracks">Záznamy aktivit</string>
|
||||
<string name="activity_type_treadmill">Běh na pásu</string>
|
||||
<string name="activity_type_treadmill">Běžecký pás</string>
|
||||
<string name="devicetype_miband3">Mi Band 3</string>
|
||||
<string name="devicetype_q8">Q8</string>
|
||||
<string name="devicetype_mykronoz_zetime">MyKronoz ZeTime</string>
|
||||
@ -725,7 +725,7 @@
|
||||
<string name="pref_title_use_custom_font">Využít vlastní font</string>
|
||||
<string name="pref_summary_use_custom_font">Vaše zařízení má vlastní font s podporou emoji</string>
|
||||
<string name="activity_db_management_autoexport_explanation">Cesta autoexportu databáze je nastaveno na:</string>
|
||||
<string name="activity_db_management_autoexport_label">AutoExport</string>
|
||||
<string name="activity_db_management_autoexport_label">Automatický export</string>
|
||||
<string name="activity_DB_ExportButton">Exportovat Databázi</string>
|
||||
<string name="activity_DB_import_button">Importovat Databázi</string>
|
||||
<string name="activity_DB_test_export_button">Spustit AutoExport Teď</string>
|
||||
@ -792,4 +792,22 @@
|
||||
\n
|
||||
\nPOKRAČUJTE NA VLASTNÍ NEBEZPEČÍ!</string>
|
||||
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
|
||||
<string name="devicetype_qhybrid">Fossil Q Hybrid</string>
|
||||
<string name="preferences_qhybrid_settings">Q hybrid nastavení</string>
|
||||
<string name="watch_not_connected">Hodinky nejsou připojeny</string>
|
||||
<string name="qhybrid_vibration_strength">síla vibrace:</string>
|
||||
<string name="qhybrid_goal_in_steps">Cíl v krocích</string>
|
||||
<string name="qhybrid_time_shift">časový posun</string>
|
||||
<string name="qhybrid_second_timezone_offset_relative_to_utc">posun dalšího časového pásma vzhledem k UTC</string>
|
||||
<string name="qhybrid_overwrite_buttons">přepsat tlačítka</string>
|
||||
<string name="qhybrid_use_activity_hand_as_notification_counter">použít čítač aktivity jako čítač oznámení</string>
|
||||
<string name="qhybrid_prompt_million_steps">Chcete-li aktivovat počítadlo, nastavte počet kroků na milion.</string>
|
||||
<string name="qhybrid_buttons_overwrite_success">Tlačítka přepsána</string>
|
||||
<string name="qhybrid_buttons_overwrite_error">Chyba při přepisování tlačítek</string>
|
||||
<string name="qhybrid_offset_timezone">posun časového pásma podle</string>
|
||||
<string name="qhybrid_changes_delay_prompt">změna může trvat několik sekund…</string>
|
||||
<string name="qhybrid_offset_time_by">posun času o</string>
|
||||
<string name="pref_disable_new_ble_scanning">Zakázat nové BLE skenování</string>
|
||||
<string name="pref_summary_disable_new_ble_scanning">Tuto možnost zaškrtněte pokud Vaše zařízení nelze najít během vyhledávání</string>
|
||||
<string name="devicetype_banglejs">Bangle.js</string>
|
||||
</resources>
|
@ -44,7 +44,7 @@
|
||||
<string name="title_activity_calblacklist">Kalender auf Blacklist</string>
|
||||
<!--Strings related to FwAppInstaller-->
|
||||
<string name="title_activity_fw_app_insaller">FW/App-Installer</string>
|
||||
<string name="fw_upgrade_notice">Du installierst jetzt %s.</string>
|
||||
<string name="fw_upgrade_notice">Du bist dabei, die %s zu installieren.</string>
|
||||
<string name="fw_multi_upgrade_notice">Du bist dabei, die %1$s und %2$s Firmware zu installieren, anstatt die, die sich derzeit auf deinem Mi Band befinden.</string>
|
||||
<string name="miband_firmware_known">Diese Firmware wurde getestet und ist bekanntlich mit Gadgetbridge kompatibel.</string>
|
||||
<string name="miband_firmware_unknown_warning">Diese Firmware ist nicht getestet und ist möglicherweise nicht mit Gadgetbridge kompatibel.
|
||||
|
@ -795,4 +795,9 @@
|
||||
<string name="watch_not_connected">Klokke ikke tilkoblet</string>
|
||||
<string name="qhybrid_vibration_strength">vibrasjonsstyrke:</string>
|
||||
<string name="devicetype_banglejs">Bangle.js</string>
|
||||
<string name="devicetype_qhybrid">Fossil Q Hybrid</string>
|
||||
<string name="preferences_qhybrid_settings">Q Hybrid-innstillinger</string>
|
||||
<string name="qhybrid_overwrite_buttons">overskriv taster</string>
|
||||
<string name="qhybrid_buttons_overwrite_success">Knapper overskrevet</string>
|
||||
<string name="qhybrid_buttons_overwrite_error">Kunne ikke overskrive knapper</string>
|
||||
</resources>
|
@ -346,7 +346,7 @@
|
||||
<string name="activity_type_running">Bieganie</string>
|
||||
<string name="activity_type_swimming">Pływanie</string>
|
||||
<string name="activity_type_treadmill">Bieżnia</string>
|
||||
<string name="controlcenter_connect">Połącz</string>
|
||||
<string name="controlcenter_connect">Połącz…</string>
|
||||
<string name="controlcenter_navigation_drawer_open">Otwórz okno nawigacji</string>
|
||||
<string name="controlcenter_navigation_drawer_close">Zamknij okno nawigacji</string>
|
||||
<string name="controlcenter_calibrate_device">Kalibracja urządzenia</string>
|
||||
|
@ -26,4 +26,19 @@
|
||||
<string name="appmananger_app_delete_cache">刪除並清除緩存</string>
|
||||
<string name="appmananger_app_reinstall">重新安裝</string>
|
||||
<string name="mi2_prefs_button_press_broadcast_default_value" translatable="false">nodomain.freeyourgadget.gadgetbridge.ButtonPressed</string>
|
||||
<string name="app_name">Gadgetbridge</string>
|
||||
<string name="title_activity_controlcenter">Gadgetbridge</string>
|
||||
<string name="controlcenter_snackbar_connecting">連接中…</string>
|
||||
<string name="controlcenter_snackbar_requested_screenshot">截取設備的屏幕截圖</string>
|
||||
<string name="controlcenter_calibrate_device">校正設備</string>
|
||||
<string name="title_activity_appmanager">應用管理器</string>
|
||||
<string name="appmanager_cached_watchapps_watchfaces">緩存的應用程式</string>
|
||||
<string name="appmanager_installed_watchfaces">已安裝的錶盤</string>
|
||||
<string name="appmanager_app_openinstore">在Pebble應用商店中搜索</string>
|
||||
<string name="appmanager_health_activate">啟動</string>
|
||||
<string name="appmanager_health_deactivate">停用</string>
|
||||
<string name="appmanager_hrm_activate">激活HRM</string>
|
||||
<string name="appmanager_hrm_deactivate">停用HRM</string>
|
||||
<string name="appmanager_weather_activate">啟動系統天氣應用</string>
|
||||
<string name="appmanager_weather_deactivate">停用系统天气应用</string>
|
||||
</resources>
|
@ -390,7 +390,7 @@
|
||||
|
||||
<string-array name="pref_amazfitbip_language">
|
||||
<item name="auto">@string/automatic</item>
|
||||
<item name="zh_CH">@string/simplified_chinese</item>
|
||||
<item name="zh_CN">@string/simplified_chinese</item>
|
||||
<item name="zh_TW">@string/traditional_chinese</item>
|
||||
<item name="en_US">@string/english</item>
|
||||
<item name="es_ES">@string/spanish</item>
|
||||
@ -404,7 +404,7 @@
|
||||
|
||||
<string-array name="pref_amazfitbip_language_values">
|
||||
<item>auto</item>
|
||||
<item>zh_CH</item>
|
||||
<item>zh_CN</item>
|
||||
<item>zh_TW</item>
|
||||
<item>en_US</item>
|
||||
<item>es_ES</item>
|
||||
@ -418,7 +418,7 @@
|
||||
|
||||
<string-array name="pref_amazfitcor_language">
|
||||
<item name="auto">@string/automatic</item>
|
||||
<item name="zh_CH">@string/simplified_chinese</item>
|
||||
<item name="zh_CN">@string/simplified_chinese</item>
|
||||
<item name="zh_TW">@string/traditional_chinese</item>
|
||||
<item name="en_US">@string/english</item>
|
||||
<item name="es_ES">@string/spanish</item>
|
||||
@ -427,7 +427,7 @@
|
||||
|
||||
<string-array name="pref_amazfitcor_language_values">
|
||||
<item>auto</item>
|
||||
<item>zh_CH</item>
|
||||
<item>zh_CN</item>
|
||||
<item>zh_TW</item>
|
||||
<item>en_US</item>
|
||||
<item>es_ES</item>
|
||||
@ -436,7 +436,7 @@
|
||||
|
||||
<string-array name="pref_miband3_language">
|
||||
<item name="auto">@string/automatic</item>
|
||||
<item name="zh_CH">@string/simplified_chinese</item>
|
||||
<item name="zh_CN">@string/simplified_chinese</item>
|
||||
<item name="zh_TW">@string/traditional_chinese</item>
|
||||
<item name="en_US">@string/english</item>
|
||||
<item name="es_ES">@string/spanish</item>
|
||||
@ -459,7 +459,7 @@
|
||||
|
||||
<string-array name="pref_miband3_language_values">
|
||||
<item>auto</item>
|
||||
<item>zh_CH</item>
|
||||
<item>zh_CN</item>
|
||||
<item>zh_TW</item>
|
||||
<item>en_US</item>
|
||||
<item>es_ES</item>
|
||||
|
@ -1,5 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<changelog>
|
||||
<release version="0.40.1" versioncode="164">
|
||||
<change>Mi Band/Amazfit: Recogize changes when toggling alarm on device (immediately when connected, else when connecting)</change>
|
||||
<change>Mi Band/Amazfit: Fix some bugs with stuck connection when re-connecting</change>
|
||||
<change>Mi Band 4: Support higher MTU for multiple times faster firmware transfer (probably also Amazfit GTR/GTS)</change>
|
||||
<change>Amazfit Cor: Fix setting language to Chinese manually</change>
|
||||
</release>
|
||||
<release version="0.40.0" versioncode="163">
|
||||
<change>Fossil Q Hybrid: Initial support</change>
|
||||
<change>Bangle.js: Initial support</change>
|
||||
<change>Reserve Alarm for Calendar feature restricted to Mi Band 1/2 and moved to per-device settings</change>
|
||||
<change>New icon for App Manager</change>
|
||||
</release>
|
||||
<release version="0.39.1" versioncode="162">
|
||||
<change>Try to actively re-connect when a connection gets interrupted (interval grows up to 64 seconds)</change>
|
||||
<change>Mi Band2/Amazfip Bip: Make button action settings per-device and enable for Amazfit Bip</change>
|
||||
|
4
fastlane/metadata/android/en-US/changelogs/163.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/163.txt
Normal file
@ -0,0 +1,4 @@
|
||||
* Fossil Q Hybrid: Initial support
|
||||
* Bangle.js: Initial support
|
||||
* Reserve Alarm for Calendar feature restricted to Mi Band 1/2 and moved to per-device settings
|
||||
* New icon for App Manager
|
4
fastlane/metadata/android/en-US/changelogs/164.txt
Normal file
4
fastlane/metadata/android/en-US/changelogs/164.txt
Normal file
@ -0,0 +1,4 @@
|
||||
* Mi Band/Amazfit: Recogize changes when toggling alarm on device (immediately when connected, else when connecting)
|
||||
* Mi Band/Amazfit: Fix some bugs with stuck connection when re-connecting
|
||||
* Mi Band 4: Support higher MTU for multiple times faster firmware transfer (probably also Amazfit GTR/GTS)
|
||||
* Amazfit Cor: Fix setting language to Chinese manually
|
Loading…
Reference in New Issue
Block a user