mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-06-02 11:26:09 +02:00
81aef0bf35
Introduce the concept of primary and secondary weathers: * Primary weather keeps the same behavior as previously across all weather providers, so it's non-breaking. This location is not necessarily the current location, just the primary weather location set by the user. * The GenericWeatherReceiver now has a new extra WeatherSecondaryJson, that receives a json list with secondary weather locations. It's guaranteed that the primary weather always exists, so the list of WeatherSpecs provided to devices is never empty. Update all support classes accordingly.
315 lines
10 KiB
Java
315 lines
10 KiB
Java
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, José Rebelo,
|
|
Julien Pivotto, Steffen Liebergeld
|
|
|
|
This file is part of Gadgetbridge.
|
|
|
|
Gadgetbridge is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as published
|
|
by the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Gadgetbridge is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
package nodomain.freeyourgadget.gadgetbridge.service.serial;
|
|
|
|
import android.location.Location;
|
|
|
|
import java.util.ArrayList;
|
|
import java.util.UUID;
|
|
|
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
|
|
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventSendBytes;
|
|
import nodomain.freeyourgadget.gadgetbridge.devices.EventHandler;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.Alarm;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.CalendarEventSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.CallSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.MusicStateSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.Reminder;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.WeatherSpec;
|
|
import nodomain.freeyourgadget.gadgetbridge.model.WorldClock;
|
|
import nodomain.freeyourgadget.gadgetbridge.service.AbstractDeviceSupport;
|
|
|
|
/**
|
|
* An abstract base class for devices speaking a serial protocol, like via
|
|
* an rfcomm bluetooth socket or a TCP socket.
|
|
* <p/>
|
|
* This class uses two helper classes to deal with that:
|
|
* - GBDeviceIoThread, which creates and maintains the actual socket connection and implements the transport layer
|
|
* - GBDeviceProtocol, which implements the encoding and decoding of messages, i.e. the actual device specific protocol
|
|
* <p/>
|
|
* Note that these two classes need to be implemented in a device specific way.
|
|
* <p/>
|
|
* This implementation implements all methods of {@link EventHandler}, calls the {@link GBDeviceProtocol device protocol}
|
|
* to create the device specific message for the respective events and sends them to the device via {@link #sendToDevice(byte[])}.
|
|
*/
|
|
public abstract class AbstractSerialDeviceSupport extends AbstractDeviceSupport {
|
|
private GBDeviceProtocol gbDeviceProtocol;
|
|
protected GBDeviceIoThread gbDeviceIOThread;
|
|
|
|
/**
|
|
* Factory method to create the device specific GBDeviceProtocol instance to be used.
|
|
*/
|
|
protected abstract GBDeviceProtocol createDeviceProtocol();
|
|
|
|
/**
|
|
* Factory method to create the device specific GBDeviceIoThread instance to be used.
|
|
*/
|
|
protected abstract GBDeviceIoThread createDeviceIOThread();
|
|
|
|
@Override
|
|
public void dispose() {
|
|
// currently only one thread allowed
|
|
if (gbDeviceIOThread != null) {
|
|
gbDeviceIOThread.quit();
|
|
gbDeviceIOThread.interrupt();
|
|
gbDeviceIOThread = null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lazily creates and returns the GBDeviceProtocol instance to be used.
|
|
*/
|
|
protected synchronized GBDeviceProtocol getDeviceProtocol() {
|
|
if (gbDeviceProtocol == null) {
|
|
gbDeviceProtocol = createDeviceProtocol();
|
|
}
|
|
return gbDeviceProtocol;
|
|
}
|
|
|
|
/**
|
|
* Lazily creates and returns the GBDeviceIoThread instance to be used.
|
|
*/
|
|
public synchronized GBDeviceIoThread getDeviceIOThread() {
|
|
if (gbDeviceIOThread == null) {
|
|
gbDeviceIOThread = createDeviceIOThread();
|
|
}
|
|
return gbDeviceIOThread;
|
|
}
|
|
|
|
/**
|
|
* Sends the given message to the device. This implementation delegates the
|
|
* writing to the {@link #getDeviceIOThread device io thread}
|
|
*
|
|
* @param bytes the message to send to the device
|
|
*/
|
|
private void sendToDevice(byte[] bytes) {
|
|
if (bytes != null && gbDeviceIOThread != null) {
|
|
gbDeviceIOThread.write(bytes);
|
|
}
|
|
}
|
|
|
|
private void handleGBDeviceEvent(GBDeviceEventSendBytes sendBytes) {
|
|
sendToDevice(sendBytes.encodedBytes);
|
|
}
|
|
|
|
@Override
|
|
public void evaluateGBDeviceEvent(GBDeviceEvent deviceEvent) {
|
|
if (deviceEvent instanceof GBDeviceEventSendBytes) {
|
|
handleGBDeviceEvent((GBDeviceEventSendBytes) deviceEvent);
|
|
return;
|
|
}
|
|
super.evaluateGBDeviceEvent(deviceEvent);
|
|
}
|
|
|
|
@Override
|
|
public void onNotification(NotificationSpec notificationSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeNotification(notificationSpec);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onDeleteNotification(int id) {
|
|
byte[] bytes = gbDeviceProtocol.encodeDeleteNotification(id);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetTime() {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetTime();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetCallState(CallSpec callSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetCallState(callSpec.number, callSpec.name, callSpec.command);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetCannedMessages(CannedMessagesSpec cannedMessagesSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetCannedMessages(cannedMessagesSpec);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetMusicState(MusicStateSpec stateSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetMusicState(stateSpec.state, stateSpec.position, stateSpec.playRate, stateSpec.shuffle, stateSpec.repeat);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetMusicInfo(MusicSpec musicSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetMusicInfo(musicSpec.artist, musicSpec.album, musicSpec.track, musicSpec.duration, musicSpec.trackCount, musicSpec.trackNr);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetPhoneVolume(final float volume) {
|
|
byte[] bytes = gbDeviceProtocol.encodeVolume(volume);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onAppInfoReq() {
|
|
byte[] bytes = gbDeviceProtocol.encodeAppInfoReq();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onAppStart(UUID uuid, boolean start) {
|
|
byte[] bytes = gbDeviceProtocol.encodeAppStart(uuid, start);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onAppDelete(UUID uuid) {
|
|
byte[] bytes = gbDeviceProtocol.encodeAppDelete(uuid);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onAppReorder(UUID[] uuids) {
|
|
byte[] bytes = gbDeviceProtocol.encodeAppReorder(uuids);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onFetchRecordedData(int dataTypes) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSynchronizeActivityData();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onReset(int flags) {
|
|
byte[] bytes = gbDeviceProtocol.encodeReset(flags);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onFindDevice(boolean start) {
|
|
byte[] bytes = gbDeviceProtocol.encodeFindDevice(start);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onFindPhone(boolean start) {
|
|
byte[] bytes = gbDeviceProtocol.encodeFindPhone(start);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onScreenshotReq() {
|
|
byte[] bytes = gbDeviceProtocol.encodeScreenshotReq();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onEnableRealtimeSteps(boolean enable) {
|
|
byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeSteps(enable);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onEnableHeartRateSleepSupport(boolean enable) {
|
|
byte[] bytes = gbDeviceProtocol.encodeEnableHeartRateSleepSupport(enable);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onEnableRealtimeHeartRateMeasurement(boolean enable) {
|
|
byte[] bytes = gbDeviceProtocol.encodeEnableRealtimeHeartRateMeasurement(enable);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onAddCalendarEvent(CalendarEventSpec calendarEventSpec) {
|
|
byte[] bytes = gbDeviceProtocol.encodeAddCalendarEvent(calendarEventSpec);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onDeleteCalendarEvent(byte type, long id) {
|
|
byte[] bytes = gbDeviceProtocol.encodeDeleteCalendarEvent(type, id);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSendConfiguration(String config) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSendConfiguration(config);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onTestNewFunction() {
|
|
byte[] bytes = gbDeviceProtocol.encodeTestNewFunction();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSendWeather(ArrayList<WeatherSpec> weatherSpecs) {
|
|
WeatherSpec weatherSpec = weatherSpecs.get(0);
|
|
byte[] bytes = gbDeviceProtocol.encodeSendWeather(weatherSpec);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetFmFrequency(float frequency) {
|
|
byte[] bytes = gbDeviceProtocol.encodeFmFrequency(frequency);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetLedColor(int color) {
|
|
byte[] bytes = gbDeviceProtocol.encodeLedColor(color);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onPowerOff() {
|
|
byte[] bytes = gbDeviceProtocol.encodePowerOff();
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetAlarms(ArrayList<? extends Alarm> alarms) {
|
|
byte[] bytes = gbDeviceProtocol.encodeSetAlarms(alarms);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetReminders(ArrayList<? extends Reminder> reminders) {
|
|
byte[] bytes = gbDeviceProtocol.encodeReminders(reminders);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetWorldClocks(ArrayList<? extends WorldClock> clocks) {
|
|
byte[] bytes = gbDeviceProtocol.encodeWorldClocks(clocks);
|
|
sendToDevice(bytes);
|
|
}
|
|
|
|
@Override
|
|
public void onSetGpsLocation(Location location) {
|
|
byte[] bytes = gbDeviceProtocol.encodeGpsLocation(location);
|
|
sendToDevice(bytes);
|
|
}
|
|
}
|