Send address book contacts between devices via NFC
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
android:versionName="0.1.1" >
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.NFC" />
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="9"
|
||||
@@ -69,6 +70,16 @@
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value="i2p.bote.android.addressbook.AddressBookActivity" />
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.NDEF_DISCOVERED" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="vnd.android.nfc"
|
||||
android:host="ext"
|
||||
android:pathPrefix="/i2p.bote:contact"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".NetworkInfoActivity"
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
package i2p.bote.android.addressbook;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Intent;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
import android.nfc.NfcAdapter;
|
||||
import android.nfc.NfcEvent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
|
||||
import i2p.bote.android.InitActivities;
|
||||
|
||||
public class EditContactActivity extends ActionBarActivity {
|
||||
NfcAdapter mNfcAdapter;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -24,7 +35,82 @@ public class EditContactActivity extends ActionBarActivity {
|
||||
destination = args.getString(EditContactFragment.CONTACT_DESTINATION);
|
||||
EditContactFragment f = EditContactFragment.newInstance(destination);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.add(android.R.id.content, f).commit();
|
||||
.add(android.R.id.content, f).commit();
|
||||
}
|
||||
|
||||
// NFC send only works on API 10+
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD_MR1) {
|
||||
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
|
||||
if (mNfcAdapter != null &&
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH)
|
||||
mNfcAdapter.setNdefPushMessageCallback(new NfcAdapter.CreateNdefMessageCallback() {
|
||||
@Override
|
||||
public NdefMessage createNdefMessage(NfcEvent nfcEvent) {
|
||||
return getNdefMessage();
|
||||
}
|
||||
}, this);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
if (mNfcAdapter != null &&
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
mNfcAdapter.enableForegroundNdefPush(this, getNdefMessage());
|
||||
}
|
||||
|
||||
// Check to see that the Activity started due to an Android Beam
|
||||
if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction()) ||
|
||||
NfcAdapter.ACTION_TAG_DISCOVERED.equals(getIntent().getAction())) {
|
||||
processIntent(getIntent());
|
||||
}
|
||||
}
|
||||
|
||||
private NdefMessage getNdefMessage() {
|
||||
EditContactFragment f = (EditContactFragment) getSupportFragmentManager()
|
||||
.findFragmentById(android.R.id.content);
|
||||
return f.createNdefMessage();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewIntent(Intent intent) {
|
||||
// onResume gets called after this to handle the intent
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the NDEF Message from the intent
|
||||
*/
|
||||
void processIntent(Intent intent) {
|
||||
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(
|
||||
NfcAdapter.EXTRA_NDEF_MESSAGES);
|
||||
if (rawMsgs == null || rawMsgs.length < 1)
|
||||
return; // TODO notify user?
|
||||
NdefMessage msg = (NdefMessage) rawMsgs[0];
|
||||
|
||||
NdefRecord[] records = msg.getRecords();
|
||||
if (records.length != 2)
|
||||
return; // TODO notify user?
|
||||
String name = new String(records[0].getPayload());
|
||||
String destination = new String(records[1].getPayload());
|
||||
|
||||
EditContactFragment f = EditContactFragment.newInstance(
|
||||
name, destination);
|
||||
getSupportFragmentManager().beginTransaction()
|
||||
.replace(android.R.id.content, f).commit();
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
if (mNfcAdapter != null &&
|
||||
Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
mNfcAdapter.disableForegroundNdefPush(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
package i2p.bote.android.addressbook;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.nfc.NdefMessage;
|
||||
import android.nfc.NdefRecord;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -13,35 +35,18 @@ import i2p.bote.android.util.BoteHelper;
|
||||
import i2p.bote.android.util.EditPictureFragment;
|
||||
import i2p.bote.fileencryption.PasswordException;
|
||||
import i2p.bote.packet.dht.Contact;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class EditContactFragment extends EditPictureFragment {
|
||||
public static final String CONTACT_DESTINATION = "contact_destination";
|
||||
public static final String NEW_NAME = "new_name";
|
||||
public static final String NEW_DESTINATION = "new_destination";
|
||||
|
||||
static final int REQUEST_DESTINATION_FILE = 3;
|
||||
|
||||
private String mDestination;
|
||||
EditText mNameField;
|
||||
EditText mDestinationField;
|
||||
EditText mTextField;
|
||||
TextView mError;
|
||||
private String mDestination;
|
||||
|
||||
public static EditContactFragment newInstance(String destination) {
|
||||
EditContactFragment f = new EditContactFragment();
|
||||
@@ -51,6 +56,15 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
return f;
|
||||
}
|
||||
|
||||
public static EditContactFragment newInstance(String name, String destination) {
|
||||
EditContactFragment f = new EditContactFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(NEW_NAME, name);
|
||||
args.putString(NEW_DESTINATION, destination);
|
||||
f.setArguments(args);
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
@@ -59,7 +73,7 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_edit_contact, container, false);
|
||||
}
|
||||
|
||||
@@ -68,6 +82,7 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
mDestination = getArguments().getString(CONTACT_DESTINATION);
|
||||
String newName = getArguments().getString(NEW_NAME);
|
||||
|
||||
mNameField = (EditText) view.findViewById(R.id.contact_name);
|
||||
mDestinationField = (EditText) view.findViewById(R.id.destination);
|
||||
@@ -90,6 +105,9 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
// TODO Handle
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else if (newName != null) {
|
||||
mNameField.setText(newName);
|
||||
mDestinationField.setText(getArguments().getString(NEW_DESTINATION));
|
||||
}
|
||||
|
||||
Button b = (Button) view.findViewById(R.id.import_destination_from_file);
|
||||
@@ -100,7 +118,7 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
i.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
try {
|
||||
startActivityForResult(
|
||||
Intent.createChooser(i,"Select file containing Email Destination"),
|
||||
Intent.createChooser(i, "Select file containing Email Destination"),
|
||||
REQUEST_DESTINATION_FILE);
|
||||
} catch (android.content.ActivityNotFoundException ex) {
|
||||
Toast.makeText(getActivity(), "Please install a File Manager.",
|
||||
@@ -110,6 +128,42 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
});
|
||||
}
|
||||
|
||||
public NdefMessage createNdefMessage() {
|
||||
NdefMessage msg = new NdefMessage(new NdefRecord[]{
|
||||
createNameRecord(),
|
||||
createDestinationRecord()
|
||||
});
|
||||
return msg;
|
||||
}
|
||||
|
||||
private NdefRecord createNameRecord() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
||||
return new NdefRecord(
|
||||
NdefRecord.TNF_EXTERNAL_TYPE,
|
||||
"i2p.bote:contact".getBytes(),
|
||||
new byte[0],
|
||||
mNameField.getText().toString().getBytes()
|
||||
);
|
||||
else
|
||||
return NdefRecord.createExternal(
|
||||
"i2p.bote", "contact", mNameField.getText().toString().getBytes()
|
||||
);
|
||||
}
|
||||
|
||||
private NdefRecord createDestinationRecord() {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN)
|
||||
return new NdefRecord(
|
||||
NdefRecord.TNF_EXTERNAL_TYPE,
|
||||
"i2p.bote:contactDestination".getBytes(),
|
||||
new byte[0],
|
||||
mDestinationField.getText().toString().getBytes()
|
||||
);
|
||||
else
|
||||
return NdefRecord.createExternal(
|
||||
"i2p.bote", "contactDestination", mDestinationField.getText().toString().getBytes()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.edit_contact, menu);
|
||||
@@ -118,70 +172,70 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case R.id.action_save_contact:
|
||||
String picture = getPictureB64();
|
||||
String name = mNameField.getText().toString();
|
||||
String destination = mDestinationField.getText().toString();
|
||||
String text = mTextField.getText().toString();
|
||||
case R.id.action_save_contact:
|
||||
String picture = getPictureB64();
|
||||
String name = mNameField.getText().toString();
|
||||
String destination = mDestinationField.getText().toString();
|
||||
String text = mTextField.getText().toString();
|
||||
|
||||
mError.setText("");
|
||||
mError.setText("");
|
||||
|
||||
try {
|
||||
String err = BoteHelper.saveContact(destination, name, picture, text);
|
||||
if (err == null) {
|
||||
if (mDestination == null) // Only set if adding new contact
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else
|
||||
mError.setText(err);
|
||||
} catch (PasswordException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
mError.setText(e.getLocalizedMessage());
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
mError.setText(e.getLocalizedMessage());
|
||||
}
|
||||
return true;
|
||||
|
||||
case R.id.action_delete_contact:
|
||||
DialogFragment df = new DialogFragment() {
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage(R.string.delete_contact)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
try {
|
||||
String err = BoteHelper.deleteContact(mDestination);
|
||||
if (err == null) {
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else
|
||||
mError.setText(err);
|
||||
} catch (PasswordException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
try {
|
||||
String err = BoteHelper.saveContact(destination, name, picture, text);
|
||||
if (err == null) {
|
||||
if (mDestination == null) // Only set if adding new contact
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else
|
||||
mError.setText(err);
|
||||
} catch (PasswordException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
mError.setText(e.getLocalizedMessage());
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
mError.setText(e.getLocalizedMessage());
|
||||
}
|
||||
};
|
||||
df.show(getActivity().getSupportFragmentManager(), "deletecontact");
|
||||
return true;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
case R.id.action_delete_contact:
|
||||
DialogFragment df = new DialogFragment() {
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setMessage(R.string.delete_contact)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
try {
|
||||
String err = BoteHelper.deleteContact(mDestination);
|
||||
if (err == null) {
|
||||
getActivity().setResult(Activity.RESULT_OK);
|
||||
getActivity().finish();
|
||||
} else
|
||||
mError.setText(err);
|
||||
} catch (PasswordException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
} catch (GeneralSecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
return builder.create();
|
||||
}
|
||||
};
|
||||
df.show(getActivity().getSupportFragmentManager(), "deletecontact");
|
||||
return true;
|
||||
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +250,8 @@ public class EditContactFragment extends EditPictureFragment {
|
||||
try {
|
||||
br = new BufferedReader(
|
||||
new InputStreamReader(
|
||||
new FileInputStream(file)));
|
||||
new FileInputStream(file))
|
||||
);
|
||||
try {
|
||||
mDestinationField.setText(br.readLine());
|
||||
} catch (IOException ioe) {
|
||||
|
||||
Reference in New Issue
Block a user