I'm new to NFC with Android and I'm trying to make a kind of messaging app with NFC.
I have a first activity that sends the content of an EditText view to the other phone when beaming and displays the incoming message on a TextView on the other phone. This works fine.
I have another activity which is used to add a contact to the contacts register, it should work as the following:
- A wants to add B as a contact,
- A goes to the AddContactActivity, enters the name of the contact in the EditText view,
- then B touches A's phone (on the same activity) and sends their identifier (public key, for further encryption).
My problem is that even though the code concerning the sending via NFC is basically the same between the two activities, when I beam on the second activity (AddContactActivity), the action of the intent sent is ACTION_MAIN
instead of ACTION_NDEF_DISCOVERED
, which has the effect of opening the first activity and thus not going through the right treatment.
Here is the code of the MainActivity:
public class MainActivity extends Activity {
private TextView mTextView;
private EditText mEdit;
NfcAdapter nfcAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = getIntent();
mTextView = (TextView)findViewById(R.id.retour);
mEdit = (EditText)findViewById(R.id.editText);
nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
@Override public NdefMessage createNdefMessage(NfcEvent event) {
String stringOut = mEdit.getText().toString();
byte[] bytesOut = stringOut.getBytes();
NdefRecord ndefRecordOut = new NdefRecord(
NdefRecord.TNF_MIME_MEDIA,
"text/plain".getBytes(),
new byte[] {},
bytesOut);
NdefMessage ndefMessageout = new NdefMessage(ndefRecordOut);
return ndefMessageout;
}
}, this);
checkAndProcessBeamIntent(intent);
}
@Override
public void onResume() {
super.onResume();
Intent intent = getIntent();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("text/plain");
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
}
private void checkAndProcessBeamIntent(Intent intent) {
String action = intent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
Parcelable[] parcelables =
intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
NdefRecord NdefRecord_0 = inNdefRecords[0];
String inMsg = new String(NdefRecord_0.getPayload());
mTextView.setText(inMsg);
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Toast.makeText(MainActivity.this,
intent.getAction().toString(),
Toast.LENGTH_LONG).show();
checkAndProcessBeamIntent(intent);
}
@Override
public void onPause() {
super.onPause();
nfcAdapter.disableForegroundDispatch(this);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public void generateKeys(){
Calendar cal = Calendar.getInstance();
Date now = cal.getTime();
cal.add(Calendar.YEAR, 1);
Date end = cal.getTime();
KeyPairGenerator kpg = null;
try {
kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
try {
kpg.initialize(new KeyPairGeneratorSpec.Builder(getApplicationContext())
.setAlias("Keys")
.setStartDate(now)
.setEndDate(end)
.setSerialNumber(BigInteger.valueOf(1))
.setSubject(new X500Principal("CN=test1"))
.build());
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
}
kpg.generateKeyPair();
}
public void goToAddContact(View view) {
Intent intent = new Intent(this, AddContactActivity.class);
intent.setAction("NewActivity");
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
}
Here is the code of the AddContactActivity:
public class AddContactActivity extends Activity{
NfcAdapter nfcAdapter;
EditText editText;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_contact);
editText = (EditText)findViewById(R.id.editText);
nfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
Intent intent = getIntent();
nfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
@Override public NdefMessage createNdefMessage(NfcEvent event) {
String stringOut = getMyPublicKey();
byte[] bytesOut = stringOut.getBytes();
NdefRecord ndefRecordOut = new NdefRecord(
NdefRecord.TNF_MIME_MEDIA,
"text/plain".getBytes(),
new byte[] {},
bytesOut);
NdefMessage ndefMessageout = new NdefMessage(ndefRecordOut);
return ndefMessageout;
}
}, this);
checkAndProcessBeamIntent(intent);
}
@Override
public void onResume() {
super.onResume();
Intent intent = getIntent();
Toast.makeText(AddContactActivity.this,
"onResume : "+intent.getAction().toString(),
Toast.LENGTH_LONG).show();
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("text/plain");
} catch (IntentFilter.MalformedMimeTypeException e) {
e.printStackTrace();
}
IntentFilter[] intentFiltersArray = new IntentFilter[] {ndef, };
nfcAdapter.enableForegroundDispatch(this, pendingIntent, intentFiltersArray, null);
}
public void addContactDataBase(String publicKey){
SQLiteHelper sqLiteHelper = new SQLiteHelper(this);
sqLiteHelper.addUser(new User(editText.getText().toString(), publicKey));
}
public void checkUserInDataBase(String publicKey){
SQLiteHelper sqLiteHelper = new SQLiteHelper(this);
User u = sqLiteHelper.getUser(publicKey);
Toast.makeText(AddContactActivity.this,
""+u.getName(),
Toast.LENGTH_LONG).show();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Toast.makeText(AddContactActivity.this,
"OnNewIntent : "+intent.getAction().toString(),
Toast.LENGTH_LONG).show();
checkAndProcessBeamIntent(intent);
}
@Override
public void onPause() {
super.onPause();
nfcAdapter.disableForegroundDispatch(this);
}
private void checkAndProcessBeamIntent(Intent intent) {
String action = intent.getAction();
if(action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)){
Toast.makeText(AddContactActivity.this,
"COUCOU",
Toast.LENGTH_LONG).show();
Parcelable[] parcelables =
intent.getParcelableArrayExtra(
NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage inNdefMessage = (NdefMessage)parcelables[0];
NdefRecord[] inNdefRecords = inNdefMessage.getRecords();
NdefRecord NdefRecord_0 = inNdefRecords[0];
String inMsg = new String(NdefRecord_0.getPayload());
addContactDataBase(inMsg);
checkUserInDataBase(inMsg);
}
}
public String getMyPublicKey(){
KeyStore ks = null;
RSAPublicKey publicKey = null;
try {
ks = KeyStore.getInstance("AndroidKeyStore");
ks.load(null);
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)ks.getEntry("Keys", null);
publicKey = (RSAPublicKey) keyEntry.getCertificate().getPublicKey();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (UnrecoverableEntryException e) {
e.printStackTrace();
}
return publicKey.toString();
}
}
And here is the manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.bsauzet.testnfc" >
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".AddContactActivity"
android:label="@string/title_activity_add_contact"
android:launchMode="singleTop">
<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>
</manifest>