Notify thread from receiver - java

This is my main thread:
Thread t = new Thread(){
#Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0; i < passes.length; i++){
progPass.setProgress(i);
WifiConfiguration wc = new WifiConfiguration();
wc.SSID = "\"" + dbw.getSsid() + "\"";
wc.preSharedKey = "\"" + passes[i] + "\"";
wc.status = WifiConfiguration.Status.ENABLED;
wc = configureCapabs(wc, dbw.getCapability());
int res = wifi.addNetwork(wc);
//Toast.makeText(this, "add Network returned " + res , Toast.LENGTH_SHORT).show();
boolean b = wifi.enableNetwork(res, true);
//Toast.makeText(this, "enableNetwork returned " + b , Toast.LENGTH_SHORT).show();
if(!b) continue;
try {
synchronized(this){
this.wait();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean fin = wifi.getConnectionInfo() != null;
if(fin) break;
}
progPass.dismiss();
this.interrupt();
}
};
It checks if wifi uses one of more common passwords. When the on the wait line it waits for notification from broadcast receiver, here is its code:
public class ConnectivityActionReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
if(intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
if(networkInfo.isConnected()) {
// Wifi is connected
Toast.makeText(context, "Wifi is connected: " + String.valueOf(networkInfo), Toast.LENGTH_SHORT).show();
synchronized(this){
notifyAll();
}
}
} else if(intent.getAction().equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
NetworkInfo networkInfo = intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
if(networkInfo.getType() == ConnectivityManager.TYPE_WIFI && ! networkInfo.isConnected()) {
// Wifi is disconnected
Toast.makeText(context, "Wifi is disconnected: " + String.valueOf(networkInfo), Toast.LENGTH_SHORT).show();
}
} else if (intent.getAction().equals(WifiManager.SUPPLICANT_STATE_CHANGED_ACTION)){
int esr = intent.getIntExtra(WifiManager.EXTRA_SUPPLICANT_ERROR, 0);
if(esr != 0){
Toast.makeText(context, Integer.toString(esr), Toast.LENGTH_LONG).show();
synchronized(this){
notifyAll();
}
}
}
}
Here it is registered Manifest:
<receiver
android:name="ConnectivityActionReceiver"
android:enabled="true"
android:label="ConnectivityActionReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
<action android:name="android.net.wifi.STATE_CHANGE" />
<action android:name="android.net.wifi.supplicant.STATE_CHANGE" />
</intent-filter>
</receiver>
It has an instance in the same class as the thread:
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
IntentFilter filter = new IntentFilter();
this.registerReceiver(car, filter);
}
The toast that should appear in onReceive method shows up, meaning that messages are received, but the notification doesn't reach the thread, which means it's stuck in waiting.

You're using two different objects for synchronization! One is the thread object, one is the ConnectivityActionReceiver. When you're using this:
synchronized(this){
this.wait();
}
you're locking on the current instance, hence you are locking on different instances in your case.
The solution is to call wait/notify on a common, globally visible object:
final Object signal = new Object();
// in the waiting thread
synchronized(signal) {
signal.wait();
}
// in the signaling thread
synchronized(signal) {
signal.notifyAll();
}

Related

Same serial port code is functioning differently in different activites

So I'm writing an app that reads reads in data from the serial port. This data is coming in from an arduino which is connected to a force transducer - essentially, the app is meant to measure the weight of something. I found serial port code here: https://www.allaboutcircuits.com/projects/communicate-with-your-arduino-through-android/, and I'm using it in multiple different activities (since I need an activity for calibration, an activity for the actual measuring, etc.). My problem is that the same exact serial port code is working in one activity and is not working in another. It works in this activity, for example:
public class EnterDataActivity extends AppCompatActivity {
private static final long TIMER_DELAY = 5000;
private static final long TIMER_LENGTH = 15000;
EditText enterMax, enterMin;
Button submitMax, submitMin, continueButton;
Chronometer emptyBagTimer;
boolean firstMeasure, getEmptyBagData, canEnterMax, canEnterMin;
ArrayList<String> emptyBagData;
float maxLoad, minLoad;
// serial port variables:
public final String ACTION_USB_PERMISSION = "com.example.jake.USB_PERMISSION";
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serialPort;
UsbDeviceConnection connection;
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
#Override
public void onReceivedData(byte[] arg0) {
String data;
try {
data = new String(arg0, "UTF-8");
if(getEmptyBagData)
emptyBagData.add(data);
} catch (UnsupportedEncodingException e) {}
}
};
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
serialPort.setBaudRate(9600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
start();
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
stop();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_enter_data);
usbManager = (UsbManager) getSystemService(USB_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);
enterMax = (EditText) findViewById(R.id.enterMax);
enterMin = (EditText) findViewById(R.id.enterMin);
submitMax = (Button) findViewById(R.id.submitMax);
submitMin = (Button) findViewById(R.id.submitMin);
continueButton = (Button) findViewById(R.id.continueButton);
emptyBagTimer = (Chronometer) findViewById(R.id.emptyBagTimer);
firstMeasure = true;
getEmptyBagData = false;
canEnterMax = true;
canEnterMin = true;
emptyBagData = new ArrayList<>();
start();
}
// method: measureEmptyBag
// description: this method is called when the button to measure the mass of the empty bag is
// pressed. It starts the chronometer and serial port, first waiting TIMER_DELAY milliseconds
// from the button press, then sets a boolean to true that causes the serial data to be added to
// an arraylist over the next TIMER_LENGTH milliseconds. It then sets the next views in the
// enter data process to visible. The firstMeasure boolean is to prevent spamming.
public void measureEmptyBag(View view){
if(firstMeasure) {
firstMeasure = false;
start();
emptyBagTimer.setBase(SystemClock.elapsedRealtime());
emptyBagTimer.start();
emptyBagTimer.setFormat("Waiting - %s");
emptyBagTimer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
#Override
public void onChronometerTick(Chronometer chronometer) {
if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() <= TIMER_DELAY)
emptyBagTimer.setFormat("Waiting - %s");
else if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() <= TIMER_DELAY + TIMER_LENGTH) {
emptyBagTimer.setFormat("Calculating - %s");
getEmptyBagData = true;
}
else if (SystemClock.elapsedRealtime() - emptyBagTimer.getBase() > TIMER_DELAY + TIMER_LENGTH) {
getEmptyBagData = false;
emptyBagTimer.stop();
enterMax.setVisibility(View.VISIBLE);
submitMax.setVisibility(View.VISIBLE);
}
else
emptyBagTimer.setFormat("Waiting - %s");
}
});
}
}
// method: setMaxLoad
// description: called when the submit button is pressed for the max load, this method trys to
// pull the max load value from it edit text and store it. If that is successful (the user has
// entered in a number) then it sets the next views in the enter data process to visible.
public void setMaxLoad(View view){
if(canEnterMax){
try {
canEnterMax = false;
maxLoad = Float.parseFloat(enterMax.getText().toString());
enterMin.setVisibility(View.VISIBLE);
submitMin.setVisibility(View.VISIBLE);
} catch (Exception e) {} // in case the user enters a non number
}
}
// method: setMinLoad
// description: called when the submit button is pressed for the min load, this method trys to
// pull the min load value from its edit text and store it. If that is successful (the user has
// entered in a number) then it sets the next view in the enter data process to visible.
public void setMinLoad(View view){
if(canEnterMin){
try {
canEnterMin = false;
minLoad = Float.parseFloat(enterMin.getText().toString());
continueButton.setVisibility(View.VISIBLE);
} catch (Exception e) {} // in case the user enters a non number
}
}
// method: continuePressed
// description: this method is called when the continue button is pressed. It averages all of the
// data read in over the measure empty mass period to find the mass when empty, then writes that
// value along with maxLoad and minLoad to a file for later use. Finally it starts the pump
// activity
public void continuePressed(View view){
int emptyMassSum = 0;
int emptyMass;
// cleaning up emptyBagData to only include 3,2, or 1 digit numbers (the serial output gets
// wonky sometimes and spits out weird numbers that would throw off the calculations below,
// so those numbers need to be removed)
for (int i = emptyBagData.size() - 1; i >= 0; i--)
if (emptyBagData.get(i).length() != 3)
emptyBagData.remove(i);
// add up all the values in emptyBagData (try catch in case a non-number was read in)
for (int i = emptyBagData.size() - 1; i >= 0; i--) {
try {
emptyMassSum += Integer.parseInt(emptyBagData.get(i));
} catch (Exception e) {
emptyBagData.remove(i);
}
}
emptyMass = emptyMassSum / emptyBagData.size();
FileOutputStream outputStream;
String dataOut = "E" + emptyMass + "Mx" + maxLoad + "Mn" + minLoad + ";";
try {
outputStream = openFileOutput("BagData.txt", Context.MODE_PRIVATE);
outputStream.write(dataOut.getBytes());
outputStream.close();
} catch (Exception e) {
continueButton.setText(R.string.file_write_error_message);
}
Intent intent = new Intent(this, PumpActivity.class);
startActivity(intent);
}
// serial port methods:
public void start() {
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 10755 || deviceVID == 9025)//Arduino Vendor ID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
}
public void stop() {
if(serialPort!=null)
serialPort.close();
}
}
By "it works", I mean that I can get the data coming in from the serial port and use it. However, the same code does not work here:
public class PumpActivity extends AppCompatActivity {
File calibrationData, bagData;
int mass1, mass2, read1, read2, emptyMassNum;
float maxLoad, minLoad;
double slope, currentMassVal, emptyMass;
boolean status, runTimer;
TextView statusTextView, currentMassTextView;
Button stop;
Thread updateMass;
ArrayList<String> inData;
// this does two things when the handleMessage method is called:
// 1) it takes the most recent data read in and calculates the current mass from it, then updates
// the current mass text view to reflect that
// 2) it takes that newly calculated mass and sees if status should change, depending on how much
// mass there currently is. It also writes a value to the serial port (back to the arduino)
// depending on that status. It then updates the status text view to reflect this
Handler updateMassHandler = new Handler(){
public void handleMessage(Message msg){
// mass calculation
try{currentMassVal = calculateMass(Integer.parseInt(inData.get(inData.size()-1)));} catch (Exception e){} // try-catch in case data isn't an int
inData.clear();
currentMassTextView.setText(String.format(getResources().getString(R.string.current_mass_string), currentMassVal));
// status check with new mass
if (currentMassVal >= maxLoad)
status = true;
else if (currentMassVal <= minLoad)
status = false;
statusTextView.setText(String.format(getResources().getString(R.string.pump_status), getStatus()));
// writing back to arduino
if (serialPort != null) {
if (status)
serialPort.write("1".getBytes());
else
serialPort.write("0".getBytes());
}
}
};
// serial port variables:
public final String ACTION_USB_PERMISSION = "com.example.jake.USB_PERMISSION";
UsbManager usbManager;
UsbDevice device;
UsbSerialDevice serialPort;
UsbDeviceConnection connection;
UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { //Defining a Callback which triggers whenever data is read.
#Override
public void onReceivedData(byte[] arg0) {
String data;
try {
data = new String(arg0, "UTF-8");
inData.add(data);
} catch (UnsupportedEncodingException e) {}
}
};
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { //Broadcast Receiver to automatically start and stop the Serial connection.
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_USB_PERMISSION)) {
boolean granted = intent.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED);
if (granted) {
connection = usbManager.openDevice(device);
serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection);
if (serialPort != null) {
if (serialPort.open()) { //Set Serial Connection Parameters.
serialPort.setBaudRate(9600);
serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8);
serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1);
serialPort.setParity(UsbSerialInterface.PARITY_NONE);
serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF);
serialPort.read(mCallback);
} else {
Log.d("SERIAL", "PORT NOT OPEN");
}
} else {
Log.d("SERIAL", "PORT IS NULL");
}
} else {
Log.d("SERIAL", "PERM NOT GRANTED");
}
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
start();
} else if (intent.getAction().equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
stop();
}
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_pump);
usbManager = (UsbManager) getSystemService(USB_SERVICE);
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_USB_PERMISSION);
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
registerReceiver(broadcastReceiver, filter);
status = false;
statusTextView = (TextView) findViewById(R.id.statusTextView);
statusTextView.setText(String.format(getResources().getString(R.string.pump_status), getStatus()));
currentMassTextView = (TextView) findViewById(R.id.currentMassTextView);
currentMassTextView.setText(R.string.calculating_text);
stop = (Button) findViewById(R.id.stopButton);
runTimer = true;
currentMassVal = 0;
inData = new ArrayList<>();
// thread that "calls" the handleMessage method in the upDateMassHandler every 100 milliseconds
updateMass = new Thread(new Runnable() {
#Override
public void run() {
while(runTimer){
updateMassHandler.sendEmptyMessage(0);
try{Thread.sleep(100);} catch (InterruptedException e){}
}
}
});
// thanks to stackOverflow for the file reading code
// reading and parsing from calibration data
calibrationData = new File(getFilesDir(), "CalibrationData.txt");
StringBuilder text = new StringBuilder();
// reading in the calibration data from the file (of the same name)
try {
BufferedReader br = new BufferedReader(new FileReader(calibrationData));
String line;
while ((line = br.readLine()) != null) {
text.append(line);
text.append('\n');
}
br.close();
} catch (IOException e) {}
// parsing values from calibration data
String calibData = text.toString();
calibData = calibData.substring(3);
mass1 = Integer.parseInt(calibData.substring(0, calibData.indexOf('R')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
read1 = Integer.parseInt(calibData.substring(0, calibData.indexOf('M')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
mass2 = Integer.parseInt(calibData.substring(0, calibData.indexOf('R')));
calibData = calibData.substring(calibData.indexOf(':') + 1);
read2 = Integer.parseInt(calibData.substring(0, calibData.indexOf('.')));
slope = ((double) (mass2 - mass1) / (read2 - read1)); // calculating slope of masses and reads to allow
// calculation of mass of an unknown read
// reading and parsing from bag data
bagData = new File(getFilesDir(), "BagData.txt");
StringBuilder text2 = new StringBuilder();
// reading in the bag data from the file (of the same name)
try {
BufferedReader br = new BufferedReader(new FileReader(bagData));
String line;
while ((line = br.readLine()) != null) {
text2.append(line);
text2.append('\n');
}
br.close();
} catch (IOException e) {}
// parsing values frm bag data
String bagData = text2.toString();
bagData = bagData.substring(1);
emptyMassNum = Integer.parseInt(bagData.substring(0, bagData.indexOf('M')));
bagData = bagData.substring(bagData.indexOf('x') + 1);
maxLoad = Float.parseFloat(bagData.substring(0, bagData.indexOf('M')));
bagData = bagData.substring(bagData.indexOf('n') + 1);
minLoad = Float.parseFloat(bagData.substring(0, bagData.indexOf(';')));
emptyMass = calculateMass(emptyMassNum); // emptyMassNum is the values read in from the arduino
// this converts it to a mass
updateMass.start();
start();
}
// method: calculateMass
// description: calculates the mass of the object on the transducer based off of the value read
// in and the data gotten from calibration
// input: int readVal - the value read in
// output: double - the calculated mass
public double calculateMass(int readVal){
return (slope * (readVal-read1)) + mass1;
}
// method: getStatus
// description: returns a string representation of the status
public String getStatus(){
if(status)
return "running";
else
return "stopped";
}
// method: stop
// description: stops everything when the stop button is pressed
public void stop(View view){
status = false;
runTimer = false;
stop();
stop.setText(R.string.button_stopped);
}
// serial port methods:
public void start() {
HashMap<String, UsbDevice> usbDevices = usbManager.getDeviceList();
if (!usbDevices.isEmpty()) {
boolean keep = true;
for (Map.Entry<String, UsbDevice> entry : usbDevices.entrySet()) {
device = entry.getValue();
int deviceVID = device.getVendorId();
if (deviceVID == 10755 || deviceVID == 9025)//Arduino Vendor ID
{
PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
usbManager.requestPermission(device, pi);
keep = false;
} else {
connection = null;
device = null;
}
if (!keep)
break;
}
}
}
public void stop() {
if(serialPort!=null)
serialPort.close();
}
}
For some reason, the onReceivedData method in the mCallback variable does not seem to be called in the second activity (the one not working). I'm pretty sure this is the problem, I'm just not sure why it is being called in one activity and not in another with the same code. If that method is not called, then I can't access the data coming in, which is my problem.
Also, here's my manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.stylosa.hangingtransducer">
<uses-feature android:name="android.hardware.usb.host" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".CalibrateActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".InputActivity"
android:parentActivityName=".MainActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".EnterDataActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
<activity
android:name=".PumpActivity">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
</intent-filter>
</activity>
</application>
Any and all help would be greatly appreciated!

how to set android hotspot active in background?

I'm working on app which will set hotspot on/off when button is clicked.
If i turn on hotspot with app, when i opened another app or got any notification hotspot automatically going to turn off
My code:
public class WifiAP extends Activity {
private static int constant = 0;
private static final int WIFI_AP_STATE_UNKNOWN = -1;
private static int WIFI_AP_STATE_DISABLING = 0;
private static int WIFI_AP_STATE_DISABLED = 1;
public int WIFI_AP_STATE_ENABLING = 2;
public int WIFI_AP_STATE_ENABLED = 3;
private static int WIFI_AP_STATE_FAILED = 4;
private final String[] WIFI_STATE_TEXTSTATE = new String[] {
"DISABLING","DISABLED","ENABLING","ENABLED","FAILED"
};
private WifiManager wifi;
private String TAG = "WifiAP";
private int stateWifiWasIn = -1;
private boolean alwaysEnableWifi = true; //set to false if you want to try and set wifi state back to what it was before wifi ap enabling, true will result in the wifi always being enabled after wifi ap is disabled
/**
* Toggle the WiFi AP state
* #param wifihandler
*/
public void toggleWiFiAP(WifiManager wifihandler, Context context) {
if (wifi==null){
wifi = wifihandler;
}
boolean wifiApIsOn = getWifiAPState()==WIFI_AP_STATE_ENABLED || getWifiAPState()==WIFI_AP_STATE_ENABLING;
new SetWifiAPTask(!wifiApIsOn,false,context).execute();
}
private int setWifiApEnabled(boolean enabled) {
Log.d(TAG, "*** setWifiApEnabled CALLED **** " + enabled);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "Aqual soul";
config.preSharedKey="aquasoul";
config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN);
config.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
config.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
config.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.CCMP);
config.allowedGroupCiphers.set(WifiConfiguration.GroupCipher.TKIP);
//remember wirelesses current state
if (enabled && stateWifiWasIn==-1){
stateWifiWasIn=wifi.getWifiState();
}
/* //disable wireless
if (enabled && wifi.getConnectionInfo() !=null) {
Log.d(TAG, "disable wifi: calling");
wifi.setWifiEnabled(false);
int loopMax = 10;
while(loopMax>0 && wifi.getWifiState()!=WifiManager.WIFI_STATE_DISABLED){
Log.d(TAG, "disable wifi: waiting, pass: " + (10-loopMax));
try {
Thread.sleep(500);
loopMax--;
} catch (Exception e) {
}
}
Log.d(TAG, "disable wifi: done, pass: " + (10-loopMax));
}
*/
//enable/disable wifi ap
int state = WIFI_AP_STATE_UNKNOWN;
try {
Log.d(TAG, (enabled?"enabling":"disabling") +" wifi ap: calling");
wifi.setWifiEnabled(false);
Method method1 = wifi.getClass().getMethod("setWifiApEnabled", WifiConfiguration.class, boolean.class);
//method1.invoke(wifi, null, enabled); // true
method1.invoke(wifi, config, enabled); // true
Method method2 = wifi.getClass().getMethod("getWifiApState");
state = (Integer) method2.invoke(wifi);
} catch (Exception e) {
Log.e(WIFI_SERVICE, e.getMessage());
// toastText += "ERROR " + e.getMessage();
}
//hold thread up while processing occurs
if (!enabled) {
int loopMax = 10;
while (loopMax>0 && (getWifiAPState()==WIFI_AP_STATE_DISABLING || getWifiAPState()==WIFI_AP_STATE_ENABLED || getWifiAPState()==WIFI_AP_STATE_FAILED)) {
Log.d(TAG, (enabled?"enabling":"disabling") +" wifi ap: waiting, pass: " + (10-loopMax));
try {
Thread.sleep(500);
loopMax--;
} catch (Exception e) {
}
}
Log.d(TAG, (enabled?"enabling":"disabling") +" wifi ap: done, pass: " + (10-loopMax));
//enable wifi if it was enabled beforehand
//this is somewhat unreliable and app gets confused and doesn't turn it back on sometimes so added toggle to always enable if you desire
if(stateWifiWasIn==WifiManager.WIFI_STATE_ENABLED || stateWifiWasIn==WifiManager.WIFI_STATE_ENABLING || stateWifiWasIn==WifiManager.WIFI_STATE_UNKNOWN || alwaysEnableWifi){
Log.d(TAG, "enable wifi: calling");
wifi.setWifiEnabled(true);
//don't hold things up and wait for it to get enabled
}
stateWifiWasIn = -1;
} else if (enabled) {
int loopMax = 10;
while (loopMax>0 && (getWifiAPState()==WIFI_AP_STATE_ENABLING || getWifiAPState()==WIFI_AP_STATE_DISABLED || getWifiAPState()==WIFI_AP_STATE_FAILED)) {
Log.d(TAG, (enabled?"enabling":"disabling") +" wifi ap: waiting, pass: " + (10-loopMax));
try {
Thread.sleep(500);
loopMax--;
} catch (Exception e) {
}
}
Log.d(TAG, (enabled?"enabling":"disabling") +" wifi ap: done, pass: " + (10-loopMax));
}
return state;
}
public int getWifiAPState() {
int state = WIFI_AP_STATE_UNKNOWN;
try {
Method method2 = wifi.getClass().getMethod("getWifiApState");
state = (Integer) method2.invoke(wifi);
} catch (Exception e) {
}
if(state>=10){
//using Android 4.0+ (or maybe 3+, haven't had a 3 device to test it on) so use states that are +10
constant=10;
}
//reset these in case was newer device
WIFI_AP_STATE_DISABLING = 0+constant;
WIFI_AP_STATE_DISABLED = 1+constant;
WIFI_AP_STATE_ENABLING = 2+constant;
WIFI_AP_STATE_ENABLED = 3+constant;
WIFI_AP_STATE_FAILED = 4+constant;
Log.d(TAG, "getWifiAPState.state " + (state==-1?"UNKNOWN":WIFI_STATE_TEXTSTATE[state-constant]));
return state;
}
class SetWifiAPTask extends AsyncTask<Void, Void, Void> {
boolean mMode; //enable or disable wifi AP
boolean mFinish; //finalize or not (e.g. on exit)
ProgressDialog d;
public SetWifiAPTask(boolean mode, boolean finish, Context context) {
mMode = mode;
mFinish = finish;
d = new ProgressDialog(context);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
d.setTitle("Turning WiFi AP " + (mMode?"on":"off") + "...");
d.setMessage("...please wait a moment.");
d.show();
}
#Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
try {
d.dismiss();
MainActivity.updateStatusDisplay();
} catch (IllegalArgumentException e) {
};
if (mFinish){
finish();
}
}
#Override
protected Void doInBackground(Void... params) {
setWifiApEnabled(mMode);
return null;
}
}
}

Application receiving NFC always pops up new instance in front

I run through the following life-cycle when starting my app through the launcher:
onCreate..., onPostCreate..., onResume..., onNewIntent..., act:android.intent.action.MAIN, mNfcAdapter.disableForegroundDispatch OK.
When I then tap a tag, a new instance of application seems to be launched as I run through the following life-cycle then:
onPause..., onCreate..., onPostCreate..., onResume..., onNewIntent..., act:android.nfc.action.TAG_DISCOVERED, myTag.mId:048a1382bd2384)
Since I try to use the foreground dispatch system to disable recieving NFC events, I expected my app to ignore the NFC tag. So why is my activity recreated instead? Is it because AndroidManifest.xml allows it?
package com.example.pdf.nfcaccess;
import android.annotation.SuppressLint;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
// PDf import
import android.telephony.TelephonyManager;
import android.content.Intent;
import android.content.Context;
import android.content.IntentFilter;
import android.app.PendingIntent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcEvent;
import android.widget.TextView;
import android.widget.Toast;
import android.util.Log;
import android.nfc.tech.NfcF;
import android.nfc.Tag;
/**
* An example full-screen activity that shows and hides the system UI (i.e.
* status bar and navigation/system bar) with user interaction.
*/
public class FullscreenActivity extends AppCompatActivity {
/**
* Whether or not the system UI should be auto-hidden after
* {#link #AUTO_HIDE_DELAY_MILLIS} milliseconds.
*/
private static final boolean AUTO_HIDE = true;
/**
* If {#link #AUTO_HIDE} is set, the number of milliseconds to wait after
* user interaction before hiding the system UI.
*/
private static final int AUTO_HIDE_DELAY_MILLIS = 3000;
/**
* Some older devices needs a small delay between UI widget updates
* and a change of the status and navigation bar.
*/
private static final int UI_ANIMATION_DELAY = 300;
private final Handler mHideHandler = new Handler();
private View mContentView;
private final Runnable mHidePart2Runnable = new Runnable() {
#SuppressLint("InlinedApi")
#Override
public void run() {
// Delayed removal of status and navigation bar
// Note that some of these constants are new as of API 16 (Jelly Bean)
// and API 19 (KitKat). It is safe to use them, as they are inlined
// at compile-time and do nothing on earlier devices.
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE
| View.SYSTEM_UI_FLAG_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
}
};
private View mControlsView;
// application
static FullscreenActivity mInstance;
NfcAdapter mNfcAdapter;
Intent mNfcIntent;
PendingIntent mNfcPendingIntent;
IntentFilter mTagIntentFilter;
IntentFilter[] mIntentFiltersArray;
String[][] mTechLists;
TextView mTagContentText;
// log
//java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
java.util.ArrayList<String> mLogItems = new java.util.ArrayList<String>();
android.widget.ArrayAdapter<String> mLogAdapter;
android.widget.ListView mLogList;
/**/
private final Runnable mShowPart2Runnable = new Runnable() {
#Override
public void run() {
// Delayed display of UI elements
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.show();
}
mControlsView.setVisibility(View.VISIBLE);
}
};
private boolean mVisible;
private final Runnable mHideRunnable = new Runnable() {
#Override
public void run() {
hide();
}
};
/**
* Touch listener to use for in-layout UI controls to delay hiding the
* system UI. This is to prevent the jarring behavior of controls going away
* while interacting with activity UI.
*/
/* Enable NFC
*/
private final View.OnTouchListener mFuncNfcEnable = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
traceTry("mFuncNfcEnable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.enableForegroundDispatch");
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};
/* read Intent
*/
private final View.OnTouchListener mFuncNfcRead = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (mNfcAdapter != null) {
try {
traceTry("onNewIntent");
onNewIntent(getIntent());
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
return false;
}
};
/* Disable NFC
*/
private final View.OnTouchListener mFuncNfcDisable = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
traceTry("mFuncNfcDisable");
if (mNfcAdapter != null) {
try {
traceTry("mNfcAdapter.disableForegroundDispatch");
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
return false;
}
};
/* Quit
*/
private final View.OnTouchListener mFuncBtnQuit = new View.OnTouchListener() {
#Override
public boolean onTouch(View view, MotionEvent motionEvent) {
finish();
return false;
}
};
/**/
private void trace(String m) {
Log.d("NFCTags",m);
/*TextView tv = (TextView)findViewById(R.id.logContent_value);
String previous = tv.getText().toString();
tv.setText(previous + "\n" + m);*/
if (mLogAdapter != null) {
mLogItems.add(m);
mLogAdapter.notifyDataSetChanged();
mLogList.setSelection(mLogList.getCount()-1);
}
}
String mMessage = "";
private void traceTry(String m) {
trace(m + "...");
mMessage = m;
}
private void traceOk() {
trace(mMessage + " OK");
mMessage = "";
}
private void traceFails(Throwable t) {
String msg = mMessage + " fails";
if (t != null) {
msg += " exception:" + t.getMessage();
}
trace(msg);
//Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
mMessage = "";
}
/*
*/
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
trace("onCreate...");
// set global unique instance
FullscreenActivity.mInstance = this;
setContentView(R.layout.activity_fullscreen);
// log
mLogItems.add("starts");
mLogAdapter = new android.widget.ArrayAdapter<String>(this, R.layout.support_simple_spinner_dropdown_item, mLogItems);
mLogList = (android.widget.ListView) findViewById(R.id.logList_value);
mLogList.setAdapter(mLogAdapter);
mVisible = true;
mControlsView = findViewById(R.id.fullscreen_content_controls);
mContentView = findViewById(R.id.fullscreen_content);
mTagContentText = (TextView) findViewById(R.id.tagContent_value);
// Set up the user interaction to manually show or hide the system UI.
mContentView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
toggle();
}
});
// Upon interacting with UI controls, delay any scheduled hide()
// operations to prevent the jarring behavior of controls going away
// while interacting with the UI.
findViewById(R.id.nfcRead_btn).setOnTouchListener(mFuncNfcRead);
//findViewById(R.id.nfcDisable_btn).setOnTouchListener(mFuncNfcDisable);
findViewById(R.id.quit_btn).setOnTouchListener(mFuncBtnQuit);
trace("onCreate > before initializing nfc");
TelephonyManager tm = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
trace("ID:" + tm.getDeviceId());
trace("Network Operator Name:" + tm.getNetworkOperatorName());
trace("Sim Operator Name:" + tm.getSimOperatorName());
trace("Sim Serial Number:" + tm.getSimSerialNumber());
trace("Phone Type:" + tm.getPhoneType());
trace("Initial Phone Number:" + tm.getLine1Number());
boolean tryNfc = true;
if (tryNfc) {
try {
mMessage = "NfcAdapter.getDefaultAdapter";
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
mMessage = "NFC is not available";
traceFails(null);
return;
} else {
traceOk();
}
} catch (Throwable t) {
traceFails(t);
return;
}
// Check if NFC is enabled
try {
mMessage = "test NfcAdapter.isEnabled";
if (!mNfcAdapter.isEnabled()) {
mMessage = "NFC is not enabled. do it manually";
traceFails(null);
return;
} else {
trace("NFC is enabled.");
}
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "create new Intent";
mNfcIntent = new Intent(this, getClass());
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "mNfcIntent.addFlags, PendingIntent.getActivity";
mNfcIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
mNfcPendingIntent = PendingIntent.getActivity(this, 0, mNfcIntent, 0);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "new IntentFilter";
mTagIntentFilter = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
mTagIntentFilter.addCategory(Intent.CATEGORY_DEFAULT);
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
try {
mMessage = "addDataType, new IntentFilter[]";
mTagIntentFilter.addDataType("*/*");
//mTagIntentFilter.addDataType("text/plain");
mIntentFiltersArray = new IntentFilter[]{mTagIntentFilter};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
// Setup a tech list for all NfcF tags
try {
mMessage = "new tech list";
//mTechLists = new String[][]{new String[]{NfcF.class.getName()}};
mTechLists = new String[][]{};
traceOk();
} catch (Throwable t) {
traceFails(t);
return;
}
/*
if (mNfcAdapter != null) {
try {
mMessage = "mNfcAdapter.enableForegroundDispatch";
mNfcAdapter.enableForegroundDispatch(FullscreenActivity.mInstance, mNfcPendingIntent, mIntentFiltersArray, mTechLists);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
*/
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
trace("onPostCreate...");
// Trigger the initial hide() shortly after the activity has been
// created, to briefly hint to the user that UI controls
// are available.
//delayedHide(100);
}
private void toggle() {
trace("toggle...");
if (mVisible) {
hide();
} else {
show();
}
}
private void hide() {
trace("hide...");
// Hide UI first
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.hide();
}
mControlsView.setVisibility(View.GONE);
mVisible = false;
// Schedule a runnable to remove the status and navigation bar after a delay
mHideHandler.removeCallbacks(mShowPart2Runnable);
mHideHandler.postDelayed(mHidePart2Runnable, UI_ANIMATION_DELAY);
}
#SuppressLint("InlinedApi")
private void show() {
// Show the system bar
mContentView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mVisible = true;
// Schedule a runnable to display UI elements after a delay
mHideHandler.removeCallbacks(mHidePart2Runnable);
mHideHandler.postDelayed(mShowPart2Runnable, UI_ANIMATION_DELAY);
}
/**
* Schedules a call to hide() in [delay] milliseconds, canceling any
* previously scheduled calls.
*/
private void delayedHide(int delayMillis) {
mHideHandler.removeCallbacks(mHideRunnable);
mHideHandler.postDelayed(mHideRunnable, delayMillis);
}
/**/
public String intentToText(Intent intent){
String report = "?";
try {
Bundle bundle = intent.getExtras();
if (bundle != null) {
java.util.Set<String> keys = bundle.keySet();
java.util.Iterator<String> it = keys.iterator();
report = "Intent:{";
while (it.hasNext()) {
String key = it.next();
report += "\n[" + key + ":" + bundle.get(key) + "],";
}
report += "}\n";
}
}
catch(Throwable t){
trace("intentToText > " + t.getMessage());
}
return report;
}
/**/
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
/**/
#Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
trace("onNewIntent...");
handleIntent(intent);
}
/**/
void handleIntent(Intent intent) {
if (intent == null) return;
String sAction = intent.getAction();
trace("act:" + sAction);
if( (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TAG_DISCOVERED.equals(intent.getAction()))
|| (NfcAdapter.ACTION_TECH_DISCOVERED.equals(intent.getAction()))) {
String payload = intent.getDataString();
mTagContentText.setText("act:" + sAction + "\n" + "pload:" + payload + "\n" + intentToText(intent));
Tag myTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (myTag != null) {
trace("myTag.mId:" + byteArrayToHex(myTag.getId()));
mTagContentText.setText(mTagContentText.getText() + "\n" + "myTag.mId:" + byteArrayToHex(myTag.getId()));
android.os.Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
for (android.os.Parcelable p : rawMsgs) {
NdefMessage msg = (NdefMessage) p;
NdefRecord[] records = msg.getRecords();
for (NdefRecord record : records) {
short tnf = record.getTnf();
byte[] id = record.getId();
byte[] payLoad = record.getPayload();
}
}
}
}
}
}
/**/
#Override
protected void onResume() {
super.onResume();
trace("onResume...");
if (mNfcAdapter != null) {
try {
// See if the Activity is being started/resumed due to an NFC event and handle it
onNewIntent( getIntent());
}
catch (Throwable t) {
traceFails(t);
}
try {
mMessage = "mNfcAdapter.disableForegroundDispatch";
mNfcAdapter.disableForegroundDispatch(FullscreenActivity.mInstance);
traceOk();
}
catch (Throwable t) {
traceFails(t);
}
}
}
/**/
#Override
protected void onPause() {
super.onPause();
trace("onPause...");
}
}
AndroidManifest.xml is :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pdf.nfcaccess">
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_pdflauncher"
android:label="#string/app_name"
android:supportsRtl="true"
android:debuggable="true"
android:theme="#style/AppTheme">
<activity
android:name=".FullscreenActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:label="#string/app_name"
android:theme="#style/FullscreenTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
<!--intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain"/>
</intent-filter-->
</manifest>
You receive the NFC intent (action TAG_DISCOVERED) because you registered for it in the manifest:
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
This is also the reason why your activity is recreated upon receiving the intent.
The intent filter that you register for the foreground dispatch (action NDEF_DISCOVERED with any MIME type) does not seem to match your tag (or you did not yet invoke the piece of code that would enable the foreground dispatch).
Note that calling disableForegroundDispatch() will ony disable a foreground dispatch previously registered through enableForegroundDispatch(). It will not influence the intent filters in your manifest. See Android: Can I enable/disable an activity's intent filter programmatically? on how you could selectively disable intent filters registered in the manifest. However, with regard to NFC intents, you would probably want to register to receive events for all tags through the foreground dispatch system and then, upon receiving the event in onNewIntent() selectively ignore tags that you don't want.
A few more things about your code (actually only about the NFC parts)
For the NDEF_DISCOVERED intent filter in your manifest you would typically also want to specify a <data ... /> element that matches the data type of your tags.
Do not use a TAG_DISCOVERED intent filter in your manifest (unless you really understand and want the impact of this). The TAG_DISCOVERED intent filter (when used in the manifest) is merely a compatibility mode for API level 9 (before Android 2.3.3) where NFC support was very, very limited and a fall-back mode that can be used to create apps that handle NFC tags that are not supported by any other app.
The TECH_DISCOVERED intent filter requires a tech-list XML file in order to match any tag. Thus, your current version of this filter in your manifest will never match anything.
Calling disableForegroundDispatch() in onResume() does not make any sense. By design, the foreground dispatch could never be enabled at this point of the activity life-cycle. The reason for this is that you must not call enableForegroundDispatch() before onResume() and you are required to call disableForegroundDispatch() at latest in onPause().
In fact it does not make sense to use enableForegroundDispatch() / disableForegroundDispatch() anywhere other than in onResume() / onPause(). If you want to stop listening for tags upon other events (e.g. a pressing a button), you would simply remember your current state (process/don't process NFC events) in some flag and, when you receive a new NFC intent in onNewIntent(), you would either process or silently ignore the tag based n that flag.
Your code should not manually call activity life-cycle methods (as you currently do with onNewIntent(getIntent());).

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.

How to Run the Async Task for a set timeout?

I want to run my Async Task which fetches the co-odinates with a certain accuracy and fires up a different activity if it gets co-ordinates.
Now I want to setup a time so that if it doesn't gets the co-ordinates with a set accuracy then the Async task should destroy itself (remove location updates etc.) and the default value for Lattitude/Longitude is passed.
I tried using this:
new GetGPShotfix().execute().get(1, TimeUnit.MINUTES); so as to set a timeout for this async for a min and then proceed onto the next line/task below this async execute call.
But in my case it skips over to the next line without waiting for the timeout set by Async.
How can I make it execute the way I want? I also tried using thread's join() but apparently results were same :(
Update:
Here's my code (for gpshotfix() Async):
private class GetGPShotfix extends AsyncTask<Void, Void, Void> {
// ProgressDialog progressDialogGPS;
#Override
protected void onPreExecute() {
super.onPreExecute();
Log.i("GPSfixer", "Ready to get GPS Hotfix");
}
#Override
protected Void doInBackground(Void... params) {
try {
LocationRetriever myLoc = new LocationRetriever();
// myLoc.getUserLoc();
//if (gotLoc == 0 && (firstLoc.getAccuracy() > 10)) {
if (gotLoc == 0) {
myLoc.getUserLoc();
}
} catch (Exception e) {
Log.i("GPSfixer", "GPS Hotfix Failed!", e);
}
finally {
Log.i("GPSfixer", "Get GPS Hotfix Completed...");
}
return null;
}
#Override
protected void onCancelled() {
Log.i("GPSfixer", "Get GPS Hotfix Cancelled");
}
#Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
Log.i("GPSfixer", "GPS Hotfix cycle completed");
System.out.println("Lon :" + myCurrentLon + "Lon2: " + finalLonNow);
System.out.println("Lat :" + myCurrentLat + "Lat2: " + finalLatNow);
//pDialog2.dismiss();
// progressDialogGPS.dismiss();
}
}
public class LocationRetriever {
final LocationManager locationManager = (LocationManager) StoreSelection.this.getSystemService(Context.LOCATION_SERVICE);
final LocationListener locationListener = new LocationListener() {
public void onProviderDisabled(String provider) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
provider + " is disabled!", Toast.LENGTH_SHORT).show();
Toast.makeText(getApplicationContext(),
"Please standby..enabling " + provider,
Toast.LENGTH_SHORT).show();
// explicitly enable GPS
Intent enableGPS = new Intent("android.location.GPS_ENABLED_CHANGE");
enableGPS.putExtra("enabled", true);
sendBroadcast(enableGPS);
// explictly disable GPS
/*
* Intent intent = new
* Intent("android.location.GPS_ENABLED_CHANGE");
* intent.putExtra("enabled", false); sendBroadcast(intent);
*/
}
public void onProviderEnabled(String provider) {
// TODO Auto-generated method stub
Toast.makeText(getApplicationContext(),
provider + " is enabled..", Toast.LENGTH_SHORT).show();
}
public void onStatusChanged(String provider, int status,
Bundle extras) {
// TODO Auto-generated method stub
/*
* System.out.println("val of status: " + status + " provider: "
* + provider);
*/
if (status == 1) {
Toast.makeText(getApplicationContext(),
provider + " is enabled & available..",
Toast.LENGTH_SHORT).show();
System.out.println(provider + " is NOT available!");
} else {
System.out.println(provider + " is NOT available!");
}
/* progressDialogGPS.dismiss(); */
}
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
// ORIG CODE --BELOW--
// moved lat/lon vars to top ^
myCurrentLon = location.getLongitude();
myCurrentLat = location.getLatitude();
firstLoc = location;
myCurrentLon = Double.parseDouble(new DecimalFormat("##.#########")
.format(myCurrentLon));
myCurrentLat = Double.parseDouble(new DecimalFormat("##.#########")
.format(myCurrentLat));
/*Toast.makeText(getApplicationContext(),
myCurrentLat + " " + myCurrentLon, Toast.LENGTH_SHORT)
.show();*/
System.out.println(myCurrentLat + " " + myCurrentLon);
float acc=location.getAccuracy();
/*Toast.makeText(getApplicationContext(), "Acc.: " + acc,Toast.LENGTH_SHORT).show();*/
// --
// get best out of 2 locs. --BEGINS--
/*
* makeUseOfNewLocation(location);
*
* if(currentBestLocation == null){ currentBestLocation =
* location; }
*/
if (myCurrentLon != null && myCurrentLat != null && (firstLoc.getAccuracy() <= 10)) { // added
// chk
// for
// online..
gotLoc = 1;
System.out.println("OK GOTLOC == 1 !");
System.out.println("Got your Current Location..disabling GPS to save Battery Power..");
Toast.makeText(getApplicationContext(), "Got your Current Location..disabling GPS to save Battery Power..", Toast.LENGTH_SHORT).show();
// removing updates
// locationManager.removeUpdates(locationListener);
// explicitly turning off GPS
Intent intent = new Intent("android.location.GPS_ENABLED_CHANGE");
intent.putExtra("enabled", false);
sendBroadcast(intent);
System.out.println("GPS disabled!");
finalLatNow = myCurrentLat;
finalLonNow = myCurrentLon;
//
// if(gotLoc == 0){
if (myCurrentLon != null
&& myCurrentLat != null && (firstLoc.getAccuracy() <= 10)) {
// locationManager.removeUpdates(locationListener);
gotLoc = 1;
Intent i = new Intent(StoreSelection.this, LastVisitDetails.class);
i.putExtra("currUsrLon", myCurrentLon); // 2nd
i.putExtra("currUsrLat", myCurrentLat); // 1st
i.putExtra("storeID", selStoreID);
i.putExtra("selStoreName", selStoreName);
i.putExtra("imei", uuid);
i.putExtra("date", userDate);
runOnUiThread(new Runnable() {
public void run() {
try {
// stuff here
pDialog2.dismiss();
} catch (Exception e) {
e.printStackTrace();
}
}
});
System.out.println("--Removing Loc. Updates--");
remUpdates();
syncTIMESTAMP = System.currentTimeMillis();
Date dateobj = new Date(syncTIMESTAMP);
SimpleDateFormat df = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
fullFileName1 = df.format(dateobj);
dbengine.open();
dbengine.UpdateStoreStartVisit(selStoreID, fullFileName1);
dbengine.close();
startActivity(i);
finish();
} else {
if (myCurrentLon == null && myCurrentLat == null) {
// alert + GPS not locking on..do something()
} else {
}
/*if (!isOnline()) {
// alert + not online...do something()
showNoConnAlert();
} else {
}*/
}
//
/*
* } else{}
*/
} else {
System.out.println("INSIDE ELSE -- GOTLOC");
}
}
};
// locationManager.requestLocationUpdates(locationManager.getBestProvider(new
// Criteria(), true), 2000, 4, locationListener);
// enable gps everytime we request location update
/*
* Intent enableGPS = new Intent("android.location.GPS_ENABLED_CHANGE");
* enableGPS.putExtra("enabled", true); sendBroadcast(enableGPS);
*/
// ** ORIG Grequest location updates from GPS string
/*
* locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER,
* ONE_MIN, 4, locationListener);
*/
// ** now remove updating of co-ordinates
// locationManager.removeUpdates(locationListener);
/*public Location getBestLoc(){
if(firstLoc.getAccuracy() <= newLoc.getAccuracy() && newLoc.getAccuracy() <= 10) {
return firstLoc;
}
else if(newLoc.getAccuracy() <= firstLoc.getAccuracy() && newLoc.getAccuracy() <= 10){
return newLoc;
}
else {
return newLoc;
}
}*/
void getUserLoc() {
if (gotLoc == 1 && (firstLoc.getAccuracy() <= 10)) {
locationManager.removeUpdates(locationListener);
} else {
}
final Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setHorizontalAccuracy(Criteria.ACCURACY_FINE);
// criteria.setVerticalAccuracy(Criteria.NO_REQUIREMENT);
criteria.setAltitudeRequired(false);
// criteria.setBearingAccuracy(Criteria.NO_REQUIREMENT);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_HIGH);
runOnUiThread(new Runnable() {
public void run() {
try {
// stuff here
/*
* progressDialogGPS = ProgressDialog.show(_activity,
* null, null);
* progressDialogGPS.setContentView(R.layout.loader);
* progressDialogGPS
* .getWindow().setType(WindowManager.LayoutParams
* .TYPE_KEYGUARD_DIALOG);
*/
/*locationManager
.requestLocationUpdates(locationManager
.getBestProvider(criteria, true),
TEN_SECS, 4, locationListener);*/
locationManager.requestLocationUpdates(locationManager.GPS_PROVIDER, 0l, 0.0f, locationListener);
// remove updates #
if (gotLoc == 1 && (firstLoc.getAccuracy() <= 10)) {
locationManager.removeUpdates(locationListener);
} else {
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
/*
* try { Thread.currentThread().sleep(2000); } catch
* (InterruptedException e) { // TODO Auto-generated catch block
* e.printStackTrace(); }
*/
}
void remUpdates() {
//if(firstLoc.getAccuracy() <= 10){
locationManager.removeUpdates(locationListener);
//}
//else {}
}
}
Any help is appreciable..
When using execute.get(1, TimeUnit.MINUTES) it converts async task to synchronus. Using async task is of no use in that case. You can start a separate thread when starting asynctask to keep a watch for time and do the required operation after that. You can create a class implmenting runnable and pass asyctask as constructor argument and cancel it inside.
class checkAyscTask implements Runnable {
AsyncTask<Void, Void, Boolean> mAT;
Context context;
public checkAyscTask(AsyncTask<Void, Void, Boolean> at) {
mAT = at;
}
#Override
public void run() {
mHandler.postDelayed(runnable, 60000);
// After 60sec the task in run() of runnable will be done
}
Handler mHandler = new Handler();
Runnable runnable = new Runnable() {
#Override
public void run() {
if (mAT.getStatus() == Status.RUNNING || mAT.getStatus() == Status.PENDING) {
mAT.cancel(true); //Cancel Async task or do the operation you want after 1 minute
}
}
};
}
task_GetGPS = new GetGPShotfix();
task_GetGPS.execute();
checkAyscTask chk = new checkAyscTask(task_GetGPS);
// Thread keeping 1 minute time watch
(new Thread(chk)).start();

Categories

Resources