Implement music control (play, pause, next, previous). Try to make code a bit less Pebble centric.

This commit is contained in:
Andreas Shimokawa 2015-02-12 16:00:45 +01:00
parent 20b3dffba6
commit df8c290442
10 changed files with 181 additions and 29 deletions

View File

@ -72,6 +72,11 @@
</receiver>
<receiver android:name=".StopServiceReceiver" />
<receiver android:name=".GBMusicControlReceiver">
<intent-filter>
<action android:name="nodomain.freeyourgadget.gadgetbridge.musiccontrol" />
</intent-filter>
</receiver>
<activity
android:name=".DebugActivity"

View File

@ -114,6 +114,23 @@ public class BluetoothCommunicationService extends Service {
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
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);
mBtSocketIoThread.write(msg);
} 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 callerName = null;
if (phoneNumber != null) {
callerName = getContactDisplayNameByNumber(phoneNumber);
}
byte[] msg = PebbleProtocol.encodeSetPhoneState(phoneNumber, callerName, phoneState);
byte[] msg = PebbleProtocol.encodeSetCallState(phoneNumber, callerName, command);
mBtSocketIoThread.write(msg);
} else if (intent.getAction().equals(ACTION_SETTIME)) {
byte[] msg = PebbleProtocol.encodeSetTime(-1);
@ -330,7 +347,12 @@ public class BluetoothCommunicationService extends Service {
Log.i(TAG, "Pebble asked for Phone/App Version - repLYING!");
write(PebbleProtocol.encodePhoneVersion(PebbleProtocol.PHONEVERSION_REMOTE_OS_ANDROID));
} 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 {
Thread.sleep(100);

View File

@ -73,7 +73,7 @@ public class DebugActivity extends ActionBarActivity {
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_INCOMINGCALL);
startIntent.putExtra("call_command", GBCommand.CALL_INCOMING.ordinal());
startService(startIntent);
}
});
@ -84,7 +84,7 @@ public class DebugActivity extends ActionBarActivity {
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
startIntent.putExtra("call_phonenumber", editContent.getText().toString());
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_OUTGOINGCALL);
startIntent.putExtra("call_command", GBCommand.CALL_OUTGOING.ordinal());
startService(startIntent);
}
});
@ -95,7 +95,7 @@ public class DebugActivity extends ActionBarActivity {
public void onClick(View v) {
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_START);
startIntent.putExtra("call_command", GBCommand.CALL_START.ordinal());
startService(startIntent);
}
});
@ -105,7 +105,7 @@ public class DebugActivity extends ActionBarActivity {
public void onClick(View v) {
Intent startIntent = new Intent(DebugActivity.this, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
startIntent.putExtra("call_state", PebbleProtocol.PHONECONTROL_END);
startIntent.putExtra("call_command", GBCommand.CALL_END.ordinal());
startService(startIntent);
}
});

View File

@ -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,
}

View File

@ -0,0 +1,7 @@
package nodomain.freeyourgadget.gadgetbridge;
public class GBCommandBundle {
public GBCommandClass commandClass;
public GBCommand command;
}

View File

@ -0,0 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge;
public enum GBCommandClass {
MUSIC_CONTROL,
CALL_CONTROL
}

View File

@ -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);
}
}

View File

@ -46,6 +46,14 @@ public class PebbleProtocol {
static final byte PHONECONTROL_END = 9;
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_SETTIME = 9;
@ -153,9 +161,26 @@ public class PebbleProtocol {
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};
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) {
@ -186,23 +211,41 @@ public class PebbleProtocol {
return buf.array();
}
// FIXME: that should return data into some unified struct/Class
public static String decodeResponse(byte[] responseData) {
public static GBCommandBundle decodeResponse(byte[] responseData) {
ByteBuffer buf = ByteBuffer.wrap(responseData);
buf.order(ByteOrder.BIG_ENDIAN);
short length = buf.getShort();
short endpoint = buf.getShort();
byte extra = 0;
byte pebbleCmd = buf.get();
GBCommandBundle cmd = new GBCommandBundle();
switch (endpoint) {
case ENDPOINT_PHONECONTROL:
extra = buf.get();
case ENDPOINT_MUSICCONTROL:
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;
default:
break;
return null;
}
String ret = "length: " + Short.toString(length) + " Endpoint:" + Short.toString(endpoint) + "/" + Byte.toString(extra);
return ret;
return cmd;
}
}

View File

@ -36,33 +36,33 @@ public class PhoneCallReceiver extends BroadcastReceiver {
return;
}
byte pebblePhoneCommand = -1; // TODO: dont assume Pebble here
GBCommand callCommand = null;
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
mSavedNumber = number;
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_INCOMINGCALL;
callCommand = GBCommand.CALL_INCOMING;
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_START;
callCommand = GBCommand.CALL_START;
} else {
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_OUTGOINGCALL;
callCommand = GBCommand.CALL_OUTGOING;
}
break;
case TelephonyManager.CALL_STATE_IDLE:
if (mLastState == TelephonyManager.CALL_STATE_RINGING) {
//pebblePhoneCommand = PebbleProtocol.PHONECONTROL_MISSEDCALL;
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_END; // MISSED CALL DOES NOT WORK
//missed call would be correct here
callCommand = GBCommand.CALL_END;
} else {
pebblePhoneCommand = PebbleProtocol.PHONECONTROL_END;
callCommand = GBCommand.CALL_END;
}
break;
}
if (pebblePhoneCommand != -1) {
if (callCommand != null) {
Intent startIntent = new Intent(context, BluetoothCommunicationService.class);
startIntent.setAction(BluetoothCommunicationService.ACTION_CALLSTATE);
startIntent.putExtra("call_phonenumber", mSavedNumber);
startIntent.putExtra("call_state", pebblePhoneCommand);
startIntent.putExtra("call_command", callCommand.ordinal());
context.startService(startIntent);
}
mLastState = state;

View File

@ -10,8 +10,7 @@ public class StopServiceReceiver extends BroadcastReceiver {
Intent stopIntent = new Intent(context, BluetoothCommunicationService.class);
context.stopService(stopIntent);
Intent quitIntent = new Intent();
quitIntent.setAction(ControlCenter.ACTION_QUIT);
Intent quitIntent = new Intent(ControlCenter.ACTION_QUIT);
context.sendBroadcast(quitIntent);
}
}