Sip Error while registration - java

I am using native methods of sip calling and it is working fine but some time it is giving registration error IN_PROGRESS (Error Code -9 ) .I have search in Sip Error codes but dint find any error code of this kind . Here is my code for sip registration .PLease tell me if any one have idea about this error please tell me .
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.*;
import android.net.sip.*;
import java.text.ParseException;
/**
* Handles all calling, receiving calls, and UI interaction in the WalkieTalkie app.
*/
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
public String sipAddress = null;
public static SipManager manager = null;
public static SipProfile me = null;
public SipAudioCall call = null;
public SipErrorCode sipcode;
public SipException sipexeception;
public static WalkieTalkieActivity walkiy;
public static WalkieTalkieActivity getInstance() {
if (walkiy == null) {
walkiy = new WalkieTalkieActivity();
}
return walkiy;
}
#
Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Log.e("onCreate", "onCreate");
initializeManager(this);
}
#
Override
public void onStart() {
super.onStart();
// When we get back from the preference setting Activity, assume
// settings have changed, and re-login with new auth info.
}
#
Override
public void onDestroy() {
super.onDestroy();
if (call != null) {
call.close();
}
closeLocalProfile();
}
#
Override
protected void onResume() {
initializeManager(this);
super.onResume();
}
public void initializeManager(Context ctx) {
Log.e("inilitize", "initialize manager");
if (manager == null) {
manager = SipManager.newInstance(ctx);
}
initializeLocalProfile(ctx);
}
/**
* Logs you into your SIP provider, registering this device as the location to
* send SIP calls to for your SIP address.
*/
public void initializeLocalProfile(final Context ctx) {
Log.e("inilitize", "initialize profile");
if (manager == null) {
Log.e("inilitize", "return in profile");
updateStatus("we are unable to establish this feature on your device ", ctx);
Log.e("Wifi state", "" + SipManager.isSipWifiOnly(ctx));
return;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
String username = prefs.getString("namePref", "XYZ");
String domain = prefs.getString("domainPref", "236.343.230.2");
String password = prefs.getString("passPref", "XYZ");
try {
Log.e("inilitize", "building profile ");
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword(password);
me = builder.build();
manager.open(me);
Log.e("alredy registered1", "" + manager.isRegistered(me.getUriString()));
try {
if (manager.isRegistered(me.getUriString())) {
Log.e("alredy registered2", "" + manager.isRegistered(me.getUriString()));
updateStatus("Ready", ctx);
return;
}
} catch (SipException e) {
// TODO Auto-generated catch block
closeLocalProfile();
e.printStackTrace();
}
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
Log.e("Sip restration", "Registering with SIP Server..." + me.getUriString());
updateStatus("Registering with SIP Server...", ctx);
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
Log.e("Sip restration", "Ready");
updateStatus("Ready", ctx);
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
Log.e("Error Code Registration ", SipErrorCode.toString(errorCode) + " " + errorCode);
updateStatus(SipErrorCode.toString(errorCode), ctx);
}
});
} catch (ParseException pe) {
updateStatus("Connection Error.", ctx);
} catch (SipException se) {
updateStatus("Connection error.", ctx);
}
}
/**
* Closes out your local profile, freeing associated objects into memory
* and unregistering your device from the server.
*/
public void closeLocalProfile() {
if (manager == null) {
return;
}
try {
if (me != null) {
manager.unregister(me, new SipRegistrationListener() {
#
Override
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
// TODO Auto-generated method stub
Log.e("unregister failed", "unregister failed");
}
#
Override
public void onRegistrationDone(String localProfileUri, long expiryTime) {
// TODO Auto-generated method stub
Log.e("unregister done", "unregister done");
}
#
Override
public void onRegistering(String localProfileUri) {
// TODO Auto-generated method stub
Log.e("unregistering", "unregistering");
}
});
manager.close(me.getUriString());
}
} catch (Exception ee) {
Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
}
}
/**
* Make an outgoing call.
*/
public void initiateCall(String number, final Context ctx, final View v) {
Log.d("Number", "" + number);
sipAddress = number;
Log.e("initiating call", "initiating call");
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {#
Override
public void onCallBusy(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("buzy", "buzy");
super.onCallBusy(call);
}
#
Override
public void onCallHeld(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("held", "held");
super.onCallHeld(call);
}
#
Override
public void onCalling(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("calling", "calling");
super.onCalling(call);
}
#
Override
public void onChanged(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("changed", "changed");
super.onChanged(call);
}
#
Override
public void onError(SipAudioCall call, int errorCode,
String errorMessage) {
// TODO Auto-generated method stub
Log.e("call error", "error" + SipErrorCode.toString(errorCode) + " " + errorCode);
CallingScreen.fa.finish();
super.onError(call, errorCode, errorMessage);
}
#
Override
public void onReadyToCall(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("ready to call", "ready to call ");
super.onReadyToCall(call);
}
#
Override
public void onRinging(SipAudioCall call, SipProfile caller) {
// TODO Auto-generated method stub
Log.e("ringing", "ringing");
super.onRinging(call, caller);
}
#
Override
public void onRingingBack(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("ringing back", "ringing back");
super.onRingingBack(call);
}
// Much of the client's interaction with the SIP Stack will
// happen via listeners. Even making an outgoing call, don't
// forget to set up a listener to set things up once the call is established.
#
Override
public void onCallEstablished(SipAudioCall call) {
Log.e("call established", "call established");
call.startAudio();
updateTime(true, ctx);
}
#
Override
public void onCallEnded(SipAudioCall call) {
Log.e("call ended", "call ended");
updateTime(false, ctx);
CallingScreen.fa.finish();
}
};
Log.e("param 1 ", "" + me.getUriString());
call = manager.makeAudioCall(me.getUriString(), sipAddress + "#216.245.200.2:5060", listener, 30);
} catch (Exception e) {
e.printStackTrace();
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (me != null) {
try {
closeLocalProfile();
} catch (Exception ee) {
ee.printStackTrace();
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
public void updateStatus(final String status, final Context context) {
// Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
generateNotification(context, status);
}
});
}
public void updateTime(final Boolean status, final Context context) {
// Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
if (status) {
CallingScreen.fa.calling_screen_text.setVisibility(View.GONE);
CallingScreen.fa.ch.setVisibility(View.VISIBLE);
CallingScreen.fa.ch.start();
} else {
CallingScreen.fa.ch.stop();
}
}
});
}
public void updateStatus(SipAudioCall call) {
String useName = call.getPeerProfile().getDisplayName();
if (useName == null) {
useName = call.getPeerProfile().getUserName();
}
// updateStatus(useName + "#" + call.getPeerProfile().getSipDomain());
}
public boolean onTouch(View v, MotionEvent event) {
if (call == null) {
return false;
} else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
call.toggleMute();
} else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
call.toggleMute();
}
return false;
}
public void speaker(Boolean state) {
if (call != null)
call.setSpeakerMode(state);
}
public void endcall() {
if (call != null) {
try {
call.endCall();
} catch (SipException se) {
Log.d("WalkieTalkieActivity/onOptionsItemSelected",
"Error ending call.", se);
}
call.close();
}
}
public static void generateNotification(Context context, String message) {
Log.e("inilitize", "generate notification");
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, Splash_screen.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notificationManager.notify(0, notification);
}
}

SIP is a transaction based protocol, this means, every negotiation process is a transaction (e.g. a basic registration process would imply sending a REISTER request and receive 200 OK response). I posted a small example in this response.
IN_PROGRESS error initially indicates that you tried to start a new transaction, in your scenario you're trying to send a REGISTER request, when client is already in another related one.
A quite typical scenario is, in a fast logout/login, trying to register when unregistration process is still running (no 200 OK final response has been received).
Main problem regarding Android's SIP implementation and this error code is that it's used when as generic error when processing a SIP request fails so, previous meaning loses its significance.
Because of previous problem you would need to check logcat to get more information (you should see something like "~~~~~ SipSessionGroup:: processing ") but, best way to handle this, would be working with different listeners provided by the stack.
The stack provides two listeners that can get registration errors: SipRegistrationListener and SipSession.Listener. Both provides onRegistrationFailed callback but, later one, also provides onRegistrationTimeout, that can be quite helpful. Actually, you already used SipRegistrationListener in your code but I don't really get why you say that it should be set after open because open would try to automatically register and, if some error occurs, you won't be notified.
On the other hand, main problem with this listeners is that registration can fail because of several reason (you can check a list of different error responses here) and current implementation only notifies of error codes >= 500 (those are server and global failures) but not others like quite common 406. This is, in my opinion, an important bug in this stack.

Related

“How to fix ‘Registration failed. Please check settings’ error in android with sample demo SIP

I'm using sample demo of
https://github.com/aosp-mirror/platform_development/tree/master/samples/SipDemo
the programing is ok, it doesn´t show issues, but when I configure this, it shows message Registration failed.
I´m programing with android studio, and the server is asterisk.
I tried with soiper and and it works.
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
public String sipAddress = null;
public SipManager manager = null;
public SipProfile me = null;
public SipAudioCall call = null;
public IncomingCallReceiver callReceiver;
private static final int CALL_ADDRESS = 1;
private static final int SET_AUTH_INFO = 2;
private static final int UPDATE_SETTINGS_DIALOG = 3;
private static final int HANG_UP = 4;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_walkie_talkie);
ToggleButton pushToTalkButton = (ToggleButton) findViewById(R.id.pushToTalk);
pushToTalkButton.setOnTouchListener(this);
// Set up the intent filter. This will be used to fire an
// IncomingCallReceiver when someone calls the SIP address used by this
// application.
IntentFilter filter = new IntentFilter();
filter.addAction("android.SipDemo.INCOMING_CALL");
callReceiver = new IncomingCallReceiver();
this.registerReceiver(callReceiver, filter);
// "Push to talk" can be a serious pain when the screen keeps turning off.
// Let's prevent that.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
initializeManager();
}
#Override
public void onStart() {
super.onStart();
// When we get back from the preference setting Activity, assume
// settings have changed, and re-login with new auth info.
initializeManager();
}
#Override
public void onDestroy() {
super.onDestroy();
if (call != null) {
call.close();
}
closeLocalProfile();
if (callReceiver != null) {
this.unregisterReceiver(callReceiver);
}
}
public void initializeManager() {
if(manager == null) {
manager = SipManager.newInstance(this);
}
initializeLocalProfile();
}
/**
* Logs you into your SIP provider, registering this device as the location to
* send SIP calls to for your SIP address.
*/
public void initializeLocalProfile() {
if (manager == null) {
return;
}
if (me != null) {
closeLocalProfile();
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
/* String username = prefs.getString("namePref", "");
String domain = prefs.getString("domainPref", "");
String password = prefs.getString("passPref", ""); */
String username = "12";
String domain = "192.168.1.37";
String password = "1234";
if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
showDialog(UPDATE_SETTINGS_DIALOG);
return;
}
try {
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setAuthUserName("12");
builder.setDisplayName("12");
builder.setProfileName("12");
builder.setPassword(password);
me = builder.build();
Intent i = new Intent();
i.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
manager.open(me, pi, null);
// This listener must be added AFTER manager.open is called,
// Otherwise the methods aren't guaranteed to fire.
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
updateStatus("Registering with SIP Server...");
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
updateStatus("Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
updateStatus("Registration failed. Please check settings.");
}
});
} catch (ParseException pe) {
updateStatus("Connection Error.");
} catch (SipException se) {
updateStatus("Connection error.");
}
}
/**
* Closes out your local profile, freeing associated objects into memory
* and unregistering your device from the server.
*/
public void closeLocalProfile() {
if (manager == null) {
return;
}
try {
if (me != null) {
manager.close(me.getUriString());
}
} catch (Exception ee) {
// Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
}
}
/**
* Make an outgoing call.
*/
public void initiateCall() {
updateStatus(sipAddress);
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
// Much of the client's interaction with the SIP Stack will
// happen via listeners. Even making an outgoing call, don't
// forget to set up a listener to set things up once the call is established.
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
updateStatus(call);
}
#Override
public void onCallEnded(SipAudioCall call) {
updateStatus("Ready.");
}
};
call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
}
catch (Exception e) {
// Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (me != null) {
try {
manager.close(me.getUriString());
} catch (Exception ee) {
// Log.i("WalkieTalkieActivity/InitiateCall",
// "Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
/**
* Updates the status box at the top of the UI with a messege of your choice.
* #param status The String to display in the status box.
*/
public void updateStatus(final String status) {
// Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
TextView labelView = (TextView) findViewById(R.id.sipLabel);
labelView.setText(status);
}
});
}
/**
* Updates the status box with the SIP address of the current call.
* #param call The current, active call.
*/
public void updateStatus(SipAudioCall call) {
String useName = call.getPeerProfile().getDisplayName();
if(useName == null) {
useName = call.getPeerProfile().getUserName();
}
updateStatus(useName + "#" + call.getPeerProfile().getSipDomain());
}
/**
* Updates whether or not the user's voice is muted, depending on whether the button is pressed.
* #param v The View where the touch event is being fired.
* #param event The motion to act on.
* #return boolean Returns false to indicate that the parent view should handle the touch event
* as it normally would.
*/
public boolean onTouch(View v, MotionEvent event) {
if (call == null) {
return false;
} else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
call.toggleMute();
} else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
call.toggleMute();
}
return false;
}
public boolean onCreateOptionsMenu(Menu menu) {
menu.add(0, CALL_ADDRESS, 0, "Call someone");
menu.add(0, SET_AUTH_INFO, 0, "Edit your SIP Info.");
menu.add(0, HANG_UP, 0, "End Current Call.");
return true;
}
}
Think that should be user#domain ...and an IP address is not a domain.

Sunmi V1s device - Java callback doesn't work when the printer is done printing

I'm using Sunmi V1s device and want to show a Dialog once the printer finished printing the whole receipt. I now can get a message once the query is done processing, but I cannot get the message the exact moment when the printer is done the whole printing.
I used demo app to create a Callback which I then send to an AidlUtil class.
TextActivity
final PrinterCallback printerCallback = new PrinterCallback() {
#Override
public void onReturnString(String result) {
System.out.println("Finished: " + result); //never prints out, expecting this line to work when Sunmi printer finishes printing
}
#Override
public void onRunResult(boolean success) {
System.out.println("Success: " + success); //prints out immediately after query is sent
}
#Override
public void onRaiseException(String msg) {
}
};
AidlUtil.getInstance().printText(content, size, isBold, isUnderLine, printerCallback);
AidlUtil class:
public void printText(String content, float size, boolean isBold, boolean isUnderLine, PrinterCallback printerCallback) {
if (woyouService == null) {
Toast.makeText(context, R.string.toast_2, Toast.LENGTH_LONG).show();
return;
}
try {
if (isBold) {
woyouService.sendRAWData(ESCUtil.boldOn(), null);
} else {
woyouService.sendRAWData(ESCUtil.boldOff(), null);
}
if (isUnderLine) {
woyouService.sendRAWData(ESCUtil.underlineWithOneDotWidthOn(), null);
} else {
woyouService.sendRAWData(ESCUtil.underlineOff(), null);
}
woyouService.printTextWithFont(content, null, size, generateCB(printerCallback)); //generating ICallback and sending it to printTextWithFont method
woyouService.lineWrap(3, null);
} catch (RemoteException e) {
e.printStackTrace();
}
}
generateCB method:
public ICallback generateCB(final PrinterCallback printerCallback){
return new ICallback.Stub(){
#Override
public void onRunResult(boolean isSuccess) throws RemoteException {
printerCallback.onRunResult(isSuccess);
}
#Override
public void onReturnString(String result) throws RemoteException {
printerCallback.onReturnString(result);
}
#Override
public void onRaiseException(int code, String msg) throws RemoteException {
printerCallback.onRaiseException(msg);
}
#Override
public void onPrintResult(int code, String msg) throws RemoteException {
}
};
}
What can be an issue? I expect to get a System.out.println onReturnString method, but the method is not called anytime

How to send (from Native code) a android.content.Context parameter to a Java fct (via JNI)

I am developping an application for my android phone, and I am trying to enable the Wifi hotspot.
I am using Qt 5.4.1 so I developp in C++.
As there is not any function to do this in the NDK, I am using JNI to call Java Methods.
My java code is (thanks to Ashish Sahu's answer in stackoverflow thread) :
package org.app.test;
import android.content.*;
import android.net.wifi.*;
import java.lang.reflect.*;
//Class that handles Wifi Hotspot (access point) configuration
public class ApManager {
//Is Wifi hotspot on or off ?
public static boolean isApOn(Context context) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
try {
Method method = wifimanager.getClass().getDeclaredMethod("isWifiApEnabled");
method.setAccessible(true);
return (Boolean) method.invoke(wifimanager);
}
catch (Throwable ignored) {}
return false;
}
//Turn Wifi hotspot on or off
public static boolean configApState(Context context, boolean b) {
WifiManager wifimanager = (WifiManager) context.getSystemService(context.WIFI_SERVICE);
WifiConfiguration wificonfiguration = null;
try {
//if Wifi is on, turn it off
if(isApOn(context)) {
wifimanager.setWifiEnabled(false);
}
Method method = wifimanager.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
method.invoke(wifimanager, wificonfiguration, b);
return true;
}
catch(Exception e) {
e.printStackTrace();
}
return false;
}
}
C++ code sample :
setWifiApEnabled(QAndroidJniObject context, bool b)
{
return QAndroidJniObject::callStaticMethod<jboolean>("org/app/test/ApManager"
, "configApState"
, "(Ljava/lang/Object;Z)Z" //Or (Landroid/content/Context;Z)Z ???
, context.object<jobject>()
, b);
}
But now I have a problem ; how to get the parameter context to pass to the function setWifiApEnabled(context, b) when I call it ?
I am a little lost, I read some threads about this problem (like this one) but I do not totally understand what the people who answered meant.
Could you help me with this ?
EDIT : I found on this stackoverflow thread a way to get the context :
interface = QApplication::platformNativeInterface();
activiti = (jobject)interface->nativeResourceForIntegration("QtActivity");
at = new QAndroidJniObject(activiti);
appctx = at->callObjectMethod("getApplicationContext", "()Landroid/content/Context;");
if(appctx.isValid()) qDebug() << "I am valid !";
else qDebug() << "I ain't valid !";
appctx is valid, but the Wifi hotspot doesn't get enabled and I cannot get its state.
EDIT 2 : : I successfully managed to enable the Wifi hotspot in java, using Android Studio. The code is the following :
WifiApManager.java :
public class WifiApManager {
private WifiManager wifiMan;
protected Method setWifiApEnabledMethod, isWifiApEnabledMethod;
protected final static int MAX_ITER = 10;
public WifiApManager(WifiManager wifiMan) {
this.wifiMan = wifiMan;
getHiddenMethods();
}
private void getHiddenMethods() {
try {
setWifiApEnabledMethod = wifiMan.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
isWifiApEnabledMethod = wifiMan.getClass().getMethod("isWifiApEnabled");
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
public boolean isWifiApEnabled() {
try {
return (Boolean)isWifiApEnabledMethod.invoke(wifiMan);
} catch (Exception e) {
return false;
}
}
public boolean isWifiEnabled() {
return wifiMan.isWifiEnabled();
}
public boolean setWifiApEnabled(WifiConfiguration conf, boolean enabled) {
try {
return (Boolean) setWifiApEnabledMethod.invoke(wifiMan, conf, true);
} catch (Exception e) {
return false;
}
}
public boolean toggleWifi(String ssid) {
// WifiConfiguration creation:
WifiConfiguration conf = new WifiConfiguration();
conf.SSID = ssid;
conf.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
// If AP Wifi is enabled, disables it and returns:
if(isWifiApEnabled()) {
//setWifiApEnabled(null, false); Won't work, see two further lines
wifiMan.setWifiEnabled(true);
wifiMan.setWifiEnabled(false);
int maxIter = MAX_ITER;
while (isWifiApEnabled() && maxIter-- >= 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
return isWifiApEnabled();
}
// If standard Wifi is enabled, disables it:
if (isWifiEnabled()) {
if (wifiMan.setWifiEnabled(false)) {
int maxIter = MAX_ITER;
while (wifiMan.isWifiEnabled() && maxIter-- >= 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
}
if (isWifiEnabled()) {
return false;
}
}
// Enables AP Wifi
try {
if (! setWifiApEnabled(conf, true)) {
System.out.println("setWifiApEnabledMethod failed.");
return false;
}
int maxIter = MAX_ITER;
while (! isWifiApEnabled() && maxIter-- > 0) {
try {Thread.sleep(500);} catch (Exception e) {}
}
} catch(Exception e) {
e.printStackTrace();
return false;
}
return true;
}
}
Main class :
public class AndroidMenusActivity extends Activity implements OnClickListener {
private WifiApManager wifiMan;
private ToggleButton wifiButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wifiMan = new WifiApManager((WifiManager) this.getSystemService(Context.WIFI_SERVICE));
setContentView(R.layout.activity_android_menus);
makeUI();
}
private void makeUI() {
LinearLayout subLayout = (LinearLayout) findViewById(R.id.subLayout);
wifiButton = new ToggleButton(this);
wifiButton.setTextOn("Disable Wifi");
wifiButton.setTextOff("Enable AP Wifi");
wifiButton.setChecked(wifiMan.isWifiApEnabled());
wifiButton.setOnClickListener(this);
subLayout.addView(wifiButton);
}
#Override
public void onClick(View sender) {
if (!wifiButton.equals(sender))
return;
AsyncTask<Object, Void, Boolean> task = new AsyncTask<Object, Void, Boolean>() {
private ToggleButton bt;
private WifiApManager wm;
#Override
protected Boolean doInBackground(Object... args) {
bt = (ToggleButton) args[0];
wm = (WifiApManager) args[1];
return wm.toggleWifi("test.com");
}
#Override
protected void onPostExecute (Boolean result) {
bt.setChecked(result.booleanValue());
bt.setEnabled(true);
}
};
wifiButton.setEnabled(false);
task.execute(wifiButton, wifiMan);
}
}
But I cannot find a way to do the same in C++, any help ?
Just in order to transfer context object from C++ to JNI, use auto-injection like that:
QtAndroid::androidActivity().callStaticMethod<void>(
"com/company/project/MyApp",
"myFunc", // method name
"(Landroid/content/Context;)V" // auto-injection
);

Android voice recognition and send data via bluetooth to Arduino. How can I send data several times?

I am a newbie of Android. My application uses Voice Recognition, TextToSpeech and send data out via Bluetooth from Android phone (SAMSUNG Galaxy Note | OS: Android 4.1.2) to Arduino. It can send data out only once a time and after it can't send (it through IOException), so application finish(). Below is my code.
Android Code
package com.itcdroid.smarthome;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Locale;
import java.util.UUID;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.speech.tts.TextToSpeech;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends Activity implements
TextToSpeech.OnInitListener {
//Tag for logging
private static final String TAG = "ITCDroid";
private static final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothSocket mBluetoothSocket = null;
private OutputStream outStream = null;
//MAC address of remote Bluetooth device
private final String address = "98:D3:31:B4:34:EE";
// UUID that specifies a protocol for generic bluetooth serial communication
//Well known SPP UUID
private static final UUID MY_UUID =
UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
private TextToSpeech tts;
private String ttsText;
private TextView txtSpeechInput;
private ImageButton btnSpeak;
private final int REQ_CODE_SPEECH_INPUT = 100;
// Available commands
private static final String[] commands = {"on", "off", "turn on the light", "turn off the light"};
boolean foundCommand;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
checkBtState();
tts = new TextToSpeech(this, this);
txtSpeechInput = (TextView) findViewById(R.id.txtSpeechInput);
btnSpeak = (ImageButton) findViewById(R.id.btnSpeak);
// hide the action bar
//getActionBar().hide();
//mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
//checkBtState();
btnSpeak.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
promptSpeechInput();
}
});
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, "...In onResume - Attempting client connect...");
//Set up a pointer to the remote node using it's address.
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. in this case we are using the UUID for SPP
try {
mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
mBluetoothAdapter.cancelDiscovery();
// Establish the connection. This will block until is connects.
Log.d(TAG, "...Connecting to Remote...");
try {
mBluetoothSocket.connect();
Log.d(TAG, "...Connection established and data link opened...");
} catch(IOException e) {
try {
mBluetoothSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
}
}
//Create a data stream so we can talk to server.
Log.d(TAG, "...Creating Socket...");
try {
outStream = mBluetoothSocket.getOutputStream();
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
}
}
#Override
public void onPause(){
super.onPause();
Log.d(TAG, "...In onPause()...");
if (outStream != null) {
try {
outStream.flush();
} catch (IOException e) {
errorExit("Fatal Error", "In onPause() and failed to flush output stream: " + e.getMessage() + ".");
}
}
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mBluetoothSocket.close();
} catch (IOException e) { }
}
private void checkBtState() {
// TODO Auto-generated method stub
//Check for Bluetooth support and then check to make sure it is turned on
if (mBluetoothAdapter == null) {
errorExit("Fatal Error", "Bluetooth Not supported. Aborting.");
} else {
if (mBluetoothAdapter.isEnabled()) {
Log.d(TAG, "...Bluetooth is enabled...");
} else {
//Prompt user to turn on Bluetooth
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
}
/**
* Showing google speech input dialog
* */
private void promptSpeechInput() {
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault());
intent.putExtra(RecognizerIntent.EXTRA_PROMPT,
getString(R.string.speech_prompt));
try {
startActivityForResult(intent, REQ_CODE_SPEECH_INPUT);
} catch (ActivityNotFoundException a) {
Toast.makeText(getApplicationContext(),
getString(R.string.speech_not_supported),
Toast.LENGTH_SHORT).show();
}
}
/**
* Receiving speech input
* */
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQ_CODE_SPEECH_INPUT: {
if (resultCode == RESULT_OK && null != data) {
ArrayList<String> result = data
.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
foundCommand = false;
for(String command : commands) {
if(result.contains(command)) {
foundCommand = true;
if(command == "on") {
txtSpeechInput.setText("You say -on-");
ttsText = "The light is turn on now.";
speakOut();
sentData("1");
}
else if(command == "off") {
txtSpeechInput.setText("You say -off-");
ttsText = "The light is turn off now.";
speakOut();
sentData("2");
}
else if(command == "turn on the light") {
txtSpeechInput.setText("You say -turn on the light-");
ttsText = "The light is turn on now.";
speakOut();
sentData("1");
}
else if(command == "turn off the light") {
txtSpeechInput.setText("You say -turn off the light-");
ttsText = "The light is turn off now.";
speakOut();
sentData("2");
}
}
}
if (!foundCommand) {
txtSpeechInput.setText("Unknown what you say");
ttsText = "I don't know what you want!";
speakOut();
}
//txtSpeechInput.setText(result.get(0));
}
break;
}
}
}
#Override
public void onDestroy() {
// Don't forget to shutdown!
if (tts != null) {
tts.stop();
tts.shutdown();
}
super.onDestroy();
}
#Override
public void onInit(int status) {
// TODO Auto-generated method stub
if (status == TextToSpeech.SUCCESS) {
int result = tts.setLanguage(Locale.US);
// tts.setPitch(5); // set pitch level
// tts.setSpeechRate(2); // set speech speed rate
if (result == TextToSpeech.LANG_MISSING_DATA
|| result == TextToSpeech.LANG_NOT_SUPPORTED) {
Log.e("TTS", "Language is not supported");
} else {
//btnSpeak.setEnabled(true);
speakOut();
}
} else {
Log.e("TTS", "Initilization Failed");
}
}
//#SuppressWarnings("deprecation")
private void speakOut() {
String text = ttsText;
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
}
private void sentData(String message) {
// TODO Auto-generated method stub
byte[] msgBuffer = message.getBytes();
Log.d(TAG, "...Sending data: " + message + "...");
try {
outStream.write(msgBuffer);
outStream.close();
reConnectBT();
} catch (IOException e) {
String msg = "In onResume() and an exception occurred during write:" + e.getMessage();
msg = msg + ".\n\nCheck that the SPP UUID: " + MY_UUID.toString() + "exists on server.\n\n";
errorExit("sentData IOException", msg);
}
}
private void reConnectBT() {
// TODO Auto-generated method stub
Log.d(TAG, "...In reConnectBT - Attempting client connect...");
//Set up a pointer to the remote node using it's address.
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
// Two things are needed to make a connection:
// A MAC address, which we got above.
// A Service ID or UUID. in this case we are using the UUID for SPP
try {
mBluetoothSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and socket create failed: " + e.getMessage() + ".");
}
// Discovery is resource intensive. Make sure it isn't going on
// when you attempt to connect and pass your message.
mBluetoothAdapter.cancelDiscovery();
// Establish the connection. This will block until is connects.
Log.d(TAG, "...Connecting to Remote...");
try {
mBluetoothSocket.connect();
Log.d(TAG, "...Connection established and data link opened...");
} catch(IOException e) {
try {
mBluetoothSocket.close();
} catch (IOException e2) {
errorExit("Fatal Error", "In onResume() and unable to close socket during connection failture" + e2.getMessage() + ".");
}
}
//Create a data stream so we can talk to server.
Log.d(TAG, "...Creating Socket...");
try {
outStream = mBluetoothSocket.getOutputStream();
} catch (IOException e) {
errorExit("Fatal Error", "In onResume() and output stream creation failture: " + e.getMessage() + ".");
}
}
private void errorExit(String title, String message) {
// TODO Auto-generated method stub
Toast msg= Toast.makeText(getBaseContext(),
title, Toast.LENGTH_SHORT);
msg.show();
finish();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
It seems that you're doing a lot of juggling with connecting and disconnecting from your bluetooth device, which can harm your performance. Another thing you're doing is managing all of the heavy Bluetooth processes directly in your UI thread, which will make your app lock up until the connections complete.
Here's a link to my project's repository, I'm doing simple Bluetooth connections in it and made a BluetoothConnection class as a wrapper for managing the connection state. Feel free to use the source code, but be wary that I'm always actively changing it. If you choose to use it your code, the implementation would go something like this:
InputStream mInputStream;
OutputStream mOutputStream;
BluetoothConnection mConnection = new BluetoothConnection("Connection Name", "98:D3:31:B4:34:EE");
mConnection.setOnConnectStatusChangedListener(this, new onConnectStatusChangedListener() {
#Override
public void onConnect() {
/*
* Connecting to bluetooth takes some time, it won't be ready immediately.
* Set some actions here that let your program know that the connection
* finished successfully. For example,
*/
mInputStream = mConnection.getInputStream();
mOutputStream = mConnection.getOutputStream();
//Use some method of your own to write data
sendDataToBluetoothDevice(mOutputStream);
}
#Override
public void onDisconnect() {
/*
* Same thing applies to disconnecting, set some actions to occur
* when the disconnect is confirmed.
*/
}
}
/*
* Internally, this launches an AsyncTask to handle connecting,
* which is why we need the onConnectStatusChangedListener
* callbacks.
*/
mConnection.connect();
//To disconnect:
mConnection.disconnect();
This should simplify things for you by handling all of the heavy lifting in background processes. As far as reading and writing more than once, as long as you use the InputStream and OutputStream correctly you should be golden.

Trying to circumvent NetworkOnMainThreadException on AsyncTask because of ProgressDialog

I have the following problem. I am using the DropBox SDK to upload a file to dropbox which works fine. When the file is being uploaded (inside an AsyncTask) a ProgressDialog is being shown with a cancel button, still fine here. What is not working fine is, when the cancel button gets pressed a NetworkOnMainThreadException is being raised. I am new to Android programming but I am suspecting it has something to do with the ProgressDialog which is in the constructor. Since it is not in the "doInBackground" part.
Tried to fix it with implementing the OnDismissListener and doing the abortion onDismiss but still no luck. I am getting the error when "mRequest.abort()" is called.
Thanks in advance for any answers!
So here is my code
public class DropBoxUpload extends AsyncTask<Void, Long, Boolean> implements OnDismissListener {
private DropboxAPI<?> mApi;
private String mPath;
private File mFile;
private long mFileLen;
private UploadRequest mRequest;
private Context mContext;
private final ProgressDialog mDialog;
private String mErrorMsg;
public DropBoxUpload(Context context, DropboxAPI<?> api, String dropboxPath, File file) {
// We set the context this way so we don't accidentally leak activities
mContext = context.getApplicationContext();
mFileLen = file.length();
mApi = api;
mPath = dropboxPath;
mFile = file;
mDialog = new ProgressDialog(context);
mDialog.setMax(100);
mDialog.setMessage("Uploading " + file.getName());
mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
mDialog.setProgress(0);
mDialog.setButton("Cancel", new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// This will cancel the putFile operation
mDialog.dismiss();
}
});
mDialog.setCancelable(true);
mDialog.setOnDismissListener(this);
mDialog.show();
}
#Override
protected Boolean doInBackground(Void... params) {
try {
// By creating a request, we get a handle to the putFile operation,
// so we can cancel it later if we want to
FileInputStream fis = new FileInputStream(mFile);
String path = mPath + mFile.getName();
mRequest = mApi.putFileOverwriteRequest(path, fis, mFile.length(),
new ProgressListener() {
#Override
public long progressInterval() {
// Update the progress bar every half-second or so
return 500;
}
#Override
public void onProgress(long bytes, long total) {
publishProgress(bytes);
}
});
if (mRequest != null) {
mRequest.upload();
return true;
}
} catch (DropboxUnlinkedException e) {
// This session wasn't authenticated properly or user unlinked
mErrorMsg = "This app wasn't authenticated properly.";
} catch (DropboxFileSizeException e) {
// File size too big to upload via the API
mErrorMsg = "This file is too big to upload";
} catch (DropboxPartialFileException e) {
// We canceled the operation
mErrorMsg = "Upload canceled";
} catch (DropboxServerException e) {
// Server-side exception. These are examples of what could happen,
// but we don't do anything special with them here.
if (e.error == DropboxServerException._401_UNAUTHORIZED) {
// Unauthorized, so we should unlink them. You may want to
// automatically log the user out in this case.
} else if (e.error == DropboxServerException._403_FORBIDDEN) {
// Not allowed to access this
} else if (e.error == DropboxServerException._404_NOT_FOUND) {
// path not found (or if it was the thumbnail, can't be
// thumbnailed)
} else if (e.error == DropboxServerException._507_INSUFFICIENT_STORAGE) {
// user is over quota
} else {
// Something else
}
// This gets the Dropbox error, translated into the user's language
mErrorMsg = e.body.userError;
if (mErrorMsg == null) {
mErrorMsg = e.body.error;
}
} catch (DropboxIOException e) {
// Happens all the time, probably want to retry automatically.
mErrorMsg = "Network error. Try again.";
} catch (DropboxParseException e) {
// Probably due to Dropbox server restarting, should retry
mErrorMsg = "Dropbox error. Try again.";
} catch (DropboxException e) {
// Unknown error
mErrorMsg = "Unknown error. Try again.";
} catch (FileNotFoundException e) {
}
return false;
}
#Override
protected void onProgressUpdate(Long... progress) {
int percent = (int)(100.0*(double)progress[0]/mFileLen + 0.5);
mDialog.setProgress(percent);
}
#Override
protected void onPostExecute(Boolean result) {
mDialog.dismiss();
}
#Override
public void onDismiss(DialogInterface arg0) {
// TODO Auto-generated method stub
mRequest.abort();
}
}
You cannot access the mRequest object from the main UI thread as this is what is responsible for the network operation. That is why you get a NetworkOnMainThreadException when you call mRequest.abort().
You should modify your code such that you use AsyncTask.cancel on dialog dismissal and check for isCancelled periodically in your doInBackground and call mRequest.abort() when the task is cancelled.
you should call the cancel method to stop your uploading process.
ast.cancel(true);
where ast is your asynctask object

Categories

Resources