I'm trying to develop a simple multiplayer game using bluetooth with Eclipse
The game is already working in single player mode (using AndEngine), but now I need to send information
between devices.
The part that concerns establishing connection between devices,and link them
is already working, and I can send messages between devices, but now I need to
start the game on "the other" device, so I think that the solution is sending an Intent
using Bluetooth, but I'm not sure if this is possible or not.
So, how can I start the game in both devices at the same time? (I don't want the game in real time, I just want to compare the number of coins that each player gets).
Thank you very much!
If you see the "Uno" game, you'll get some idea. There, they aren't using Bluetooth, but WiFi.
From that I learned, and some other bluetooth games that you wait for Connection successful.
If you're using BluetoothChat application as the reference, then use your Handler as your event generator to start your game.
// The Handler that gets information back from the BluetoothChatService
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
if(D) Log.i(TAG, "MESSAGE_STATE_CHANGE: " + msg.arg1);
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
mConversationArrayAdapter.clear();
// DO YOUR ACTIVITY HERE .. ..
// May Be like ... Intent intent = new Intent( ... )
break;
Related
I am writing some code for a Xamarin Forms Android app which dials a phone number but I don't want to dial the number if the user is currently on a call(whether incoming or outgoing, it doesn't make a difference). I have researched a lot about the phone state but I can't find what I am looking for, unless I am applying it incorrectly. What I need is something like this:
if (NoCurrentCallIsTakingPlace)
{
var uri = Android.Net.Uri.Parse(string.Format("tel:{0}", PhoneNumber));
var intent = new Intent(Intent.ActionCall, uri);
Xamarin.Forms.Forms.Context.StartActivity(CurrentIntent);
}
The code to dial the number works but it's the the conditional statement/code to check the phone state that I am having a problem with. Please could someone help. Apologies if your need more info. Please let me know and I will provide it. Thank you.
Well in native android you have the telephony manager to check what is the state of your device:
It has three states:
Idle: when it's idle there is no call
Offhook: when Off-hook it is in call
Ringing: when Ringing
var telephonyManagerService = (TelephonyManager)Xamarin.Forms.Forms.Context.GetSystemService(TelephonyService);
var getCurrentState = telephonyManagerService?.CallState;
switch (getCurrentState)
{
case CallState.Idle:
//No call
break;
case CallState.Ringing:
//Ringing
break;
case CallState.Offhook:
//On call
break;
default:
break;
}
Revert in case of queries
I'm building an Android media player application that I intend to use to play media (videos, pictures, etc.) on a TV while connected via an HDMI cable.
I want to have the media player app pause when the TV's power status is OFF and want it to play when the TV is turned ON.
How do I detect the TV's power status within my Android application when my Android device is connected to the TV via HDMI?
Both the TV and the Android device have support for HDMI-CEC. The device in question is an ODROID C2. I've seen this functionality on the KODI Android application which has a feature to pause the video when the HDMI-CEC status is OFF, I'm looking to implement this within my app as well.
Any help is appreciated. Thanks in advance!
EDIT: Progress below
I tried reading the status of the HDMI connection from within this file /sys/devices/virtual/switch/hdmi/state. However, this file holds int 1 no matter whether the power status of the connected screen / TV is ON or OFF.
2nd Progress update
I'm still working on this. Will not give up, and once I'm done I will surely post the answer here.
You can listen for changes in HDMI status (0 for unplugged and 1 for plugged) by registering for ACTION_HDMI_AUDIO_PLUG. It reports with status 0 when tv is switched off, switches to any other display medium or HDMI is removed. To read into its technicality, you can check out how hot plug detection works in HDMI. Overall, your app can at all times monitor whether the display can currently play your content or not. I have myself implemented this in a solution (on X96 mini android box & amazon fire-stick) where I needed to ensure that the content was actually being played because it included paid content. Also, I have attached the sample code file.
Note: This solution will only work when android device is HDMI source not sink!
Here's the documentation link too- https://developer.android.com/reference/android/media/AudioManager#ACTION_HDMI_AUDIO_PLUG
private BroadcastReceiver eventReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// pause video
String action = intent.getAction();
switch (action) {
case ACTION_HDMI_AUDIO_PLUG :
// EXTRA_AUDIO_PLUG_STATE: 0 - UNPLUG, 1 - PLUG
Toast.makeText(getApplicationContext(),"HDMI PLUGGED OR UNPLUGGED",Toast.LENGTH_LONG).show();
Log.d("MainActivity", "ACTION_HDMI_AUDIO_PLUG " + intent.getIntExtra(EXTRA_AUDIO_PLUG_STATE, -1));
((TextView)(findViewById(R.id.textView))).setText(((TextView)(findViewById(R.id.textView))).getText().toString().concat("At "+System.nanoTime()+": "+intent.getIntExtra(EXTRA_AUDIO_PLUG_STATE, -1) +"\n"));
break;
}
}
};
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(eventReceiver);
}
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_HDMI_AUDIO_PLUG);
registerReceiver(eventReceiver, filter);
}
In Some TV's, You need to monitor that (sys/class/amhdmitx/amhdmitx0/hpd_state) folder for changes by 500 ms Interval. because it'll change from 1 to 0 and again from 0 to 1 within 1 seconds.
I'm having trouble to check if a participant is still connected to a room.
I wrote this:
bool status=GooglePlayGames.Native.PInvoke.MultiplayerParticipant.AutomatchingSentinel().IsConnectedToRoom();
if (status = true)
{
this.gameObject.GetComponent<Text> ().text = "participant is connected";
}
if (status = false)
{
this.gameObject.GetComponent<Text> ().text = "participant left";
}`
When players are connected, "participant is connected" is displayed.
But when a player press the home button, and go back to the screen, the participant had OnPeersDisconnected called and leave the room. But for the actual player, "participant is connected" is still displayed.
How can i know when the IsConnectedToRoom() is false?
This may still depend on how implementation is going to be. According to the document:
Make sure to construct your game logic carefully to take each participant's status and connectedness into account. For example, to determine if all racers have crossed the finish line, your game should only consider the participants who are connected; some may have left the room or never have accepted the invitation.
Detecting when a player is disconnected
Your player might be disconnected from the room due to network connectivity or server issues. To be notified when a player is disconnected from the room, implement the OnConnectedSetChanged method.
virtual void OnConnectedSetChanged(RealTimeRoom const &room) {
// Check the room's participants to see who connected/disconnected.
}
Hope this helps.
My Question is: Can Android 4.3 (client) have active connections with multiple BLE devices (servers)? If so, how can I achieve it?
What I did so far
I try to evaluate what throughput you can achieve using BLE and Android 4.3 BLE API. In addition I also try to find out how many devices can be connected and active at the same time. I use a Nexus 7 (2013), Android 4.4 as master and TI CC2540 Keyfob as slaves.
I wrote a simple server software for the slaves, which transmits 10000 20Byte packets through BLE notifications. I based my Android App on the Application Accelerator from the Bluetooth SIG.
It works well for one device and I can achieve around 56 kBits payload throughput at a Connection Interval of 7.5 ms. To connect to multiple slaves I followed the advice of a Nordic Employee who wrote in the Nordic Developer Zone:
Yes it's possible to handle multiple slaves with a single app. You would need to handle each slave with one BluetoothGatt instance. You would also need specific BluetoothGattCallback for each slave you connect to.
So I tried that and it partly works. I can connect to multiple slaves. I can also register for notifications on multiple slaves. The problem begins when I start the test. I receive at first notifications from all slaves, but after a couple Connection Intervals just the notifications from one device come trough. After about 10 seconds the other slaves disconnect, because they seem to reach the connection time-out. Sometimes I receive right from the start of the test just notifications from one slave.
I also tried accessing the attribute over a read operation with the same result. After a couple of reads just the answers from one device came trough.
I am aware that there are a few similar questions on this forum: Does Android 4.3 support multiple BLE device connections?, Has native Android BLE GATT implementation synchronous nature? or Ble multiple connection. But none of this answers made it clear for me, if it is possible and how to do it.
I would be very grateful for advice.
I suspect everyone adding delays is just allowing the BLE system to complete the action you have asked before you submit another one. Android's BLE system has no form of queueing. If you do
BluetoothGatt g;
g.writeDescriptor(a);
g.writeDescriptor(b);
then the first write operation will immediately be overwritten with the second one. Yes it's really stupid and the documentation should probably actually mention this.
If you insert a wait, it allows the first operation to complete before doing the second. That is a huge ugly hack though. A better solution is to implement your own queue (like Google should have). Fortunately Nordic have released one for us.
https://github.com/NordicSemiconductor/puck-central-android/tree/master/PuckCentral/app/src/main/java/no/nordicsemi/puckcentral/bluetooth/gatt
Edit: By the way this is the universal behaviour for BLE APIs. WebBluetooth behaves the same way (but Javascript does make it easier to use), and I believe iOS's BLE API also behaves the same.
Re visting the bluetooth-lowenergy problem on android: I am still using delays.
The concept: after every major action that provokes the BluetoothGattCallback (e.g. conenction, service discovery, write, read) a dealy is needed. P.S. have a look at Google example on BLE API level 19 sample for connectivity to understand how Broadcasts should be sent and get some general understanding etc...
Firstly, scan (or scan) for BluetoothDevices, populate the connectionQueue with desired devices and call initConnection().
Have a look on the following example.
private Queue<BluetoothDevice> connectionQueue = new LinkedList<BluetoothDevice>();
public void initConnection(){
if(connectionThread == null){
connectionThread = new Thread(new Runnable() {
#Override
public void run() {
connectionLoop();
connectionThread.interrupt();
connectionThread = null;
}
});
connectionThread.start();
}
}
private void connectionLoop(){
while(!connectionQueue.isEmpty()){
connectionQueue.poll().connectGatt(context, false, bleInterface.mGattCallback);
try {
Thread.sleep(250);
} catch (InterruptedException e) {}
}
}
Now if all is good, you have made connections and BluetoothGattCallback.onConnectionStateChange(BluetoothGatt gatt, int status, int newState) has been called.
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch(status){
case BluetoothGatt.GATT_SUCCESS:
if (newState == BluetoothProfile.STATE_CONNECTED) {
broadcastUpdate(BluetoothConstants.ACTION_GATT_CONNECTED, gatt);
}else if(newState == BluetoothProfile.STATE_DISCONNECTED){
broadcastUpdate(BluetoothConstants.ACTION_GATT_DISCONNECTED, gatt);
}
break;
}
}
protected void broadcastUpdate(String action, BluetoothGatt gatt) {
final Intent intent = new Intent(action);
intent.putExtra(BluetoothConstants.EXTRA_MAC, gatt.getDevice().getAddress());
sendBroadcast(intent);
}
P.S. sendBroadcast(intent) might need to be done like this:
Context context = activity.getBaseContext();
context.sendBroadcast(intent);
Then the broadcast is received by BroadcastReceiver.onReceive(...)
public BroadcastReceiver myUpdateReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if(BluetoothConstants.ACTION_GATT_CONNECTED.equals(action)){
//Connection made, here you can make a decision: do you want to initiate service discovery.
// P.S. If you are working with multiple devices,
// make sure that you start the service discovery
// after all desired connections are made
}
....
}
}
After doing whatever you want in the broadcast receiver, here is how I continue:
private Queue<BluetoothGatt> serviceDiscoveryQueue = new LinkedList<BluetoothGatt>();
private void initServiceDiscovery(){
if(serviceDiscoveryThread == null){
serviceDiscoveryThread = new Thread(new Runnable() {
#Override
public void run() {
serviceDiscovery();
serviceDiscoveryThread.interrupt();
serviceDiscoveryThread = null;
}
});
serviceDiscoveryThread.start();
}
}
private void serviceDiscovery(){
while(!serviceDiscoveryQueue.isEmpty()){
serviceDiscoveryQueue.poll().discoverServices();
try {
Thread.sleep(250);
} catch (InterruptedException e){}
}
}
Again, after a successful service discovery, BluetoothGattCallback.onServicesDiscovered(...) is called. Again, I send an intent to the BroadcastReceiver (this time with different action String) and it is now that you can start reading, writing and enabling notifications/indications...
P.S. If you are working with multiple devices, make sure that you start the reading, writing etc... stuff after all devices have reported that their services have been discovered.
private Queue<BluetoothGattCharacteristic> characteristicReadQueue = new LinkedList<BluetoothGattCharacteristic>();
private void startThread(){
if(initialisationThread == null){
initialisationThread = new Thread(new Runnable() {
#Override
public void run() {
loopQueues();
initialisationThread.interrupt();
initialisationThread = null;
}
});
initialisationThread.start();
}
}
private void loopQueues() {
while(!characteristicReadQueue.isEmpty()){
readCharacteristic(characteristicReadQueue.poll());
try {
Thread.sleep(BluetoothConstants.DELAY);
} catch (InterruptedException e) {}
}
// A loop for starting indications and all other stuff goes here!
}
BluetoothGattCallback will have all your incoming data from the BLE sensor. A good practice is to send a broadcast with the data to your BroadcastReceiver and handle it over there.
I am developing an app with BLE features myself. The way I managed to connect to multiple devices and turn on notifications was to implement delays.
So I make a new thread (in order not to block UI thread) and in the new thread connect and turn on notifications.
For example, after BluetoothDevice.connectGatt(); call Thread.sleep();
And add the same delay for read/write and enable/dissable notifications.
EDIT
Use wait like this so that Android dindn't reaise ANR
public static boolean waitIdle() {
int i = 300;
i /= 10;
while (--i > 0) {
if (true)
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return i > 0;
}
Unfortunately notifications in the current Android BLE stack are a bit buggy. There are some hardcoded limits and I've found some stability issues even with a single device. (I read at one point that you could only have 4 notifications... not sure if that's across all devices or per device. Trying to find the source for that info now.)
I would try switching to a polling loop (say, poll the items in question 1/sec) and seeing if you find your stability increases. I would also consider switching to a different slave device (say a HRM or the TI SensorTag) to see if there is perhaps an issue with the slave-side code (unless you can test that against iOS or another platform and confirm it isn't part of the issue).
Edit: Reference for notification limitation
Rain is right in his answer, you need delays for pretty much everything when you work with BLE in Android. I developed several apps with it and it is really necessary. By using them you avoid a lot of crashes.
In my case, I use delays after every read/write command. Doing so, you ensure you receive the response from the BLE device almost always. I do something like this: (of course everything is done in a separate thread to avoid to much work on the main thread)
readCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
myChar.getValue();
or:
myChar.setValue(myByte);
writeCharacteristic(myChar);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
This is really useful when you read/write several characteristics in a row... As Android is enough fast to execute the commands almost instantly, if you don't use a delay between them you may get errors or incoherent values...
Hope it helps even if it is not exactly the answer to your question.
This question is more of a "is it possible" question.
Is it possible for Android to use a different contact list from an application when displaying the identity of an incoming caller?
So for example, if a person calls and their identity is in the apps contact list, but NOT in the internal devices contact list, i want to make the id found in the apps contact list show up on the caller id of the incoming call.
Any insight would be appreciated!
I found the solution I was looking for. I ended up just using a notification to display who was calling. I hope this helps someone else out there looking for a nice solution!
StateListener yourListener = new StateListener();
TelephonyManager yourmanager =(TelephonyManager)getSystemService(TELEPHONY_SERVICE);
yourmanager.listen(yourListener, PhoneStateListener.LISTEN_CALL_STATE);
class StateListener extends PhoneStateListener{
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
//do what you want with the incoming number here:
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
};
public void onDestroy() {
}
}
I think it's possible with broadcast receiver. Here some similar question Call block, Taking complete control of phone, is it possible and another open source app called Intent Intercept. I give you call blocking link so you can catch number, direct to your app and block normal dialer