terminate the BB 10 app on Alert button ok pressed - qml

I have a socket connection App in my BB 10 cascades, when ever socket connection is closed i need to show a dialog box and when pressed on OK button app need to close.
please find my code here...
void SocketBase::writeLine(QTcpSocket *socket, const QString &line)
{
if (socket->state() != QAbstractSocket::ConnectedState)
{
onOkAlert("Please check your internet connection and restart the app again");
}
}
void SocketBase::onOkAlert(const QString &message)
{
dialog = new SystemDialog(tr("OK"), 0);
dialog->setTitle(tr("Alert"));
dialog->setBody(message);
bool success= QObject::connect(dialog,SIGNAL(finished(bb::system::SystemUiResult::Type)),
this,
SLOT(onDialogFinishe(bb::system::SystemUiResult::Type)));
if(success){
dialog->show();
}
}
and I also added at top of my class,
using namespace bb::data;
using namespace bb::cascades;
using namespace bb::system;
SystemDialog *dialog;
and my socketBase.h is like,
class SocketBase: public QObject{
Q_OBJECT
public:
SocketBase(const QString &ipAddr, const ushort port) :
mIP(ipAddr), mPort(port) {
mRunThread = false;
}
enum Identity {
BAD_IDENTITY, SERVER, CLIENT
};
virtual void startThread() = 0;
virtual void stopThread() = 0;
virtual Identity getIdentity() = 0;
Q_INVOKABLE void showDialog(int id);
void onOkAlert(const QString &message);
private slots:
void onAPPFinished();
void onDialogFinishe(bb::system::SystemUiResult::Type);
}
here is the app termination code
void SocketBase::onDialogFinishe(bb::system::SystemUiResult::Type)
{
qDebug()<<" dialog->result():::"<<dialog->result();
if(dialog->result()==2)
{
qDebug()<<"::: Terminate App :::";
bb::Application::exit(0);
}
}
what is wrong in my code, please help!!!

Related

Revit external command with progress bar and 'Cancel' button

I am developing a new external command for Revit. it needs a progress bar + a button to cancel its execution in any moment.
In order to get it, I haver implemented a external event.
Implementing an external event handler with de code to be executed by the command.
public class GestorDeEventoExterno : IExternalEventHandler
{
public bool CancellationRequested { get; set; }
private VentanaDeProgreso progressAndcancelWindow;
private EventWaitHandle eventWait;
public void Execute(UIApplication aplicacionDeLaIU)
{
using (this.eventWait = new AutoResetEvent(false))
{
// New thread for the progress bar.
Thread progressBarThread = new Thread(new ThreadStart(() =>
{
// Populating the progress bar window.
this.progressAndcancelWindow = new VentanaDeProgreso(this);
progressAndcancelWindow.Show();
// Chenge the state of the wait event.
this.eventWait.Set();
Dispatcher.Run();
}));
progressBarThread.SetApartmentState(ApartmentState.STA);
progressBarThread.IsBackground = true;
progressBarThread.Start();
this.eventWait.WaitOne();
}
// Get the current revit document.
Document documentoActivo = aplicacionDeLaIU.ActiveUIDocument.Document;
// Code to simulate the revit command operation.
for (int i = 0;
i <= 100;
i++)
{
// Code to be executed if a cancellation has been requested.
if (this.CancellationRequested)
{
TaskDialog.Show("Test", "Cancel");
this.progressAndcancelWindow.Dispatcher.Invoke(new Action(this.progressAndcancelWindow.Close));
return;
}
this.progressAndcancelWindow.ActualizarProgreso($"loop number: {i}", i, 100);
Thread.Sleep(100);
}
this.progressAndcancelWindow.Dispatcher.Invoke(new Action(this.progressAndcancelWindow.Close));
TaskDialog.Show("Test", "END");
}
public string GetName()
{
return "test";
}
}
Implementing an external command to register the external event and populate the main window
public class Class1 : IExternalCommand
{
public Result Execute(
ExternalCommandData externalCommandData,
ref string message,
ElementSet elements)
{
// Registering the external event.
GestorDeEventoExterno externalEventHandler = new GestorDeEventoExterno();
ExternalEvent externalEvent = ExternalEvent.Create(externalEventHandler);
// Populating the main window.
VentanaPrincipal mainWindow = new VentanaPrincipal(
externalEvent);
mainWindow.Show();
return Result.Succeeded;
}
}
Finally, the code behind of the progress bar window
public partial class VentanaDeProgreso : Window
{
private GestorDeEventoExterno externalEventHandler;
public void ActualizarProgreso(
string texto,
int valorActual,
int valortotal = 100)
{
this.Dispatcher.Invoke(
new Action<string, int, int>(
delegate (string txt, int vActual, int vTotal)
{
this.IndicadorDeProgreso.Value = valorActual;
this.IndicadorDeProgreso.Maximum = vTotal;
this.Texto.Text = txt;
}),
System.Windows.Threading.DispatcherPriority.Background,
texto,
valorActual,
valortotal);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// AsignaciĆ³n de valor verdadero a la propiedad de cancelaciĆ³n solicitada del evento externo.
this.externalEventHandler.CancellationRequested = true;
}
public VentanaDeProgreso(GestorDeEventoExterno externalEventHandler)
{
InitializeComponent();
this.externalEventHandler= externalEventHandler;
}
}
AS you can see, the progress window has the external event handler as a property and the cancel button click event sets the property 'CancellationRequested'.
My question is: How can I improve it?
You do not need an external event to cancel your command.
You only need an external event to cancel submit a request to execute Revit API functionality from some context in which it is not available.
Your cancellation requires no Revit API functionality, just your own stuff, hence no external event.
Therefore, you can restructure the whole solution much more simply. Kiss!

Is TextToSpeech supported on Google Glass?

I was wondering if TextToSpeech is supported on Google Glass?
I did something like this:
public class TextToSpeechController implements TextToSpeech.OnInitListener{
private Context mContext;
private TextToSpeech tts;
public TextToSpeechController(Context context) {
Log.e("TEXT TO SPEECH CONTROLLER", "controller");
mContext = context;
tts = new TextToSpeech(context, this);
}
#Override
public void onInit(int status) {
Log.e("INIT TTS", "INIT");
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.ENGLISH);
if (result == TextToSpeech.LANG_MISSING_DATA || result == TextToSpeech.LANG_NOT_SUPPORTED) {
Toast.makeText(mContext, "This Language is not supported", Toast.LENGTH_LONG).show();
}
else {
Toast.makeText(mContext, "Ready to Speak", Toast.LENGTH_LONG).show();
speakTheText("Welcome to Vision Screening App");
}
}
else {
Toast.makeText(mContext, "Can Not Speak", Toast.LENGTH_LONG).show();
}
}
public void stopTTS(){
Log.e(".....TTS", "SHUTDOWN");
tts.stop();
tts.shutdown();
}
public void speakTheText(String str){
Log.e("SPEAK TEXT!!!!", "SPEAK TEXT");
tts.speak(str, TextToSpeech.QUEUE_FLUSH, null);
}
}
and in my Activity (onCreate) I have:
controller_tts = new TextToSpeechController(getApplicationContext());
I face several problems :
First of all the onInit method is not called at all, only at the moment when I exit the current Activity.
Somehow, after using TTS, the speeker's volume turns to mute and I cannot turn the volume back from the settings(only after I reboot the Glasses)
Am I doing something wrong? or simply Google Glass does not support TTS, even thought is hard to believe that.
Any suggestion is welcome! Thank you very much!:)
Is it possible that you are calling stopTTS before TextToSpeech is initialized?
This works just fine for me on Glass:
import android.app.Activity;
import android.os.Bundle;
import android.speech.tts.TextToSpeech;
import android.view.MotionEvent;
import android.widget.TextView;
import java.util.Locale;
public class TTSTestActivity extends Activity
implements TextToSpeech.OnInitListener {
private TextToSpeech tts;
private boolean initialized = false;
private String queuedText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
TextView view = new TextView(this);
view.setText("Tap Me");
setContentView(view);
tts = new TextToSpeech(this /* context */, this /* listener */);
}
#Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
initialized = true;
tts.setLanguage(Locale.ENGLISH);
if (queuedText != null) {
speak(queuedText);
}
}
}
public void speak(String text) {
// If not yet initialized, queue up the text.
if (!initialized) {
queuedText = text;
return;
}
queuedText = null;
// Before speaking the current text, stop any ongoing speech.
tts.stop();
// Speak the text.
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
// On any motion event (including touchpad tap), say 'Hello Glass'
speak("Hello Glass");
return true;
}
}
With this example, anytime you tap the touch pad (or cause any other type of motion event), you should hear "Hello Glass." Note that if text is provided before TextToSpeech has initialized, then this is queued and then spoken after initialization is a success.
This does not include any tear-down, but to do that you can always put stop/shutdown of TextToSpeech in onDestroy() of the activity.

Auto connecting to a BLE device

I am working on an application to coommunicate against a BLE device, currently I am trying to create a Service that starts with the application and auto connect to TI's CC2541 keyfob.
Problem is the gatt server seem to fail EVERY TIME....
I have no clue whats wrong with my code since by google API's and some tutorials I saw
It seems that all the pieces are in their place, yet still nothing works... =(
Here is my service -
package com.example.bluetoothgatt;
import java.util.UUID;
import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
public class BLE extends Service implements BluetoothAdapter.LeScanCallback {
private final IBinder mBinder = new BluetoothLeBinder();
private final static String TAG = "BLE";
private static final String DEVICE_NAME = "Keyfobdemo";
private BluetoothManager mBluetoothManager;
public BluetoothGatt mConnectedGatt;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mDevice;
private String mDeviceAddress;
private int mConnectionState = STATE_DISCONNECTED;
private static final int STATE_DISCONNECTED = 0;
private static final int STATE_CONNECTING = 1;
private static final int STATE_CONNECTED = 2;
/*******************************
*******************************
****** Service Inherited ****** Methods **********
*******************************/
#Override
public void onCreate() {
super.onCreate();
mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
Thread discoverDevices = new Thread(mStartRunnable);
discoverDevices.setPriority(discoverDevices.MAX_PRIORITY);
discoverDevices.start();
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
close();
return super.onUnbind(intent);
}
// Implements callback methods for GATT events that the app cares about.
// For example, connection change and services discovered.
private final BluetoothGattExecutor mExecutor = new BluetoothGattExecutor() {
#Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
mConnectionState = STATE_CONNECTED;
mConnectedGatt = gatt;
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
mConnectionState = STATE_DISCONNECTED;
Log.i(TAG, "Disconnected from GATT server.");
}
}
#Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
} else {
Log.w(TAG, "onServicesDiscovered received: " + status);
}
}
#Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
if (status == BluetoothGatt.GATT_SUCCESS) {
}
}
#Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
};
/**
* Return a reference for the current class
*/
public class BluetoothLeBinder extends Binder {
BLE getService() {
return BLE.this;
}
}
private Runnable mStartRunnable = new Runnable() {
#Override
public void run() {
startScan();
}
};
private void startScan() {
if (mConnectionState == STATE_DISCONNECTED) {
mBluetoothAdapter.startLeScan(this);
mHandler.postDelayed(mStopRunnable, 2500);
}
}
private Runnable mStopRunnable = new Runnable() {
#Override
public void run() {
stopScan();
}
};
private void stopScan() {
mBluetoothAdapter.stopLeScan(this);
}
#Override
public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
/*
* We are looking for SensorTag devices only, so validate the name that
* each device reports before adding it to our collection
*/
if (DEVICE_NAME.equals(device.getName())) {
mDevice = device;
mDeviceAddress = mDevice.getAddress();
connect(mDeviceAddress);
mConnectionState = STATE_CONNECTING;
if(device.getBondState() == BluetoothDevice.BOND_BONDED) {
} else if (device.getBondState() == BluetoothDevice.BOND_BONDING) {
} else if(device.getBondState() == BluetoothDevice.BOND_NONE) {
connect(device.getAddress());
}
}
}
/**
* Connects to the GATT server hosted on the Bluetooth LE device.
*
* #param address
* The device address of the destination device.
*
* #return Return true if the connection is initiated successfully. The
* connection result is reported asynchronously through the
* {#code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)}
* callback.
*/
public boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG,
"BluetoothAdapter not initialized or unspecified address.");
return false;
}
// Previously connected device. Try to reconnect.
if (mDeviceAddress != null && address.equals(mDeviceAddress)
&& mConnectedGatt != null) {
Log.d(TAG,
"Trying to use an existing BluetoothGatt for connection.");
if (mConnectedGatt.connect()) {
mConnectionState = STATE_CONNECTING;
return true;
} else {
return false;
}
}
final BluetoothDevice device = mBluetoothAdapter
.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found. Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the
// autoConnect
// parameter to false.
mConnectedGatt = device.connectGatt(this, false, mExecutor);
Log.d(TAG, "Trying to create a new connection.");
mDeviceAddress = address;
mConnectionState = STATE_CONNECTING;
return true;
}
/**
* Disconnects an existing connection or cancel a pending connection. The
* disconnection result is reported asynchronously through the
* BluetoothGattCallback >>
* onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)
* callback.
*/
public void disconnect() {
if (mBluetoothAdapter == null || mConnectedGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mConnectedGatt.disconnect();
}
/**
* After using a given BLE device, the app must call this method to ensure
* resources are released properly.
*/
public void close() {
if (mConnectedGatt == null) {
return;
}
mConnectedGatt.close();
mConnectedGatt = null;
}
private final UUID IMMEDIATE_ALERT_UUID = UUID
.fromString("00001802-0000-1000-8000-00805f9b34fb");
private final UUID ALERT_LEVEL_UUID = UUID
.fromString("00002a06-0000-1000-8000-00805f9b34fb");
public void Buzz(BluetoothGatt gatt, int level) {
BluetoothGattService alertService = gatt
.getService(IMMEDIATE_ALERT_UUID);
if (alertService == null) {
Log.d(TAG, "Immediate Alert service not found!");
return;
}
BluetoothGattCharacteristic alertLevel = alertService
.getCharacteristic(ALERT_LEVEL_UUID);
if (alertLevel == null) {
Log.d(TAG, "Alert Level charateristic not found!");
return;
}
alertLevel.setValue(level, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
gatt.writeCharacteristic(alertLevel);
Log.d(TAG, "Alert");
}
private final UUID BATTERY_SERVICE_UUID = UUID
.fromString("0000180F-0000-1000-8000-00805f9b34fb");
private final UUID BATTERY_LEVEL_UUID = UUID
.fromString("00002a19-0000-1000-8000-00805f9b34fb");
public int getbattery(BluetoothGatt mBluetoothGatt) {
BluetoothGattService batteryService = mConnectedGatt
.getService(BATTERY_SERVICE_UUID);
if (batteryService == null) {
Log.d(TAG, "Battery service not found!");
return 0;
}
BluetoothGattCharacteristic batteryLevel = batteryService
.getCharacteristic(BATTERY_LEVEL_UUID);
if (batteryLevel == null) {
Log.d(TAG, "Battery level not found!");
return 0;
}
mBluetoothGatt.readCharacteristic(batteryLevel);
return batteryLevel.getIntValue(
BluetoothGattCharacteristic.FORMAT_SINT8, 0);
}
/*
* We have a Handler to process event results on the main thread
*/
private static final int MSG_PROGRESS = 201;
private static final int MSG_DISMISS = 202;
private static final int MSG_CLEAR = 301;
private Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
BluetoothGattCharacteristic characteristic;
switch (msg.what) {
case MSG_PROGRESS:
break;
case MSG_DISMISS:
break;
case MSG_CLEAR:
break;
}
}
};
public void MakeBuzz() {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
mConnectedGatt = mDevice.connectGatt(getApplicationContext(),
true, mExecutor);
BluetoothGattService alertService = mConnectedGatt
.getService(IMMEDIATE_ALERT_UUID);
int x = getbattery(mConnectedGatt);
Buzz(mConnectedGatt, 2);
}
});
t.start();
}
}
This it the Application class -
package com.example.bluetoothgatt;
import android.app.Application;
import android.content.Intent;
public class ApplicationBleTest extends Application {
// Application variables
public final String SMOKE_TALK_PACKAGE_NAME = "com.smoketalk";
private BluetoothLEService mBleService;
private static int MODE_PRIVATE;
/**
* Application OnCreate event initiate the class parameters
*/
public void onCreate() {
super.onCreate();
getApplicationContext().startService(new Intent(this, BLE.class));
}
}
And this is the main activity (I am trying to make the keyfob alaram buzz on a button click)
package com.example.bluetoothgatt;
import com.example.bluetoothgatt.BluetoothLowEnergyService.BluetoothLeBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
/**
* Created by Dave Smith Double Encore, Inc. MainActivity
*/
public class MainActivity extends Activity {
BluetoothLowEnergyService mBluetoothService;
boolean isBound = false;
Button buzz;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, BluetoothLowEnergyService.class);
bindService(intent, mBleServiceConnection, Context.BIND_AUTO_CREATE);
buzz = (Button) findViewById(R.id.btn1);
buzz.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mBluetoothService.MakeBuzz();
}
});
}
private ServiceConnection mBleServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
BluetoothLeBinder binder = (BluetoothLeBinder) service;
mBluetoothService = binder.getService();
isBound = true;
}
public void onServiceDisconnected(ComponentName arg0) {
isBound = false;
}
};
}
And the menifest file -
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bluetoothgatt"
android:versionCode="1"
android:versionName="1.0" >
<uses-feature
android:name="android.hardware.bluetooth_le"
android:required="true" />
<uses-sdk
android:minSdkVersion="18"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH_PRIVILEGED"/>
<application
android:name="com.example.bluetoothgatt.ApplicationBleTest"
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="SensorTag Weather" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name="com.example.bluetoothgatt.BLE" />
</application>
</manifest>
and last one the layout for the main activity -
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:padding="#dimen/activity_horizontal_margin"
android:text="Android BLE Test"
android:textSize="42sp" />
<Button
android:id="#+id/btn1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/textView1"
android:layout_centerHorizontal="true"
android:layout_marginTop="56dp"
android:text="Buzz" />
</RelativeLayout>
ANY help will be appreciated since I rellay have no clue what goes wrong... =(
For starters, I would recommend commenting out the bond code (Everything after if(device.getBondState().. in the onLeScan method) The whole bonding process was unstable on 4.3 (Nexus devices at least) and became more stable on 4.4.
You should be able to discover devices, and with the BluetoothDevice the user selects you should call ConnectGatt after stopping discovery. This will attempt to connect to the Gatt server on the device. If the connection is successful, you should receive a callback on your connectionStateChange indicating that the connection was successful.
The concept behind bonding is related to pairing with the device and exchanging keys if your characteristics are encrypted. Normally you should be able to connect to the Gatt server without needing to bond, but once you are connected, if you do try to read an encrypted characteristic, it will fail.
I tried your code and it works. you need to follow this process:
BluetoothAdapter.startLeScan(leCallback)
In the onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) in leCallback, call btDevice.connectGatt(Context context, Boolean autoConnect, BluetoothGattCallback gattCallback);
In the onConnectionStateChange(BluetoothGatt gatt, int status, int newState) in gattCallBack, check if newState is BluetoothProfile.STATE_CONNECTED, if yes, call gatt.discoverServices();
In the onServicesDiscovered(BluetoothGatt gatt, int status) in gattCallBack, check if status is BluetoothGatt.GATT_SUCCESS, if yes, get the service by UUID like this: BluetoothGattService service = gatt.getService(YOUR_SERVICE_UUID);
If the service is null, it means the service has not yet been discovered, you need to check again when the next service is discovered and the onServicesDiscovered will be called again.
By the time all the services has been discovered, you should already got your service, unless the device does not support it.
Now you can use your service in your Buzz method.
Also worth noting is that the BLE actions must all be serialized by you. Eg, if you made a read/write to a characteristic you need to wait for the callback before doing another. If not, this will result in an error.
Since you are running from a service you can try running connect on the main thread like this:
public void connectToDevice( String deviceAddress) {
mDeviceAddress = deviceAddress;
final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(mDeviceAddress);
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() {
#Override
public void run() {
if (device != null) {
mGatt = device.connectGatt(getApplicationContext(), true, mGattCallback);
scanLeDevice(false);// will stop after first device detection
}
}
});
}
Hope it helps.

Start Activity with UI updated from notification if service running

I'm making kind-of an audio player. Currently I have a MediaPlayer running in the Activity itself (which I know is bad). There is a SeekBar on the screen which gets updated as the music plays, like so:
private Runnable mUpdateTimeTask = new Runnable() {
public void run()
{
long totalDuration = mp.getDuration();
long currentDuration = mp.getCurrentPosition();
songTotalDurationLabel.setText("" + utils.millisecondsToTimer(totalDuration));
songCurrentDurationLabel.setText("" + utils.millisecondsToTimer(currentDuration));
int progress = (int)(utils.getProgressPercentage(currentDuration, totalDuration));
songProgressBar.setProgress(progress);
if(mp.isPlaying())
mHandler.postDelayed(this, 100);
else
mHandler.removeCallbacks(mUpdateTimeTask);
}
};
Once the user presses the back button or kills it from the recent apps list, the music stops.
Now I want the music to run in the background, so looking around the internet I found to run it in a Service, and calling startService() from Activity. Also I have a notification come up when music is playing and removed when it is paused.
I understand from a service I'll get the music to play even when app gets closed. But what I didn't understand is, if the user taps on the notification given the service is running, the activity restarts with the SeekBar at progress = 0.
How do I get the UI to update the SeekBar to the correct value from the Service after the activity restarts?
Figured it out!
The solution is to get the running services using the ActivityManager and find your service like this
private boolean fooRunning()
{
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for(RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE))
{
if("com.name.packagename.foo".equals(service.service.getClassName()))
{
return true;
}
}
return false;
}
If this method returns true, bind to the service and get the current position from the MediaPlayer object
public void bindToService()
{
if(fooRunning())
{
bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
serviceExists = true;
}
else
serviceExists = false;
}
private ServiceConnection mConnection = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName className, IBinder serviceBinder)
{
bar binder = (bar) serviceBinder;
mService = binder.getService();
if(serviceExists)
{
int getProgress = mService.mp.getCurrentPosition();
// mp is the MediaPlayer object in the service
seekbar.setProgress(getProgress);
}
}
#Override
public void onServiceDisconnected(ComponentName className)
{
}
};
The Service class is like this:
public class foo extends Service
{
private MediaPlayer mp = new MediaPlayer();
private final IBinder mBinder = new bar();
public class bar extends Binder
{
public foo getService()
{
return foo.this;
}
}
#Override
public IBinder onBind(Intent intent)
{
return mBinder;
}
}
Hope this helps someone!

Gibberish coming from ASIO SSL Server code after the first message

I'm trying to write a SSL-based async server using Boost ASIO example code from here.
I get the first message and its response correctly at the client side. Then, I send a second message which is received fine at the server, however when the response is sent to client. It comes as some gibberish.
I have uploaded the server code to pastebin. Also, find it below:
// file - Server.h
class Server
{
public:
explicit Server(const std::string &address,
int port,
std::size_t threadPoolSize);
// run the io_service loop
void run();
// stop the server
void stop();
private:
//handle async accept operation
void handleAccept(const boost::system::error_code &e);
// number of threads in thread pool
std::size_t _threadPoolSize;
// the io_service
boost::asio::io_service _ioService;
// acceptor to listen for incoming connections
boost::asio::ip::tcp::acceptor _acceptor;
std::string get_password()
{
return "password";
}
// ssl context
boost::asio::ssl::context _context;
ConnectionPtr _connection;
};
//////////////////////////////////////////////////////////////////////////
// file - Server.cpp
//////////////////////////////////////////////////////////////////////////
Server::Server(const std::string& address,
int port,
std::size_t threadPoolSize)
: _threadPoolSize(threadPoolSize),
_acceptor(_ioService),
_context(_ioService, boost::asio::ssl::context::sslv23),
_connection()
{
try {
DEBUG_2("Starting server on port: ", port);
boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port);
_acceptor.open(endpoint.protocol());
_acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
_acceptor.bind(endpoint);
_acceptor.listen();
_context.set_options(
boost::asio::ssl::context::default_workarounds
| boost::asio::ssl::context::no_sslv2
| boost::asio::ssl::context::single_dh_use);
_context.set_password_callback(boost::bind(&Server::get_password, this));
_context.use_certificate_chain_file("./demoCA/cacert.pem");
_context.use_private_key_file("./demoCA/private/cakey.pem",
boost::asio::ssl::context::pem);
// _context.use_tmp_dh_file("dh512.pem");
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
catch(std::exception& e)
{
STD_EXCEPTION_MESSAGE;
throw;
}
}
void Server::run()
{
// Create a pool of threads to run all of the io_services.
std::vector<boost::shared_ptr<boost::thread> > threads;
for (std::size_t i = 0; i < _threadPoolSize; ++i)
{
boost::shared_ptr<boost::thread>
thread(new boost::thread(
boost::bind(&boost::asio::io_service::run,
&_ioService)
)
);
threads.push_back(thread);
}
// Wait for all threads in the pool to exit.
for (std::size_t i = 0; i < threads.size(); ++i)
threads[i]->join();
}
void Server::stop()
{
_ioService.stop();
}
void Server::handleAccept(const boost::system::error_code& e)
{
if (!e)
{
_connection->handshake();
_connection.reset(new CclConnection(_ioService, _context));
_acceptor.async_accept(_connection->socket(),
boost::bind(&Server::handleAccept,
this,
boost::asio::placeholders::error));
}
}
////////////////////////////////////////////////////////////
// file - Connection.h
////////////////////////////////////////////////////////////
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
typedef boost::asio::ssl::stream< boost::asio::ip::tcp::socket >
ssl_socket;
class Connection
: public boost::enable_shared_from_this<Connection>
{
public:
explicit Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context);
//get socket from the connection
ssl_socket::lowest_layer_type& socket();
// do an SSL handshake
void handshake();
//get socket from the connection
boost::asio::io_service::strand& strand();
// start first async operation
void start();
void sendResponse(const Response& response);
void close();
// get remote IP address for this connection
std::string getIPAddress();
private:
void handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred);
void handleWrite(const boost::system::error_code& e);
boost::asio::io_service::strand _strand;
ssl_socket _socket;
void handleHandshake(const boost::system::error_code& e);
boost::array<char, 8192> _buffer;
};
typedef boost::shared_ptr<Connection> ConnectionPtr;
///////////////////////////////////////////////////////////////
// File - Connection.cpp
///////////////////////////////////////////////////////////////
Connection::Connection(boost::asio::io_service& io_service,
boost::asio::ssl::context& context)
: _strand(io_service),
_socket(io_service, context)
{
}
ssl_socket::lowest_layer_type& Connection::socket()
{
return _socket.lowest_layer();
}
boost::asio::io_service::strand& Connection::strand()
{
return _strand;
}
void Connection::start()
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
void Connection::handshake()
{
std::cout << "doing ssl handshake" << std::endl;
_socket.async_handshake(boost::asio::ssl::stream_base::server,
_strand.wrap(
boost::bind(
&Connection::handleHandshake,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::handleHandshake(const boost::system::error_code& error)
{
if (!error)
{
_socket.async_read_some(boost::asio::buffer(_buffer),
_strand.wrap(
boost::bind(
&Connection::handleRead,
shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred
)
)
);
}
else
{
std::cout << "error occured: " << error.message();
this->close();
}
}
void Connection::handleRead(const boost::system::error_code& e,
std::size_t bytesTransferred)
{
if (!e) {
// handle read data
this->start();
}
else {
this->close();
}
}
void Connection::handleWrite(const boost::system::error_code& e)
{
if (!e) {
this->start();
}
else {
this->close();
}
}
void Connection::sendResponse(const Response& response)
{
boost::asio::async_write(_socket,
boost::asio::buffer(convertToString(response)),
_strand.wrap(
boost::bind(
&Connection::handleWrite,
shared_from_this(),
boost::asio::placeholders::error
)
)
);
}
void Connection::close()
{
boost::system::error_code ignoredCode;
socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both,
ignoredCode);
}
std::string Connection::getIPAddress()
{
return socket().remote_endpoint().address().to_string();
}
Can someone point me out as to what is being done wrongly here?
Update: The issue is resolved as noted by me in the comment. The issue was exactly similar to another old question on stackoverflow.
Your code doesn't recognize, that boost::asio::buffer is only the wrapper for objects from which it was constructed.
Here (in Connection::sendResponse):
boost::asio::buffer(convertToString(response))
You created buffer out of a (probably) temporary object, which was destroyed before it was used by boost::asio::async_write.
Boost.Asio documentation specifically tells you about that in the paragraph "Buffer invalidation"
For the boost::asio::buffer overloads that accept an argument of type
std::string, the buffer objects returned are invalidated according to
the rules defined for invalidation of references, pointers and
iterators referring to elements of the sequence (C++ Std, 21.3).