Hello fellow programmers!
I am really new to Android, 2 weeks old.
I am trying to do some programming with NFC. I have Nexus 5 and I am trying to read and display UID of the MIFARE Classic 1k. I know all the protocol compatibilities issues with the Broadcom chip, so we can skip that and go straight to fact that you can read UID with no problem.
I want to catch the intent and show a toast with read UID. So far I made it work by putting performIntent into onCreate method. By making the intent to restart my activity I am able to handle that intent and show its UID via toast and that all works. Here is my humble code:
MainActivity.java
package sanjin.com.nfc;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.app.Activity;
import android.nfc.Tag;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;
public class MainActivity extends Activity {
NfcAdapter mNfcAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
Boolean nfcEnabled = mNfcAdapter.isEnabled();
if (nfcEnabled){
Toast.makeText(MainActivity.this,
R.string.turned_on,
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this,
R.string.turned_off,
Toast.LENGTH_SHORT).show();
}
performIntent(getIntent());
}
private String serialId = "";
#Override
public void onResume() {
super.onResume();
performIntent(getIntent());
}
private void performIntent(Intent intent) {
String action = intent.getAction();
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
try {
byte[] tagId = tag.getId();
serialId = toHexString(tagId);
Log.d("[ReadCardTools]", "Serial Number: " + serialId);
Toast.makeText(this, serialId,Toast.LENGTH_SHORT).show();
} catch (NullPointerException ex) {
ex.printStackTrace();
serialId = "ERROR";
}
}
}
public static String toHexString(byte[] bytes) {
char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
char[] hexChars = new char[bytes.length * 2];
int v;
for ( int j = 0; j < bytes.length; j++ ) {
v = bytes[j] & 0xFF;
hexChars[j*2] = hexArray[v/16];
hexChars[j*2 + 1] = hexArray[v%16];
}
return new String(hexChars);
}
#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);
}
}
And manifest file:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="sanjin.com.nfc">
<uses-permission android:name="android.permission.NFC" />
<uses-feature
android:name="android.hardware.nfc"
android:required="true" />
<application
android:label="#string/app_name"
android:launchMode="singleTask">
<activity
android:name=".MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Now, I want this intent to just show the toast without starting the activity again. I realize its working because when the activity restarts, intent gets handled and show me my UID.
I just want the incoming intent to show the toast containing its UID.
Sorry if this was asked before, I tried finding it but no luck.
Thanks!
public class MainActivity extends AppCompatActivity {
private static final String LOG_TAG = MainActivity.class.getSimpleName();
NfcAdapter nfcAdapter;
TextView uidView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
uidView = (TextView)findViewById(R.id.mTextView);
nfcAdapter = NfcAdapter.getDefaultAdapter(MainActivity.this);
Boolean nfcEnabled = nfcAdapter.isEnabled();
if (nfcEnabled){
Toast.makeText(MainActivity.this,
R.string.turned_on,
Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this,
R.string.turned_off,
Toast.LENGTH_SHORT).show();
}
Intent intent = getIntent();
resolveIntent(intent);
}
protected void resolveIntent(Intent intent) {
Tag nfcTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (nfcTag == null) {
Log.w(LOG_TAG, "Unable to obtain NFC tag from intent!");
} else {
String tagId = bytesToHex(nfcTag.getId());
uidView.setText(tagId);
//Toast.makeText(getApplicationContext(), tagId, Toast.LENGTH_LONG).show();
}
}
public static String bytesToHex(byte[] bytes) {
StringBuilder ret = new StringBuilder();
if (bytes != null) {
for (Byte b : bytes) {
ret.append(String.format("%02X", b.intValue() & 0xFF));
}
}
StringBuilder result = new StringBuilder();
for (int i = 0; i <= ret.length() - 2; i = i + 2) {
result.append(new StringBuilder(ret.substring(i, i + 2)).reverse());
}
String card = result.reverse().toString();
if(card.length() == 8){
card = "0" + Long.parseLong(card, 16) + "\n\n";
}
if(card.length() == 9){
card = Long.parseLong(card, 16) + "\n\n";
}
return card;
}
}
Related
I have read many posts related to NFC scanning on Android, however I am unable to make it work.
The onNewIntent function never gets fired by my app sample.
In my activity, I have the following code:
//The array lists to hold our messages
private ArrayList<String> messagesToSendArray = new ArrayList<>();
private ArrayList<String> messagesReceivedArray = new ArrayList<>();
//Text boxes to add and display our messages
private EditText txtBoxAddMessage;
private TextView txtReceivedMessages;
private TextView txtMessagesToSend;
private NfcAdapter mNfcAdapter;
public void addMessage(View view) {
String newMessage = txtBoxAddMessage.getText().toString();
messagesToSendArray.add(newMessage);
txtBoxAddMessage.setText(null);
updateTextViews();
Toast.makeText(this, "Added Message", Toast.LENGTH_LONG).show();
}
private void updateTextViews() {
txtMessagesToSend.setText("Messages To Send:\n");
//Populate Our list of messages we want to send
if(messagesToSendArray.size() > 0) {
for (int i = 0; i < messagesToSendArray.size(); i++) {
txtMessagesToSend.append(messagesToSendArray.get(i));
txtMessagesToSend.append("\n");
}
}
txtReceivedMessages.setText("Messages Received:\n");
//Populate our list of messages we have received
if (messagesReceivedArray.size() > 0) {
for (int i = 0; i < messagesReceivedArray.size(); i++) {
txtReceivedMessages.append(messagesReceivedArray.get(i));
txtReceivedMessages.append("\n");
}
}
}
//Save our Array Lists of Messages for if the user navigates away
#Override
public void onSaveInstanceState(#NonNull Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putStringArrayList("messagesToSend", messagesToSendArray);
savedInstanceState.putStringArrayList("lastMessagesReceived",messagesReceivedArray);
}
//Load our Array Lists of Messages for when the user navigates back
#Override
public void onRestoreInstanceState(#NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
messagesToSendArray = savedInstanceState.getStringArrayList("messagesToSend");
messagesReceivedArray = savedInstanceState.getStringArrayList("lastMessagesReceived");
}
private PendingIntent mPendingIntent;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txtBoxAddMessage = (EditText) findViewById(R.id.txtBoxAddMessage);
txtMessagesToSend = (TextView) findViewById(R.id.txtMessageToSend);
txtReceivedMessages = (TextView) findViewById(R.id.txtMessagesReceived);
Button btnAddMessage = (Button) findViewById(R.id.buttonAddMessage);
btnAddMessage.setText("Add Message");
updateTextViews();
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter != null) {
//Handle some NFC initialization here
}
else {
Toast.makeText(this, "NFC not available on this device",
Toast.LENGTH_SHORT).show();
}
//Check if NFC is available on device
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if(mNfcAdapter != null) {
//This will refer back to createNdefMessage for what it will send
mNfcAdapter.setNdefPushMessageCallback(this, this);
//This will be called if the message is sent successfully
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this,
getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
this.onNewIntent(getIntent());
}
#Override
protected void onResume() {
super.onResume();
mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null);
}
#Override
protected void onPause() {
super.onPause();
if (mNfcAdapter != null) {
mNfcAdapter.disableForegroundDispatch(this);
}
}
#Override
public NdefMessage createNdefMessage(NfcEvent nfcEvent) {
//This will be called when another NFC capable device is detected.
if (messagesToSendArray.size() == 0) {
return null;
}
//We'll write the createRecords() method in just a moment
NdefRecord[] recordsToAttach = createRecords();
//When creating an NdefMessage we need to provide an NdefRecord[]
return new NdefMessage(recordsToAttach);
}
#Override
public void onNdefPushComplete(NfcEvent nfcEvent) {
//This is called when the system detects that our NdefMessage was
//Successfully sent.
messagesToSendArray.clear();
}
public NdefRecord[] createRecords() {
NdefRecord[] records = new NdefRecord[messagesToSendArray.size()];
for (int i = 0; i < messagesToSendArray.size(); i++){
byte[] payload = messagesToSendArray.get(i).
getBytes(StandardCharsets.UTF_8);
NdefRecord record = new NdefRecord(
NdefRecord.TNF_WELL_KNOWN, //Our 3-bit Type name format
NdefRecord.RTD_TEXT, //Description of our payload
new byte[0], //The optional id for our Record
payload); //Our payload for the Record
records[i] = record;
}
return records;
}
#Override
protected void onNewIntent(Intent intent) {
Log.e("TAG", "onNewIntent: "+intent.getAction());
super.onNewIntent(intent);
}
This is my manifest:
<?xml version="1.0" encoding="utf-8"?>
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" android:required="true"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:launchMode="singleTask"
android:name="com.banalapps.nfcmesssenger.MainActivity"
android:label="#string/app_name" >
<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"/>
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
</application>
I am aware that this is probably a duplicate, but any help would be greatly appreciated as I struggled for days trying to make this work.
I have an app that runs on 2 phones and allows the user to connect from one to the other using WifiP2p (WiFi Direct). On most phones, it works. Both phones go into peer discovery, they discover each other, one initiates a connection, and the other accepts. But when I try to connect to a Sony LT25i running Android 4.1.2, the pairing fails.
The code for initiating the connection is like this:
WifiP2pConfig wifiP2pConfig = new WifiP2pConfig();
wifiP2pConfig.deviceAddress = device.deviceAddress;
// Try to make a device that supports WifiDirect the group owner,
// so that a legacy device can connect to it as an access point.
wifiP2pConfig.groupOwnerIntent = 10;
// Wifi Protected Setup: Push Button Configuration. The other main option is PIN configuration.
wifiP2pConfig.wps.setup = WpsInfo.PBC;
mWifiP2pManager.connect(mChannel, wifiP2pConfig, new WifiP2pManager.ActionListener() {...
Unexpected group creation, remove network
When the problem occurs, when the initiating device runs the above code to attempt to connect, the Sony shows this interesting tidbit in Logcat:
02-02 05:22:55.494 669-781/? E/WifiP2pService: Unexpected group creation,
remove network: DIRECT-aq-LG Phoenix 2
isGO: false
GO: Device:
deviceAddress: de:0b:34:f0:11:78
primary type: null
secondary type: null
wps: 0
grpcapab: 0
devcapab: 0
status: 4
interface: p2p0
where "LG Phoenix 2" is the name of the phone initiating the pairing.
For some reason, WifiP2pService doesn't like the fact that a group is being created, and removes it. Why?
I looked up the error message "WifiP2pService: Unexpected group creation, remove"
and found this code in WifiP2pService.DefaultState.processMessage():
/* unexpected group created, remove */
case WifiMonitor.P2P_GROUP_STARTED_EVENT:
mGroup = (WifiP2pGroup) message.obj;
loge("Unexpected group creation, remove " + mGroup);
mWifiNative.p2pGroupRemove(mGroup.getInterface());
break;
So apparently this happens because the WifiP2pService is in DefaultState? By contrast, WifiP2pService.P2pEnabledState.processMessage() doesn't have a case for P2P_GROUP_STARTED_EVENT. So maybe if the WifiP2pService were in the P2pEnabledState on the phone, I wouldn't be having this group removal problem.
But according to the logs, WifiP2p is enabled: I'm catching the WIFI_P2P_STATE_CHANGED_ACTION broadcast and logging the value of EXTRA_WIFI_STATE. So why is WifiP2pService apparently in DefaultState?
By the way, pairing used to work on the Sony, but yesterday I connected the device to my home Wifi router and it doesn't seem to have worked ever since, even though I disconnected it from the router.
I've tried turning off Wifi, turning it back on, removing ("forgetting") my home Wifi router, and rebooting the phones, and connecting from other phones besides the LG. Nothing fixes the problem.
This code that you have is very incomplete and needs to be completed. Note the sample of the code for you.
import android.app.Activity;
import android.app.Fragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.net.wifi.WpsInfo;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdServiceResponseListener;
import android.net.wifi.p2p.WifiP2pManager.DnsSdTxtRecordListener;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo;
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import com.example.android.wifidirect.discovery.WiFiChatFragment.MessageTarget;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.DeviceClickListener;
import com.example.android.wifidirect.discovery.WiFiDirectServicesList.WiFiDevicesAdapter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class WiFiServiceDiscoveryActivity extends Activity implements
DeviceClickListener, Handler.Callback, MessageTarget,
ConnectionInfoListener {
public static final String TAG = "wifidirectdemo";
// TXT RECORD properties
public static final String TXTRECORD_PROP_AVAILABLE = "available";
public static final String SERVICE_INSTANCE = "_wifidemotest";
public static final String SERVICE_REG_TYPE = "_presence._tcp";
public static final int MESSAGE_READ = 0x400 + 1;
public static final int MY_HANDLE = 0x400 + 2;
private WifiP2pManager manager;
static final int SERVER_PORT = 4545;
private final IntentFilter intentFilter = new IntentFilter();
private Channel channel;
private BroadcastReceiver receiver = null;
private WifiP2pDnsSdServiceRequest serviceRequest;
private Handler handler = new Handler(this);
private WiFiChatFragment chatFragment;
private WiFiDirectServicesList servicesList;
private TextView statusTxtView;
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
statusTxtView = (TextView) findViewById(R.id.status_text);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
intentFilter
.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
manager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
channel = manager.initialize(this, getMainLooper(), null);
startRegistrationAndDiscovery();
servicesList = new WiFiDirectServicesList();
getFragmentManager().beginTransaction()
.add(R.id.container_root, servicesList, "services").commit();
}
#Override
protected void onRestart() {
Fragment frag = getFragmentManager().findFragmentByTag("services");
if (frag != null) {
getFragmentManager().beginTransaction().remove(frag).commit();
}
super.onRestart();
}
#Override
protected void onStop() {
if (manager != null && channel != null) {
manager.removeGroup(channel, new ActionListener() {
#Override
public void onFailure(int reasonCode) {
Log.d(TAG, "Disconnect failed. Reason :" + reasonCode);
}
#Override
public void onSuccess() {
}
});
}
super.onStop();
}
/**
* Registers a local service and then initiates a service discovery
*/
private void startRegistrationAndDiscovery() {
Map<String, String> record = new HashMap<String, String>();
record.put(TXTRECORD_PROP_AVAILABLE, "visible");
WifiP2pDnsSdServiceInfo service = WifiP2pDnsSdServiceInfo.newInstance(
SERVICE_INSTANCE, SERVICE_REG_TYPE, record);
manager.addLocalService(channel, service, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added Local Service");
}
#Override
public void onFailure(int error) {
appendStatus("Failed to add a service");
}
});
discoverService();
}
private void discoverService() {
/*
* Register listeners for DNS-SD services. These are callbacks invoked
* by the system when a service is actually discovered.
*/
manager.setDnsSdResponseListeners(channel,
new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName,
String registrationType, WifiP2pDevice srcDevice) {
// A service has been discovered. Is this our app?
if (instanceName.equalsIgnoreCase(SERVICE_INSTANCE)) {
// update the UI and add the item the discovered
// device.
WiFiDirectServicesList fragment = (WiFiDirectServicesList) getFragmentManager()
.findFragmentByTag("services");
if (fragment != null) {
WiFiDevicesAdapter adapter = ((WiFiDevicesAdapter) fragment
.getListAdapter());
WiFiP2pService service = new WiFiP2pService();
service.device = srcDevice;
service.instanceName = instanceName;
service.serviceRegistrationType = registrationType;
adapter.add(service);
adapter.notifyDataSetChanged();
Log.d(TAG, "onBonjourServiceAvailable "
+ instanceName);
}
}
}
}, new DnsSdTxtRecordListener() {
/**
* A new TXT record is available. Pick up the advertised
* buddy name.
*/
#Override
public void onDnsSdTxtRecordAvailable(
String fullDomainName, Map<String, String> record,
WifiP2pDevice device) {
Log.d(TAG,
device.deviceName + " is "
+ record.get(TXTRECORD_PROP_AVAILABLE));
}
});
// After attaching listeners, create a service request and initiate
// discovery.
serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
manager.addServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Added service discovery request");
}
#Override
public void onFailure(int arg0) {
appendStatus("Failed adding service discovery request");
}
});
manager.discoverServices(channel, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Service discovery initiated");
}
#Override
public void onFailure(int arg0) {
appendStatus("Service discovery failed");
}
});
}
#Override
public void connectP2p(WiFiP2pService service) {
WifiP2pConfig config = new WifiP2pConfig();
config.deviceAddress = service.device.deviceAddress;
config.wps.setup = WpsInfo.PBC;
if (serviceRequest != null)
manager.removeServiceRequest(channel, serviceRequest,
new ActionListener() {
#Override
public void onSuccess() {
}
#Override
public void onFailure(int arg0) {
}
});
manager.connect(channel, config, new ActionListener() {
#Override
public void onSuccess() {
appendStatus("Connecting to service");
}
#Override
public void onFailure(int errorCode) {
appendStatus("Failed connecting to service");
}
});
}
#Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// construct a string from the valid bytes in the buffer
String readMessage = new String(readBuf, 0, msg.arg1);
Log.d(TAG, readMessage);
(chatFragment).pushMessage("Buddy: " + readMessage);
break;
case MY_HANDLE:
Object obj = msg.obj;
(chatFragment).setChatManager((ChatManager) obj);
}
return true;
}
#Override
public void onResume() {
super.onResume();
receiver = new WiFiDirectBroadcastReceiver(manager, channel, this);
registerReceiver(receiver, intentFilter);
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(receiver);
}
#Override
public void onConnectionInfoAvailable(WifiP2pInfo p2pInfo) {
Thread handler = null;
/*
* The group owner accepts connections using a server socket and then spawns a
* client socket for every client. This is handled by {#code
* GroupOwnerSocketHandler}
*/
if (p2pInfo.isGroupOwner) {
Log.d(TAG, "Connected as group owner");
try {
handler = new GroupOwnerSocketHandler(
((MessageTarget) this).getHandler());
handler.start();
} catch (IOException e) {
Log.d(TAG,
"Failed to create a server thread - " + e.getMessage());
return;
}
} else {
Log.d(TAG, "Connected as peer");
handler = new ClientSocketHandler(
((MessageTarget) this).getHandler(),
p2pInfo.groupOwnerAddress);
handler.start();
}
chatFragment = new WiFiChatFragment();
getFragmentManager().beginTransaction()
.replace(R.id.container_root, chatFragment).commit();
statusTxtView.setVisibility(View.GONE);
}
public void appendStatus(String status) {
String current = statusTxtView.getText().toString();
statusTxtView.setText(current + "\n" + status);
}
}
And the file for your AndroidManifast.xml should be the same and give these accesses
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="16" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Google Play filtering -->
<uses-feature android:name="android.hardware.wifi.direct" android:required="true"/>
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".WiFiServiceDiscoveryActivity"
android:label="#string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
If you have any questions, let me respond as quickly as possible
SOURCE
WiFiDirectServiceDiscovery
I am Working with Reading NDEF Msg and Records
Here I have done with Reading ID by using this
public class MainActivity extends Activity {
// list of NFC technologies detected:
private final String[][] techList = new String[][] {
new String[] {
NfcA.class.getName(),
NfcB.class.getName(),
NfcF.class.getName(),
NfcV.class.getName(),
IsoDep.class.getName(),
MifareClassic.class.getName(),
MifareUltralight.class.getName(), Ndef.class.getName()
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
}
#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_activity, menu);
return true;
}
#Override
protected void onResume() {
super.onResume();
// creating pending intent:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// creating intent receiver for NFC events:
IntentFilter filter = new IntentFilter();
filter.addAction(NfcAdapter.ACTION_TAG_DISCOVERED);
filter.addAction(NfcAdapter.ACTION_NDEF_DISCOVERED);
filter.addAction(NfcAdapter.ACTION_TECH_DISCOVERED);
// enabling foreground dispatch for getting intent from NFC event:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.enableForegroundDispatch(this, pendingIntent, new IntentFilter[]{filter}, this.techList);
}
#Override
protected void onPause() {
super.onPause();
// disabling foreground dispatch:
NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
nfcAdapter.disableForegroundDispatch(this);
}
#Override
protected void onNewIntent(Intent intent) {
if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED) || intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED) || intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
((TextView)findViewById(R.id.text)).setText(
"NFC Tag\n" +
ByteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID)));
}
}
private String ByteArrayToHexString(byte [] inarray) {
int i, j, in;
String [] hex = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"};
String out= "";
for(j = 0 ; j < inarray.length ; ++j)
{
in = (int) inarray[j] & 0xff;
i = (in >> 4) & 0x0f;
out += hex[i];
i = in & 0x0f;
out += hex[i];
}
return out;
}
}
Here Reading Tag ID which is Record[0]
In the Similar way I want to Read NDEF msg and Records both in the same Program and Same way... We have many ways
Here I have tried with
if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Ndef ndef = Ndef.get(tag);
if (ndef == null) {
// NDEF is not supported by this Tag.
return;
}
NdefMessage ndefMessage = ndef.getCachedNdefMessage();
NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) {
//read each record
}
But I am Unable to read Records.. can any one suggest me to Read NDEF msg and records in my code....
Update
I have added this at manifest..
<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"/>
<data android:mimeType="text/plain" />
<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>
<meta-data
android:name="android.nfc.action.TAG_DISCOVERED"
android:resource="#xml/nfc_tech_filter" />
But Still I need to go with NfcAdapter.EXTRA_NDEF_MESSAGES can any one tell me How to use it in my code with out effecting or changing NfcAdapter.EXTRA_ID.
Add log to understand what happens.
Get NDEFMessage from tag in Intent
Your function to convert ByteArray to Hex string is not the best
And please read official documentation, all you need is explained:http://developer.android.com/guide/topics/connectivity/nfc/nfc.html#obtain-info
In your Activity, method onNewIntent:
#Override
protected void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent action=" + intent.getAction());
if (intent.getAction().equals(NfcAdapter.ACTION_TAG_DISCOVERED) || intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED) || intent.getAction().equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
((TextView)findViewById(R.id.text)).setText(
"NFC Tag\n" +
byteArrayToHexString(intent.getByteArrayExtra(NfcAdapter.EXTRA_ID)));
}
if (intent.getAction().equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
if (rawMsgs != null) {
for (int i = 0; i < rawMsgs.length; i++) {
NdefMessage ndefMessage = (NdefMessage) rawMsgs[i];
NdefRecord[] records = ndefMessage.getRecords();
for (NdefRecord ndefRecord : records) {
//read each record
}
}
}
}
}
/**
* convert byte array to a hexadecimal string
*
* #param bArray
* byte array to convert
* #return hexadecimal string
*/
public static String byteArrayToHexString(byte[] bArray) {
StringBuffer buffer = new StringBuffer();
for (byte b : bArray) {
buffer.append(byteToHexString(b));
buffer.append(" ");
}
return buffer.toString().toUpperCase(Locale.getDefault());
}
/**
* convert byte to a hexadecimal string
*
* #param b
* byte to convert
* #return hexadecimal string
*/
public static String byteToHexString(byte b) {
int tmp = b & 0xFF;
if (tmp <= 15) {
return "0".concat(Integer.toHexString(tmp));
} else {
return Integer.toHexString(tmp);
}
}
I've got a problem with my IntentService - my intention is to outsource the networking and processing from the activity (I previously used an AsyncTask which worked excellent, however I also want to extend it to a widget).
The thing is, I don't get any result from the service - it almost seems like it never gets called (or something is wrong in the code that's supposed to retreive the data)...
Can someone with more experience in using services than me take a look and spot the obvious (or hidden) errors I've made?
Would be greatly appreciated!
Contents of the service:
public class StateCheckerService extends IntentService {
public StateCheckerService() {
super("StateCheckerService");
// TODO Auto-generated constructor stub
}
String pageContent;
public static final String API_URL = "http://omegav.no/api/dooropen.php", INTENT_ACTION="omegavdoor.FETCH_COMPLETE", EXTRA_STATUS="status", EXTRA_TIME="time", KEY_STATUS="";
SharedPreferences settings;
private int timeMins = 0, timeoutMillis = 5000, resultCode;
int status_code = 0;
public void onCreate() {
super.onCreate();
// Declares the SharedPreferences object to use
settings = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(null, resultCode, resultCode);
return START_FLAG_RETRY;
}
#Override
protected void onHandleIntent(Intent intent) {
// TODO Auto-generated method stub
if (checkConnection()) {
// Start process of retrieving status
try {
getData();
} catch (IOException e) {
returnResult(11);
} finally {
returnResult(resultCode);
}
} else {
// Notify the user of missing connection
returnResult(0); // Error: connection unavailable
}
}
private boolean checkConnection() {
// Declare connection manager and NetworkInfo objects
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
// Check network connection
if (activeInfo != null && activeInfo.isConnected()) {
return true;
} else {
return false;
}
}
/** Function to get data from the remote server */
public void getData() throws IOException {
// Create URL object to connect to
URL url = new URL(API_URL);
// Open new HTTP connection
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
// Set a connection timeout to prevent app lockup if it can't reach the server
urlConnection.setConnectTimeout(timeoutMillis);
// Attempt to connect and retrieve data
try { // Return exception if the stream is unreachable
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
// Process the contents of the stream
readStream(in);
}
finally {
// Disconnect after retrieving data
urlConnection.disconnect();
}
}
public void readStream(InputStream input) throws IOException {
// Reads the content of the page
try {
// String length varies with the time value - read some extra to avoid missing the end
pageContent = readIt(input, 40);
// Remove the extra white spaces at the end
} catch (UnsupportedEncodingException e) {
resultCode = 10;
}
if (pageContent == null) {
// Stop further processing (and cause the UI to report error)
resultCode = 13;
} else {
// Checks to see whether the "open" flag exists
if (pageContent.charAt(9) == '1') {
// Find out how long it's been open
int openTime = Integer.parseInt(pageContent.substring(20, pageContent.lastIndexOf("}")));
// Convert from seconds to minutes
timeMins = openTime / 60;
if (timeMins > 0) {
resultCode = 1; // Display how long it's been open
} else {
resultCode = 2; // If it just opened
}
} else {
// Find out how long it's been closed
int closedTime = Integer.parseInt(pageContent.substring(19, pageContent.lastIndexOf("}"))); // TODO: change 19 to 20 to support the API change
// Convert from seconds to minutes
timeMins = closedTime / 60;
if (timeMins > 0) {
resultCode = 3; // Display how long it's been open
} else {
resultCode = 4; // If it just closed
}
}
}
}
// Reads an InputStream and converts it to a String.
public String readIt(InputStream stream, int len) throws IOException, UnsupportedEncodingException {
// Initialize reader object
Reader reader = null;
// Decode the input stream
reader = new InputStreamReader(stream, "UTF-8");
char[] buffer = new char[len];
reader.read(buffer);
return new String(buffer);
}
private void returnResult(int resultCode) {
Intent resultIntent = new Intent();
resultIntent.setAction(INTENT_ACTION);
resultIntent.putExtra(EXTRA_STATUS, resultCode)
.putExtra(EXTRA_TIME, timeMins);
}
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
}
Contents of the calling activity:
public class StateChecker extends Activity {
String pageContent;
boolean doorIsOpen = false, notFirstRun = false, error = false;
private static final int transitionDuration = 250;
private ResponseReceiver receiver;
TransitionDrawable transition;
TextView text_doorState;
Button button_getState;
ProgressBar door_progress;
LinearLayout background;
int timeMins;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate the XML layout
setContentView(R.layout.state_checker);
// Declare the views to be adressed
text_doorState = (TextView) findViewById(R.id.tv_doorState);
button_getState = (Button) findViewById(R.id.button_refreshState);
door_progress = (ProgressBar) findViewById(R.id.doorState_progressBar);
background = (LinearLayout) findViewById(R.id.doorStateView);
IntentFilter filter = new IntentFilter(ResponseReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new ResponseReceiver();
registerReceiver(receiver, filter);
}
/** Receiver class to listen to and handle result from checker service */
public class ResponseReceiver extends BroadcastReceiver {
public static final String ACTION_RESP = StateCheckerService.INTENT_ACTION;
#Override
public void onReceive(Context context, Intent intent) {
int result = intent.getIntExtra(StateCheckerService.EXTRA_STATUS, 0);
timeMins = intent.getIntExtra(StateCheckerService.EXTRA_TIME, 0);
Toast.makeText(context, "Result received", Toast.LENGTH_SHORT).show();
processResult(result);
}
}
public void onStart() {
super.onStart();
// Checks the door status on app launch
go();
}
public void onStop() {
super.onStop();
unregisterReceiver(receiver);
}
private void go() {
// Update text and progress bar to indicate it's working
text_doorState.setText(R.string.text_stateUpdating);
door_progress.setVisibility(View.VISIBLE);
// Fade the color back to grey if it is something else
if (notFirstRun) {
transition.reverseTransition(transitionDuration);
}
if (checkConnection()) {
Intent intent = new Intent(this, StateCheckerService.class);
startService(intent);
notify("service started");
} else {
// Notify the user of missing connection
notify(getString(R.string.error_connection_unavailable));
}
}
private boolean checkConnection() {
// Declare connection manager and NetworkInfo objects
ConnectivityManager connMgr = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeInfo = connMgr.getActiveNetworkInfo();
// Check network connection
if (activeInfo != null && activeInfo.isConnected()) {
return true;
} else {
return false;
}
}
protected void processResult(Integer resultCode) {
switch (resultCode) {
case 1:
if (timeMins < 60) {
// Notify of open door and display minutes
notify(getString(R.string.text_stateOpenMins, timeMins));
} else {
// If it's been more than an hour, display the time in hours
int openTimeHours = timeMins / 60;
int remainder = timeMins - (openTimeHours * 60);
notify(getString(R.string.text_stateOpenHours, openTimeHours, remainder));
}
break;
case 2:
// Notify of open door (just opened)
notify(getString(R.string.text_stateOpenNow));
break;
case 3:
if (timeMins < 60) {
// Notify of closed door and display minutes
notify(getString(R.string.text_stateClosedMins, timeMins));
} else {
// If it's been more than an hour, display the time in hours
int closedTimeHours = timeMins / 60;
int remainder = timeMins - (closedTimeHours * 60);
notify(getString(R.string.text_stateClosedHours, closedTimeHours, remainder));
}
break;
case 4:
// Notify of closed door (just closed
notify(getString(R.string.text_stateClosedNow));
break;
case 10:
// Error message: unsupported stream format
notify(getString(R.string.error_stream_unsupported));
break;
case 11:
// Error message: connection failed
notify(getString(R.string.error_connection_failed));
break;
// Case 12 reserved
case 13:
// Error message: null data stream
notify(getString(R.string.error_stream_retrieve));
break;
}
if (resultCode >= 10) {
error = true;
} else {
error = false;
}
updateDisplay();
}
protected void updateDisplay() {
door_progress.setVisibility(View.GONE);
if (!error) {
/** Update the UI to reflect the door state */
if(doorIsOpen) {
// Update the text view to display an open door state
text_doorState.setText(getString(R.string.text_stateOpen));
// Change the background color
background.setBackgroundResource(R.drawable.trans_open);
transition = (TransitionDrawable) background.getBackground();
transition.startTransition(transitionDuration);
} else {
// Update the text view to display a closed door state
text_doorState.setText(getString(R.string.text_stateClosed));
// Change the background color
background.setBackgroundResource(R.drawable.trans_close);
transition = (TransitionDrawable) background.getBackground();
transition.startTransition(transitionDuration);
}
// Indicates that the app has gone through a successful execution
notFirstRun = true;
} else {
// If it failed to execute, display error message
text_doorState.setText(R.string.text_stateFailed);
// Revert to grey background
background.setBackgroundResource(R.drawable.background);
}
}
/** Helper class used to display toast notifications */
private void notify(String message) {
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
Edit (AndroidManifest):
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="tovine.omegavdoor.widget"
android:versionCode="5"
android:versionName="1.0.1" >
<uses-sdk
android:minSdkVersion="7"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:name=".Settings"
android:label="#string/title_activity_settings" >
</activity>
<activity
android:name=".StateChecker"
android:configChanges="orientation|screenSize"
android:title="#string/app_name"
android:windowSoftInputMode="stateAlwaysHidden" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.google.ads.AdActivity"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|uiMode|screenSize|smallestScreenSize" />
<receiver
android:name=".WidgetStateProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="omegavdoor.FETCH_COMPLETE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/doorwidget" />
</receiver>
<service android:name="tovine.omegavdoor.widget.WidgetUpdateService">
<intent-filter>
<action android:name="omegavdoor.FETCH_COMPLETE" />
</intent-filter>
</service>
<service android:name="tovine.omegavdoor.widget.StateCheckerService"
android:process=":checker_process">
</service>
-->
<!-- <activity
android:name="Probability"
android:label="#string/title_activity_probability" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="StateChecker" />
</activity>
<activity
android:name=".LoadWebImg"
android:label="TestClass" /> -->
</application>
</manifest>
I can be wrong but it seems your returnResult() function doesn't send anything. Maybe you forgot to add sendBroadcst(resultIntent); call to it?
For intent service we does not need to implement/override the method onStartCommand
So remove the following coding
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(null, resultCode, resultCode);
return START_FLAG_RETRY;
}
from the "Contents of the service"
Then try it.
I am sure this is simple but I cannot figure it out. All I am trying to do is send a message via NFC. The code I have work perfectly if I am sending it to the main activity, but I don't know how to send it to a different activity. I have looked over both the NFC and Intent Filter articles on the Android Developer pages but am still not sure exactly how to do this. I am trying to send it to a NFC activity, I will post my manifest and NFC class below.
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.justbaumdev.tagsense"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.NFC" />
<uses-feature android:name="android.hardware.nfc" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.Holo" >
<activity
android:name=".TagSense"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="com.justbaumdev.tagsense.NFC" android:exported="false">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/com.justbaumdev.tagsense" />
</intent-filter>
</activity>
</application>
</manifest>
NFC Class:
package com.justbaumdev.tagsense;
import org.json.JSONArray;
import org.json.JSONException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.wifi.WifiManager;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcAdapter.OnNdefPushCompleteCallback;
import android.nfc.NfcEvent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.widget.Toast;
public class NFC extends Activity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback {
private NfcAdapter mNfcAdapter;
private static final int MESSAGE_SENT = 1;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.nfc);
mNfcAdapter = NfcAdapter.getDefaultAdapter(this); // Check for available NFC Adapter
if (mNfcAdapter == null)
{
Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
finish();
return;
}
else
{
mNfcAdapter.setNdefPushMessageCallback(this, this); // Register callback to set NDEF message
mNfcAdapter.setOnNdefPushCompleteCallback(this, this); // Register callback to listen for message-sent success
}
}
#Override
public void onResume() {
super.onResume();
// Check to see that the Activity started due to an Android Beam
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
processIntent(getIntent());
}
}
#Override
public void onNewIntent(Intent intent) {
// onResume gets called after this to handle the intent
setIntent(intent);
}
#Override
public NdefMessage createNdefMessage(NfcEvent event) {
WifiManager wm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
String mac = wm.getConnectionInfo().getMacAddress();
String newMac = mac.substring(0, 2);
mac = mac.substring(2);
int hex = Integer.parseInt(newMac, 16) + 0x2;
newMac = Integer.toHexString(hex);
String text = newMac + mac;
NdefMessage msg = new NdefMessage(NdefRecord.createMime(
"application/com.justbaumdev.tagsense", text.getBytes()));
return msg;
}
/**
* Implementation for the OnNdefPushCompleteCallback interface
*/
#Override
public void onNdefPushComplete(NfcEvent arg0) {
// A handler is needed to send messages to the activity when this
// callback occurs, because it happens from a binder thread
mHandler.obtainMessage(MESSAGE_SENT).sendToTarget();
}
/** This handler receives a message from onNdefPushComplete */
private final Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_SENT:
Toast.makeText(getApplicationContext(), "Message sent!", Toast.LENGTH_LONG).show();
break;
}
}
};
/**
* Parses the NDEF Message from the intent and prints to the TextView
*/
//TODO Currently overwrites any previously saved mac addresses. Get FB ID as value. Auto end activity.
void processIntent(Intent intent) {
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
// only one message sent during the beam
NdefMessage msg = (NdefMessage) rawMsgs[0];
// record 0 contains the MIME type, record 1 is the AAR, if present
//textView.setText(new String(msg.getRecords()[0].getPayload()));
String payload = new String(msg.getRecords()[0].getPayload());
Toast.makeText(this, new String(msg.getRecords()[0].getPayload()), Toast.LENGTH_LONG).show();
SharedPreferences appData = getSharedPreferences("appData", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = appData.edit();
String addresses = appData.getString("mac_address", null);
if(addresses==null)
{
JSONArray addressArray = new JSONArray();
addressArray.put(payload);
addresses = addressArray.toString();
}
else
{
try {
if(!addresses.contains(payload))
{
JSONArray addressArray = new JSONArray(addresses);
addressArray.put(payload);
addresses = addressArray.toString();
}
} catch (JSONException e) {
Toast.makeText(this, "Error adding new friend. Please try again.", Toast.LENGTH_SHORT).show();
}
}
editor.putString("mac_address", addresses);
editor.commit();
}
}
Thanks for your help.
Remove the attribute android:exported="false". See also https://stackoverflow.com/a/12719621/1202968