mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2025-02-20 06:16:49 +01:00
Implement music control (play, pause, next, previous). Try to make code a bit less Pebble centric.
This commit is contained in:
parent
20b3dffba6
commit
df8c290442
@ -72,6 +72,11 @@
|
|||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
<receiver android:name=".StopServiceReceiver" />
|
<receiver android:name=".StopServiceReceiver" />
|
||||||
|
<receiver android:name=".GBMusicControlReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="nodomain.freeyourgadget.gadgetbridge.musiccontrol" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".DebugActivity"
|
android:name=".DebugActivity"
|
||||||
|
@ -114,6 +114,23 @@ public class BluetoothCommunicationService extends Service {
|
|||||||
nm.notify(NOTIFICATION_ID, notification);
|
nm.notify(NOTIFICATION_ID, notification);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void evaluateGBCommandBundle(GBCommandBundle cmdBundle) {
|
||||||
|
switch (cmdBundle.commandClass) {
|
||||||
|
case MUSIC_CONTROL:
|
||||||
|
Log.i(TAG, "Got command for MUSIC_CONTROL");
|
||||||
|
Intent i = new Intent(GBMusicControlReceiver.ACTION_MUSICCONTROL);
|
||||||
|
i.putExtra("command", cmdBundle.command.ordinal());
|
||||||
|
sendBroadcast(i);
|
||||||
|
break;
|
||||||
|
case CALL_CONTROL:
|
||||||
|
Log.i(TAG, "Got command for CALL_CONTROL");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||||
|
|
||||||
@ -183,13 +200,13 @@ public class BluetoothCommunicationService extends Service {
|
|||||||
byte[] msg = PebbleProtocol.encodeEmail(sender, subject, body);
|
byte[] msg = PebbleProtocol.encodeEmail(sender, subject, body);
|
||||||
mBtSocketIoThread.write(msg);
|
mBtSocketIoThread.write(msg);
|
||||||
} else if (intent.getAction().equals(ACTION_CALLSTATE)) {
|
} else if (intent.getAction().equals(ACTION_CALLSTATE)) {
|
||||||
byte phoneState = intent.getByteExtra("call_state", (byte) 0);
|
GBCommand command = GBCommand.values()[intent.getIntExtra("call_command", 0)]; // UGLY
|
||||||
String phoneNumber = intent.getStringExtra("call_phonenumber");
|
String phoneNumber = intent.getStringExtra("call_phonenumber");
|
||||||
String callerName = null;
|
String callerName = null;
|
||||||
if (phoneNumber != null) {
|
if (phoneNumber != null) {
|
||||||
callerName = getContactDisplayNameByNumber(phoneNumber);
|
callerName = getContactDisplayNameByNumber(phoneNumber);
|
||||||
}
|
}
|
||||||
byte[] msg = PebbleProtocol.encodeSetPhoneState(phoneNumber, callerName, phoneState);
|
byte[] msg = PebbleProtocol.encodeSetCallState(phoneNumber, callerName, command);
|
||||||
mBtSocketIoThread.write(msg);
|
mBtSocketIoThread.write(msg);
|
||||||
} else if (intent.getAction().equals(ACTION_SETTIME)) {
|
} else if (intent.getAction().equals(ACTION_SETTIME)) {
|
||||||
byte[] msg = PebbleProtocol.encodeSetTime(-1);
|
byte[] msg = PebbleProtocol.encodeSetTime(-1);
|
||||||
@ -330,7 +347,12 @@ public class BluetoothCommunicationService extends Service {
|
|||||||
Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!");
|
Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!");
|
||||||
write(PebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID));
|
write(PebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID));
|
||||||
} else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) {
|
} else if (endpoint != PebbleProtocol.ENDPOINT_DATALOG) {
|
||||||
Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)");
|
GBCommandBundle cmdBundle = PebbleProtocol.decodeResponse(buffer);
|
||||||
|
if (cmdBundle == null) {
|
||||||
|
Log.i(TAG, "unhandled message to endpoint " + endpoint + " (" + bytes + " bytes)");
|
||||||
|
} else {
|
||||||
|
evaluateGBCommandBundle(cmdBundle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
|
@ -73,7 +73,7 @@ public class DebugActivity extends ActionBarActivity {
|
|||||||
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
||||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
||||||
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
|
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
|
||||||
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_INCOMINGCALL);
|
startIntent.putExtra("call_command", GBCommand.CALL_INCOMING.ordinal());
|
||||||
startService(startIntent);
|
startService(startIntent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -84,7 +84,7 @@ public class DebugActivity extends ActionBarActivity {
|
|||||||
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
||||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
||||||
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
|
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
|
||||||
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_OUTGOINGCALL);
|
startIntent.putExtra("call_command", GBCommand.CALL_OUTGOING.ordinal());
|
||||||
startService(startIntent);
|
startService(startIntent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -95,7 +95,7 @@ public class DebugActivity extends ActionBarActivity {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
||||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
||||||
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_START);
|
startIntent.putExtra("call_command", GBCommand.CALL_START.ordinal());
|
||||||
startService(startIntent);
|
startService(startIntent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -105,7 +105,7 @@ public class DebugActivity extends ActionBarActivity {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
|
||||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
||||||
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_END);
|
startIntent.putExtra("call_command", GBCommand.CALL_END.ordinal());
|
||||||
startService(startIntent);
|
startService(startIntent);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge;
|
||||||
|
|
||||||
|
public enum GBCommand {
|
||||||
|
|
||||||
|
UNDEFINEND,
|
||||||
|
|
||||||
|
CALL_ACCEPT,
|
||||||
|
CALL_END,
|
||||||
|
CALL_INCOMING,
|
||||||
|
CALL_OUTGOING,
|
||||||
|
CALL_PICKUP,
|
||||||
|
CALL_REJECT,
|
||||||
|
CALL_START,
|
||||||
|
|
||||||
|
MUSIC_PLAY,
|
||||||
|
MUSIC_PAUSE,
|
||||||
|
MUSIC_PLAYPAUSE,
|
||||||
|
MUSIC_NEXT,
|
||||||
|
MUSIC_PREVIOUS,
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge;
|
||||||
|
|
||||||
|
|
||||||
|
public class GBCommandBundle {
|
||||||
|
public GBCommandClass commandClass;
|
||||||
|
public GBCommand command;
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge;
|
||||||
|
|
||||||
|
public enum GBCommandClass {
|
||||||
|
MUSIC_CONTROL,
|
||||||
|
CALL_CONTROL
|
||||||
|
}
|
@ -0,0 +1,50 @@
|
|||||||
|
package nodomain.freeyourgadget.gadgetbridge;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.os.SystemClock;
|
||||||
|
import android.view.KeyEvent;
|
||||||
|
|
||||||
|
public class GBMusicControlReceiver extends BroadcastReceiver {
|
||||||
|
private final String TAG = this.getClass().getSimpleName();
|
||||||
|
|
||||||
|
public static final String ACTION_MUSICCONTROL = "nodomain.freeyourgadget.gadgetbridge.musiccontrol";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
GBCommand command = GBCommand.values()[intent.getIntExtra("command", 0)];
|
||||||
|
int keyCode;
|
||||||
|
switch (command) {
|
||||||
|
case MUSIC_NEXT:
|
||||||
|
keyCode = KeyEvent.KEYCODE_MEDIA_NEXT;
|
||||||
|
break;
|
||||||
|
case MUSIC_PREVIOUS:
|
||||||
|
keyCode = KeyEvent.KEYCODE_MEDIA_PREVIOUS;
|
||||||
|
break;
|
||||||
|
case MUSIC_PLAY:
|
||||||
|
keyCode = KeyEvent.KEYCODE_MEDIA_PLAY;
|
||||||
|
break;
|
||||||
|
case MUSIC_PAUSE:
|
||||||
|
keyCode = KeyEvent.KEYCODE_MEDIA_PAUSE;
|
||||||
|
break;
|
||||||
|
case MUSIC_PLAYPAUSE:
|
||||||
|
keyCode = KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long eventtime = SystemClock.uptimeMillis();
|
||||||
|
|
||||||
|
Intent downIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||||
|
KeyEvent downEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, keyCode, 0);
|
||||||
|
downIntent.putExtra(Intent.EXTRA_KEY_EVENT, downEvent);
|
||||||
|
context.sendOrderedBroadcast(downIntent, null);
|
||||||
|
|
||||||
|
Intent upIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
|
||||||
|
KeyEvent upEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_UP, keyCode, 0);
|
||||||
|
upIntent.putExtra(Intent.EXTRA_KEY_EVENT, upEvent);
|
||||||
|
context.sendOrderedBroadcast(upIntent, null);
|
||||||
|
}
|
||||||
|
}
|
@ -46,6 +46,14 @@ public class PebbleProtocol {
|
|||||||
static final byte PHONECONTROL_END = 9;
|
static final byte PHONECONTROL_END = 9;
|
||||||
|
|
||||||
static final byte MUSICCONTROL_SETMUSICINFO = 16;
|
static final byte MUSICCONTROL_SETMUSICINFO = 16;
|
||||||
|
static final byte MUSICCONTROL_PLAYPAUSE = 1;
|
||||||
|
static final byte MUSICCONTROL_PAUSE = 2;
|
||||||
|
static final byte MUSICCONTROL_PLAY = 3;
|
||||||
|
static final byte MUSICCONTROL_NEXT = 4;
|
||||||
|
static final byte MUSICCONTROL_PREVIOUS = 5;
|
||||||
|
static final byte MUSICCONTROL_VOLUMEUP = 6;
|
||||||
|
static final byte MUSICCONTROL_VOLUMEDOWN = 7;
|
||||||
|
static final byte MUSICCONTROL_GETNOWPLAYING = 7;
|
||||||
|
|
||||||
static final short LENGTH_PREFIX = 4;
|
static final short LENGTH_PREFIX = 4;
|
||||||
static final short LENGTH_SETTIME = 9;
|
static final short LENGTH_SETTIME = 9;
|
||||||
@ -153,9 +161,26 @@ public class PebbleProtocol {
|
|||||||
return buf.array();
|
return buf.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] encodeSetPhoneState(String number, String name, byte state) {
|
public static byte[] encodeSetCallState(String number, String name, GBCommand command) {
|
||||||
String[] parts = {number, name};
|
String[] parts = {number, name};
|
||||||
return encodeMessage(ENDPOINT_PHONECONTROL, state, 0, parts);
|
byte pebbleCmd;
|
||||||
|
switch (command) {
|
||||||
|
case CALL_START:
|
||||||
|
pebbleCmd = PHONECONTROL_START;
|
||||||
|
break;
|
||||||
|
case CALL_END:
|
||||||
|
pebbleCmd = PHONECONTROL_END;
|
||||||
|
break;
|
||||||
|
case CALL_INCOMING:
|
||||||
|
pebbleCmd = PHONECONTROL_INCOMINGCALL;
|
||||||
|
break;
|
||||||
|
case CALL_OUTGOING:
|
||||||
|
pebbleCmd = PHONECONTROL_OUTGOINGCALL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return encodeMessage(ENDPOINT_PHONECONTROL, pebbleCmd, 0, parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] encodeSetMusicInfo(String artist, String album, String track) {
|
public static byte[] encodeSetMusicInfo(String artist, String album, String track) {
|
||||||
@ -186,23 +211,41 @@ public class PebbleProtocol {
|
|||||||
return buf.array();
|
return buf.array();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: that should return data into some unified struct/Class
|
public static GBCommandBundle decodeResponse(byte[] responseData) {
|
||||||
public static String decodeResponse(byte[] responseData) {
|
|
||||||
ByteBuffer buf = ByteBuffer.wrap(responseData);
|
ByteBuffer buf = ByteBuffer.wrap(responseData);
|
||||||
buf.order(ByteOrder.BIG_ENDIAN);
|
buf.order(ByteOrder.BIG_ENDIAN);
|
||||||
short length = buf.getShort();
|
short length = buf.getShort();
|
||||||
short endpoint = buf.getShort();
|
short endpoint = buf.getShort();
|
||||||
byte extra = 0;
|
byte pebbleCmd = buf.get();
|
||||||
|
GBCommandBundle cmd = new GBCommandBundle();
|
||||||
switch (endpoint) {
|
switch (endpoint) {
|
||||||
case ENDPOINT_PHONECONTROL:
|
case ENDPOINT_MUSICCONTROL:
|
||||||
extra = buf.get();
|
cmd.commandClass = GBCommandClass.MUSIC_CONTROL;
|
||||||
|
switch (pebbleCmd) {
|
||||||
|
case MUSICCONTROL_NEXT:
|
||||||
|
cmd.command = GBCommand.MUSIC_NEXT;
|
||||||
|
break;
|
||||||
|
case MUSICCONTROL_PREVIOUS:
|
||||||
|
cmd.command = GBCommand.MUSIC_PREVIOUS;
|
||||||
|
break;
|
||||||
|
case MUSICCONTROL_PLAY:
|
||||||
|
cmd.command = GBCommand.MUSIC_PLAY;
|
||||||
|
break;
|
||||||
|
case MUSICCONTROL_PAUSE:
|
||||||
|
cmd.command = GBCommand.MUSIC_PAUSE;
|
||||||
|
break;
|
||||||
|
case MUSICCONTROL_PLAYPAUSE:
|
||||||
|
cmd.command = GBCommand.MUSIC_PLAYPAUSE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cmd.command = GBCommand.UNDEFINEND;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
return null;
|
||||||
}
|
}
|
||||||
String ret = "length: " + Short.toString(length) + " Endpoint:" + Short.toString(endpoint) + "/" + Byte.toString(extra);
|
|
||||||
|
|
||||||
return ret;
|
return cmd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,33 +36,33 @@ public class PhoneCallReceiver extends BroadcastReceiver {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte pebblePhoneCommand = -1; // TODO: dont assume Pebble here
|
GBCommand callCommand = null;
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case TelephonyManager.CALL_STATE_RINGING:
|
case TelephonyManager.CALL_STATE_RINGING:
|
||||||
mSavedNumber = number;
|
mSavedNumber = number;
|
||||||
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_INCOMINGCALL;
|
callCommand = GBCommand.CALL_INCOMING;
|
||||||
break;
|
break;
|
||||||
case TelephonyManager.CALL_STATE_OFFHOOK:
|
case TelephonyManager.CALL_STATE_OFFHOOK:
|
||||||
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
|
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
|
||||||
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_START;
|
callCommand = GBCommand.CALL_START;
|
||||||
} else {
|
} else {
|
||||||
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_OUTGOINGCALL;
|
callCommand = GBCommand.CALL_OUTGOING;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TelephonyManager.CALL_STATE_IDLE:
|
case TelephonyManager.CALL_STATE_IDLE:
|
||||||
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
|
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
|
||||||
//pebblePhoneCommand = PebbleProtocol.PHONECONTROL_MISSEDCALL;
|
//missed call would be correct here
|
||||||
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_END; // MISSED CALL DOES NOT WORK
|
callCommand = GBCommand.CALL_END;
|
||||||
} else {
|
} else {
|
||||||
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_END;
|
callCommand = GBCommand.CALL_END;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (pebblePhoneCommand != -1) {
|
if (callCommand != null) {
|
||||||
Intent startIntent = new Intent(context, BluetoothCommunicationService.class);
|
Intent startIntent = new Intent(context, BluetoothCommunicationService.class);
|
||||||
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
|
||||||
startIntent.putExtra("call_phonenumber", mSavedNumber);
|
startIntent.putExtra("call_phonenumber", mSavedNumber);
|
||||||
startIntent.putExtra("call_state", pebblePhoneCommand);
|
startIntent.putExtra("call_command", callCommand.ordinal());
|
||||||
context.startService(startIntent);
|
context.startService(startIntent);
|
||||||
}
|
}
|
||||||
mLastState = state;
|
mLastState = state;
|
||||||
|
@ -10,8 +10,7 @@ public class StopServiceReceiver extends BroadcastReceiver {
|
|||||||
Intent stopIntent = new Intent(context, BluetoothCommunicationService.class);
|
Intent stopIntent = new Intent(context, BluetoothCommunicationService.class);
|
||||||
context.stopService(stopIntent);
|
context.stopService(stopIntent);
|
||||||
|
|
||||||
Intent quitIntent = new Intent();
|
Intent quitIntent = new Intent(ControlCenter.ACTION_QUIT);
|
||||||
quitIntent.setAction(ControlCenter.ACTION_QUIT);
|
|
||||||
context.sendBroadcast(quitIntent);
|
context.sendBroadcast(quitIntent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user