mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-03 17:02:13 +01:00
WIP: Work towards SMS replies / canned replies
- Implement the PebbleProtocol side (2.x and 3.x) - Add Preferences for canned replies This can be tested by enabling untested features in Pebble Settings It lets you see and select the replies set up in "Canned Repies" on the Pebble You will get a "NOT IMPLENTED" message on your Pebble. THIS DOES NOT ACTUALLY DO ANYTHING USEFUL YET.
This commit is contained in:
parent
f258e62633
commit
53fb63781e
@ -76,7 +76,7 @@ public class DebugActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
NotificationSpec notificationSpec = new NotificationSpec();
|
NotificationSpec notificationSpec = new NotificationSpec();
|
||||||
notificationSpec.sender = getResources().getText(R.string.app_name).toString();
|
notificationSpec.phoneNumber = getResources().getText(R.string.app_name).toString();
|
||||||
notificationSpec.body = editContent.getText().toString();
|
notificationSpec.body = editContent.getText().toString();
|
||||||
notificationSpec.type = NotificationType.SMS;
|
notificationSpec.type = NotificationType.SMS;
|
||||||
notificationSpec.id = -1;
|
notificationSpec.id = -1;
|
||||||
|
@ -50,8 +50,8 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
final Preference pebbleEmuAddr = findPreference("pebble_emu_addr");
|
pref = findPreference("pebble_emu_addr");
|
||||||
pebbleEmuAddr.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newVal) {
|
public boolean onPreferenceChange(Preference preference, Object newVal) {
|
||||||
Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
|
Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
|
||||||
@ -62,8 +62,8 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final Preference pebbleEmuPort = findPreference("pebble_emu_port");
|
pref = findPreference("pebble_emu_port");
|
||||||
pebbleEmuPort.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
pref.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceChange(Preference preference, Object newVal) {
|
public boolean onPreferenceChange(Preference preference, Object newVal) {
|
||||||
Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
|
Intent refreshIntent = new Intent(ControlCenter.ACTION_REFRESH_DEVICELIST);
|
||||||
@ -110,6 +110,14 @@ public class SettingsActivity extends AbstractSettingsActivity {
|
|||||||
"pebble_emu_addr",
|
"pebble_emu_addr",
|
||||||
"pebble_emu_port",
|
"pebble_emu_port",
|
||||||
"pebble_reconnect_attempts",
|
"pebble_reconnect_attempts",
|
||||||
|
"canned_reply_1",
|
||||||
|
"canned_reply_2",
|
||||||
|
"canned_reply_3",
|
||||||
|
"canned_reply_4",
|
||||||
|
"canned_reply_5",
|
||||||
|
"canned_reply_6",
|
||||||
|
"canned_reply_7",
|
||||||
|
"canned_reply_8",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,6 +9,8 @@ import android.os.PowerManager;
|
|||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.telephony.SmsMessage;
|
import android.telephony.SmsMessage;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationSpec;
|
||||||
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
import nodomain.freeyourgadget.gadgetbridge.model.NotificationType;
|
||||||
|
@ -9,4 +9,5 @@ public class NotificationSpec {
|
|||||||
public String body;
|
public String body;
|
||||||
public NotificationType type;
|
public NotificationType type;
|
||||||
public String sourceName;
|
public String sourceName;
|
||||||
|
public String[] cannedReplies;
|
||||||
}
|
}
|
||||||
|
@ -217,6 +217,21 @@ public class DeviceCommunicationService extends Service {
|
|||||||
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
|
notificationSpec.sourceName = intent.getStringExtra(EXTRA_NOTIFICATION_SOURCENAME);
|
||||||
if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
|
if (notificationSpec.type == NotificationType.SMS && notificationSpec.phoneNumber != null) {
|
||||||
notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
|
notificationSpec.sender = getContactDisplayNameByNumber(notificationSpec.phoneNumber);
|
||||||
|
|
||||||
|
// NOTE: maybe not where it belongs
|
||||||
|
SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
if (sharedPrefs.getBoolean("pebble_force_untested", false)) {
|
||||||
|
// I would rather like to save that as an array in ShadredPreferences
|
||||||
|
// this would work but I dont know how to do the same in the Settings Activity's xml
|
||||||
|
ArrayList<String> replies = new ArrayList<>();
|
||||||
|
for (int i = 1; i <= 8; i++) {
|
||||||
|
String reply = sharedPrefs.getString("canned_reply_" + i, null);
|
||||||
|
if (reply != null && !reply.equals("")) {
|
||||||
|
replies.add(reply);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notificationSpec.cannedReplies = replies.toArray(new String[replies.size()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mDeviceSupport.onNotification(notificationSpec);
|
mDeviceSupport.onNotification(notificationSpec);
|
||||||
break;
|
break;
|
||||||
|
@ -421,10 +421,10 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
if (isFw3x) {
|
if (isFw3x) {
|
||||||
// 3.x notification
|
// 3.x notification
|
||||||
//return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing
|
//return encodeTimelinePin(id, (int) ((ts + 600) & 0xffffffffL), (short) 90, PebbleIconID.TIMELINE_CALENDAR, title); // really, this is just for testing
|
||||||
return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle, notificationSpec.type);
|
return encodeBlobdbNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle, notificationSpec.type, notificationSpec.cannedReplies);
|
||||||
} else if (mForceProtocol || notificationSpec.type != NotificationType.EMAIL) {
|
} else if (mForceProtocol || notificationSpec.type != NotificationType.EMAIL) {
|
||||||
// 2.x notification
|
// 2.x notification
|
||||||
return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle);
|
return encodeExtensibleNotification(id, (int) (ts & 0xffffffffL), title, subtitle, notificationSpec.body, notificationSpec.sourceName, hasHandle, notificationSpec.cannedReplies);
|
||||||
} else {
|
} else {
|
||||||
// 1.x notification on FW 2.X
|
// 1.x notification on FW 2.X
|
||||||
String[] parts = {title, notificationSpec.body, ts.toString(), subtitle};
|
String[] parts = {title, notificationSpec.body, ts.toString(), subtitle};
|
||||||
@ -467,7 +467,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
return encodeSetCallState("Where are you?", "Gadgetbridge", start ? ServiceCommand.CALL_INCOMING : ServiceCommand.CALL_END);
|
return encodeSetCallState("Where are you?", "Gadgetbridge", start ? ServiceCommand.CALL_INCOMING : ServiceCommand.CALL_END);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle) {
|
private static byte[] encodeExtensibleNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, String[] cannedReplies) {
|
||||||
final short ACTION_LENGTH_MIN = 10;
|
final short ACTION_LENGTH_MIN = 10;
|
||||||
|
|
||||||
String[] parts = {title, subtitle, body};
|
String[] parts = {title, subtitle, body};
|
||||||
@ -478,6 +478,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
String dismiss_string;
|
String dismiss_string;
|
||||||
String open_string = "Open on phone";
|
String open_string = "Open on phone";
|
||||||
String mute_string = "Mute";
|
String mute_string = "Mute";
|
||||||
|
String reply_string = "Reply";
|
||||||
if (sourceName != null) {
|
if (sourceName != null) {
|
||||||
mute_string += " " + sourceName;
|
mute_string += " " + sourceName;
|
||||||
}
|
}
|
||||||
@ -496,6 +497,15 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
|
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int replies_length = -1;
|
||||||
|
if (cannedReplies != null) {
|
||||||
|
actions_count++;
|
||||||
|
for (String reply : cannedReplies) {
|
||||||
|
replies_length += reply.getBytes().length + 1;
|
||||||
|
}
|
||||||
|
actions_length += ACTION_LENGTH_MIN + reply_string.getBytes().length + replies_length + 3; // 3 = attribute id (byte) + length(short)
|
||||||
|
}
|
||||||
|
|
||||||
byte attributes_count = 0;
|
byte attributes_count = 0;
|
||||||
|
|
||||||
int length = 21 + 10 + actions_length;
|
int length = 21 + 10 + actions_length;
|
||||||
@ -554,7 +564,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
buf.putShort((short) dismiss_string.getBytes().length);
|
buf.putShort((short) dismiss_string.getBytes().length);
|
||||||
buf.put(dismiss_string.getBytes());
|
buf.put(dismiss_string.getBytes());
|
||||||
|
|
||||||
// open action
|
// open and mute actions
|
||||||
if (hasHandle) {
|
if (hasHandle) {
|
||||||
buf.put((byte) 0x01);
|
buf.put((byte) 0x01);
|
||||||
buf.put((byte) 0x02); // generic
|
buf.put((byte) 0x02); // generic
|
||||||
@ -572,6 +582,23 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cannedReplies != null) {
|
||||||
|
buf.put((byte) 0x05);
|
||||||
|
buf.put((byte) 0x03); // reply action
|
||||||
|
buf.put((byte) 0x02); // number attributes
|
||||||
|
buf.put((byte) 0x01); // title
|
||||||
|
buf.putShort((short) reply_string.getBytes().length);
|
||||||
|
buf.put(reply_string.getBytes());
|
||||||
|
buf.put((byte) 0x08); // canned replies
|
||||||
|
buf.putShort((short) replies_length);
|
||||||
|
for (int i = 0; i < cannedReplies.length - 1; i++) {
|
||||||
|
buf.put(cannedReplies[i].getBytes());
|
||||||
|
buf.put((byte) 0x00);
|
||||||
|
}
|
||||||
|
// last one must not be zero terminated, else we get an additional emply reply
|
||||||
|
buf.put(cannedReplies[cannedReplies.length - 1].getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
return buf.array();
|
return buf.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -645,7 +672,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
return encodeBlobdb(uuid, BLOBDB_INSERT, BLOBDB_PIN, buf.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, NotificationType notificationType) {
|
private byte[] encodeBlobdbNotification(int id, int timestamp, String title, String subtitle, String body, String sourceName, boolean hasHandle, NotificationType notificationType, String[] cannedReplies) {
|
||||||
final short NOTIFICATION_PIN_LENGTH = 46;
|
final short NOTIFICATION_PIN_LENGTH = 46;
|
||||||
final short ACTION_LENGTH_MIN = 10;
|
final short ACTION_LENGTH_MIN = 10;
|
||||||
|
|
||||||
@ -697,6 +724,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
String dismiss_string;
|
String dismiss_string;
|
||||||
String open_string = "Open on phone";
|
String open_string = "Open on phone";
|
||||||
String mute_string = "Mute";
|
String mute_string = "Mute";
|
||||||
|
String reply_string = "Reply";
|
||||||
if (sourceName != null) {
|
if (sourceName != null) {
|
||||||
mute_string += " " + sourceName;
|
mute_string += " " + sourceName;
|
||||||
}
|
}
|
||||||
@ -714,6 +742,15 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
|
actions_length = (short) (ACTION_LENGTH_MIN * actions_count + dismiss_string.getBytes().length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int replies_length = -1;
|
||||||
|
if (cannedReplies != null) {
|
||||||
|
actions_count++;
|
||||||
|
for (String reply : cannedReplies) {
|
||||||
|
replies_length += reply.getBytes().length + 1;
|
||||||
|
}
|
||||||
|
actions_length += ACTION_LENGTH_MIN + reply_string.getBytes().length + replies_length + 3; // 3 = attribute id (byte) + length(short)
|
||||||
|
}
|
||||||
|
|
||||||
byte attributes_count = 2; // icon
|
byte attributes_count = 2; // icon
|
||||||
short attributes_length = (short) (11 + actions_length);
|
short attributes_length = (short) (11 + actions_length);
|
||||||
if (parts != null) {
|
if (parts != null) {
|
||||||
@ -798,6 +835,24 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
buf.putShort((short) mute_string.getBytes().length);
|
buf.putShort((short) mute_string.getBytes().length);
|
||||||
buf.put(mute_string.getBytes());
|
buf.put(mute_string.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (cannedReplies != null) {
|
||||||
|
buf.put((byte) 0x05);
|
||||||
|
buf.put((byte) 0x03); // reply action
|
||||||
|
buf.put((byte) 0x02); // number attributes
|
||||||
|
buf.put((byte) 0x01); // title
|
||||||
|
buf.putShort((short) reply_string.getBytes().length);
|
||||||
|
buf.put(reply_string.getBytes());
|
||||||
|
buf.put((byte) 0x08); // canned replies
|
||||||
|
buf.putShort((short) replies_length);
|
||||||
|
for (int i = 0; i < cannedReplies.length - 1; i++) {
|
||||||
|
buf.put(cannedReplies[i].getBytes());
|
||||||
|
buf.put((byte) 0x00);
|
||||||
|
}
|
||||||
|
// last one must not be zero terminated, else we get an additional emply reply
|
||||||
|
buf.put(cannedReplies[cannedReplies.length - 1].getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array());
|
return encodeBlobdb(UUID.randomUUID(), BLOBDB_INSERT, BLOBDB_NOTIFICATION, buf.array());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1436,7 +1491,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
if (command == 0x02) {
|
if (command == 0x02) {
|
||||||
int id = buf.getInt();
|
int id = buf.getInt();
|
||||||
byte action = buf.get();
|
byte action = buf.get();
|
||||||
if (action >= 0x01 && action <= 0x04) {
|
if (action >= 0x01 && action <= 0x05) {
|
||||||
GBDeviceEventNotificationControl devEvtNotificationControl = new GBDeviceEventNotificationControl();
|
GBDeviceEventNotificationControl devEvtNotificationControl = new GBDeviceEventNotificationControl();
|
||||||
devEvtNotificationControl.handle = id;
|
devEvtNotificationControl.handle = id;
|
||||||
GBDeviceEventSendBytes sendBytesAck = null;
|
GBDeviceEventSendBytes sendBytesAck = null;
|
||||||
@ -1458,6 +1513,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
sendBytesAck = new GBDeviceEventSendBytes();
|
sendBytesAck = new GBDeviceEventSendBytes();
|
||||||
sendBytesAck.encodedBytes = encodeActionResponse2x(id, action, 6, "Muted");
|
sendBytesAck.encodedBytes = encodeActionResponse2x(id, action, 6, "Muted");
|
||||||
break;
|
break;
|
||||||
|
case 0x05:
|
||||||
|
devEvtNotificationControl = null; // not implemented
|
||||||
|
sendBytesAck = new GBDeviceEventSendBytes();
|
||||||
|
sendBytesAck.encodedBytes = encodeActionResponse2x(id, action, 6, "NOT IMPLEMENTED");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -1479,7 +1539,7 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
long uuid_low = buf.getLong();
|
long uuid_low = buf.getLong();
|
||||||
int id = (int) (uuid_low & 0xffffffffL);
|
int id = (int) (uuid_low & 0xffffffffL);
|
||||||
byte action = buf.get();
|
byte action = buf.get();
|
||||||
if (action >= 0x01 && action <= 0x04) {
|
if (action >= 0x01 && action <= 0x05) {
|
||||||
GBDeviceEventNotificationControl dismissNotification = new GBDeviceEventNotificationControl();
|
GBDeviceEventNotificationControl dismissNotification = new GBDeviceEventNotificationControl();
|
||||||
dismissNotification.handle = id;
|
dismissNotification.handle = id;
|
||||||
String caption = "undefined";
|
String caption = "undefined";
|
||||||
@ -1505,6 +1565,11 @@ public class PebbleProtocol extends GBDeviceProtocol {
|
|||||||
caption = "Muted";
|
caption = "Muted";
|
||||||
icon_id = PebbleIconID.RESULT_MUTE;
|
icon_id = PebbleIconID.RESULT_MUTE;
|
||||||
break;
|
break;
|
||||||
|
case 0x05:
|
||||||
|
dismissNotification = null; // not implemented
|
||||||
|
caption = "NOT IMPLEMENTED";
|
||||||
|
icon_id = PebbleIconID.GENERIC_WARNING;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes();
|
GBDeviceEventSendBytes sendBytesAck = new GBDeviceEventSendBytes();
|
||||||
sendBytesAck.encodedBytes = encodeActionResponse(new UUID(uuid_high, uuid_low), icon_id, caption);
|
sendBytesAck.encodedBytes = encodeActionResponse(new UUID(uuid_high, uuid_low), icon_id, caption);
|
||||||
|
@ -55,6 +55,8 @@
|
|||||||
|
|
||||||
<string name="pref_blacklist">Blacklist Apps</string>
|
<string name="pref_blacklist">Blacklist Apps</string>
|
||||||
|
|
||||||
|
<string name="pref_title_canned_replies">Canned Replies</string>
|
||||||
|
|
||||||
<string name="pref_header_development">Developer Options</string>
|
<string name="pref_header_development">Developer Options</string>
|
||||||
<string name="pref_title_development_miaddr">Mi Band address</string>
|
<string name="pref_title_development_miaddr">Mi Band address</string>
|
||||||
|
|
||||||
|
@ -65,6 +65,35 @@
|
|||||||
<Preference
|
<Preference
|
||||||
android:key="pref_key_blacklist"
|
android:key="pref_key_blacklist"
|
||||||
android:title="@string/pref_blacklist" />
|
android:title="@string/pref_blacklist" />
|
||||||
|
<PreferenceScreen
|
||||||
|
android:key="pref_key_canned_replies"
|
||||||
|
android:title="@string/pref_title_canned_replies"
|
||||||
|
android:dependency="pebble_force_untested" >
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_1"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_2"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_3"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_4"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_5"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_6"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_7"
|
||||||
|
android:maxLength="64" />
|
||||||
|
<EditTextPreference
|
||||||
|
android:key="canned_reply_8"
|
||||||
|
android:maxLength="64" />
|
||||||
|
</PreferenceScreen>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
Loading…
Reference in New Issue
Block a user