I need to get the information transfered from the NFC READER to my phone to be Arrange in each line wth for eg.Event ID,Event Name,DateTime,Venue.
At the moment when I tap my phone to the reader using my android app,all i get is a string of text.I want to break the text to be able to identify Event Id,EventName,DateTime,Venue to be able to getText seperately for each text to submit to database.
here is my code
package com.techblogon.loginexample;
import java.nio.charset.Charset;
import java.util.Arrays;
import com.techblogon.loginexample.R;
import android.app.Activity;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.nfc.NfcAdapter.CreateNdefMessageCallback;
import android.nfc.NfcAdapter.OnNdefPushCompleteCallback;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Parcelable;
import android.provider.Settings;
import android.text.format.Time;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.TextView;
import android.widget.Toast;
public class UserScreen extends Activity implements CreateNdefMessageCallback, OnNdefPushCompleteCallback{
private static final int MESSAGE_SENT = 1;
NfcAdapter mNfcAdapter;
TextView mInfoText;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.userscreen);
mInfoText = (TextView) findViewById(R.id.textView);
// Check for available NFC Adapter
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
mInfoText = (TextView) findViewById(R.id.textView);
mInfoText.setText("NFC is not available on this device.");
}
// Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(this, this);
// Register callback to listen for message-sent success
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
} #Override
public NdefMessage createNdefMessage(NfcEvent event) {
Time time = new Time();
time.setToNow();
String text = ("Beam me up!\n\n" +
"Beam Time: " + time.format("%H:%M:%S"));
NdefMessage msg = new NdefMessage(
new NdefRecord[] { createMimeRecord("application/com.example.android.beam", text.getBytes()) });
return msg;
}
#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();
Log.w ("Sent",mHandler.obtainMessage(MESSAGE_SENT).toString());
}
/** 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;
}
}
};
#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);
}
// Parses the NDEF Message from the intent and prints to the TextView
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
mInfoText.setText(new String(msg.getRecords()[0].getPayload()));
}
public NdefRecord createMimeRecord(String mimeType, byte[] payload) {
byte[] mimeBytes = mimeType.getBytes(Charset.forName("US-ASCII"));
NdefRecord mimeRecord = new NdefRecord(
NdefRecord.TNF_MIME_MEDIA, mimeBytes, new byte[0], payload);
return mimeRecord;
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// If NFC is not available, we won't be needing this menu
if (mNfcAdapter == null) {
return super.onCreateOptionsMenu(menu);
}
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_settings:
Intent intent = new Intent(Settings.ACTION_NFCSHARING_SETTINGS);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
Try this
textView.setText(string1+System.getProperty ("line.separator")+string2);
Edit : Take two string variable like
String string1 = "Hello";
String string2 = "Android";
then
your_textView.setText(string1 + System.getProperty ("line.separator") + string2);
OR
your_textView.setText("Hello" + System.getProperty ("line.separator") + "Android");
Related
I am completely new to Android and just learned Object-oriented programming. My project requires me to build something on open-source code. I am really struggling with this special case. Two fragments are under activity_main, one of them is TerminalFragment. I added a menuItem (R.id.plot) in it and set if the user clicks this Item that will lead him from TerminalFragment to activity_main2. Due to receive(byte data) and TerminalFragment still on active, the data is still printing out by receiveText.append(TextUtil.toCaretString(msg, newline.length() != 0)); in activity_main.
Now, I want to convert the data to String and send it to activity_main2 for display in recyclerview and plotting graph. I am trying to use putextra and getextra but not sure how to access data from getextra in activity_main2. In my testing, the recyclerview just showed "John". Is something missing in my method? Does anyone have a better idea? Much Appreciated.
TerminalFragment
package de.kai_morich.simple_bluetooth_le_terminal;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.method.ScrollingMovementMethod;
import android.text.style.ForegroundColorSpan;
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.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class TerminalFragment extends Fragment implements ServiceConnection, SerialListener {
private MenuItem menuItem;
private enum Connected { False, Pending, True }
private String deviceAddress;
private SerialService service;
private TextView receiveText;
private TextView sendText;
private TextUtil.HexWatcher hexWatcher;
private Connected connected = Connected.False;
private boolean initialStart = true;
private boolean hexEnabled = false;
private boolean pendingNewline = false;
private String newline = TextUtil.newline_crlf;
private String output;
/*
* Lifecycle
*/
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
//Register with activity
// You must inform the system that your app bar fragment is participating in the population of the options menu.
// tells the system that your fragment would like to receive menu-related callbacks.
setRetainInstance(true);
deviceAddress = getArguments().getString("device");
}
#Override
public void onDestroy() {
if (connected != Connected.False)
disconnect();
getActivity().stopService(new Intent(getActivity(), SerialService.class));
super.onDestroy();
}
#Override
public void onStart() {
super.onStart();
if(service != null)
service.attach(this);
else
getActivity().startService(new Intent(getActivity(), SerialService.class)); // prevents service destroy on unbind from recreated activity caused by orientation change
}
#Override
public void onStop() {
if(service != null && !getActivity().isChangingConfigurations())
service.detach();
super.onStop();
}
#SuppressWarnings("deprecation") // onAttach(context) was added with API 23. onAttach(activity) works for all API versions
#Override
public void onAttach(#NonNull Activity activity) {
super.onAttach(activity);
getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}
#Override
public void onDetach() {
try { getActivity().unbindService(this); } catch(Exception ignored) {}
super.onDetach();
}
#Override
public void onResume() {
super.onResume();
if(initialStart && service != null) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
#Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((SerialService.SerialBinder) binder).getService();
service.attach(this);
if(initialStart && isResumed()) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
#Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
/*
* UI
*/
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_terminal, container, false);
receiveText = view.findViewById(R.id.receive_text); // TextView performance decreases with number of spans
receiveText.setTextColor(getResources().getColor(R.color.colorRecieveText)); // set as default color to reduce number of spans
receiveText.setMovementMethod(ScrollingMovementMethod.getInstance());
sendText = view.findViewById(R.id.send_text);
hexWatcher = new TextUtil.HexWatcher(sendText);
hexWatcher.enable(hexEnabled);
sendText.addTextChangedListener(hexWatcher);
sendText.setHint(hexEnabled ? "HEX mode" : "");
View sendBtn = view.findViewById(R.id.send_btn);
sendBtn.setOnClickListener(v -> send(sendText.getText().toString()));
return view;
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_terminal, menu);
menu.findItem(R.id.hex).setChecked(hexEnabled);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.clear) {
receiveText.setText("");
return true;
} if (id == R.id.plot){
Intent intent = new Intent(getActivity(), MainActivity2.class);
startActivity(intent);
//receive.;
return true;
}else if (id == R.id.newline) {
String[] newlineNames = getResources().getStringArray(R.array.newline_names);
String[] newlineValues = getResources().getStringArray(R.array.newline_values);
int pos = java.util.Arrays.asList(newlineValues).indexOf(newline);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Newline");
builder.setSingleChoiceItems(newlineNames, pos, (dialog, item1) -> {
newline = newlineValues[item1];
dialog.dismiss();
});
builder.create().show();
return true;
} else if (id == R.id.hex) {
hexEnabled = !hexEnabled;
sendText.setText("");
hexWatcher.enable(hexEnabled);
sendText.setHint(hexEnabled ? "HEX mode" : "");
item.setChecked(hexEnabled);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
/*
* Serial + UI
*/
private void connect() {
try {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
status("connecting...");
connected = Connected.Pending;
SerialSocket socket = new SerialSocket(getActivity().getApplicationContext(), device);
service.connect(socket);
} catch (Exception e) {
onSerialConnectError(e);
}
}
private void disconnect() {
connected = Connected.False;
service.disconnect();
}
private void send(String str) {
if(connected != Connected.True) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
String msg;
byte[] data;
if(hexEnabled) {
StringBuilder sb = new StringBuilder();
TextUtil.toHexString(sb, TextUtil.fromHexString(str));
TextUtil.toHexString(sb, newline.getBytes());
msg = sb.toString();
data = TextUtil.fromHexString(msg);
} else {
msg = str;
data = (str + newline).getBytes();
}
SpannableStringBuilder spn = new SpannableStringBuilder(msg + '\n');
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
service.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}
private void receive(byte[] data) {
if(hexEnabled) {
receiveText.append("Hello" + TextUtil.toHexString(data) + '\n');
} else {
String msg = new String(data);
if(newline.equals(TextUtil.newline_crlf) && msg.length() > 0) {
// don't show CR as ^M if directly before LF
msg = msg.replace(TextUtil.newline_crlf, TextUtil.newline_lf);
// special handling if CR and LF come in separate fragments
if (pendingNewline && msg.charAt(0) == '\n') {
Editable edt = receiveText.getEditableText();
if (edt != null && edt.length() > 1)
edt.replace(edt.length() - 2, edt.length(), "");
}
pendingNewline = msg.charAt(msg.length() - 1) == '\r';
}
receiveText.append(TextUtil.toCaretString(msg, newline.length() != 0)); //print out data
output = receiveText.toString(); // CharSequence to String
Intent intent = new Intent(getActivity(), MainActivity2.class);
intent.putExtra("output",output); // send data to next activity, MainActivity2
}
}
private void status(String str) {
SpannableStringBuilder spn = new SpannableStringBuilder(str + '\n');
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorStatusText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
}
/*
* SerialListener
*/
#Override
public void onSerialConnect() {
status("connected");
connected = Connected.True;
}
#Override
public void onSerialConnectError(Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
#Override
public void onSerialRead(byte[] data) {// receive data
receive(data); // send data to printout
}
#Override
public void onSerialIoError(Exception e) {
status("connection lost: " + e.getMessage());
disconnect();
}
}
MainActivity2.java (new activity)
package de.kai_morich.simple_bluetooth_le_terminal;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity2 extends AppCompatActivity {
Fragment CustomFragment;
private ArrayList<Data> dataList;
private RecyclerView recyclerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = findViewById(R.id.toolbar2);
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.dataflow);
dataList = new ArrayList<>();
String data;
if (savedInstanceState == null) {
Bundle extra = getIntent().getExtras();
if (extra == null) {
data = null;
receiveData(data);
} else {
data = extra.getString("output");
receiveData(data);
}
} else {
data = (String) savedInstanceState.getSerializable("output");
receiveData(data);
}
setAdapter();
}
private void receiveData(String data){
String Data = data;
dataList.add(new Data("John"));
dataList.add(new Data(Data));
}
private void setAdapter() {
recyclerAdapter adapter = new recyclerAdapter(dataList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_plot, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.dataplot:
Toast.makeText(this, "dataplot", Toast.LENGTH_SHORT).show();
replaceFragment(new DataPlotFragment());
return true;
case R.id.fft:
Toast.makeText(this, "FFT", Toast.LENGTH_SHORT).show();
replaceFragment(new FftFragment());
return true;
case R.id.data:
Toast.makeText(this, "DATA", Toast.LENGTH_SHORT).show();
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.plotframelayout,fragment);
fragmentTransaction.commit();
}
}
I realized I also need to add getText() in receive(). However, the recycler view won't update itself, it just captures what it has in the recyclerview of activity_main with TerminalFragment when the user click the menuItem (id,plot). Either getextrastring() or using bundle able to pass the data to Mainactivity2.
I think I need to add something else to keep adding data to the recyclerview of activity_main2 from activity_main.
onOptionsItemSelected of TerminalFragment
if (id == R.id.plot){
Intent intent = new Intent(getActivity(), MainActivity2.class);
intent.putExtra("output",output); //output
startActivity(intent);
return true;
}
receive() of TerminalFragment
private void receive(byte[] data) {
if(hexEnabled) {
receiveText.append("Hello" + TextUtil.toHexString(data) + '\n');
} else {
String msg = new String(data);
if(newline.equals(TextUtil.newline_crlf) && msg.length() > 0) {
// don't show CR as ^M if directly before LF
msg = msg.replace(TextUtil.newline_crlf, TextUtil.newline_lf);
// special handling if CR and LF come in separate fragments
if (pendingNewline && msg.charAt(0) == '\n') {
Editable edt = receiveText.getEditableText();
if (edt != null && edt.length() > 1)
edt.replace(edt.length() - 2, edt.length(), "");
}
pendingNewline = msg.charAt(msg.length() - 1) == '\r';
}
receiveText.append(TextUtil.toCaretString(msg, newline.length() != 0)); //print out data
output = receiveText.getText().toString(); // CharSequence to String
}
}
OnCreate of mainActivity2
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = findViewById(R.id.toolbar2);
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.dataflow);
dataList = new ArrayList<>();
String data;
Bundle extras = getIntent().getExtras();
if (extras != null)
{
data = extras.getString("output");
receiveData(data);
}
setAdapter();
}
I'm working on a school project and have hit a road block and wanted to see if anyone can help point me in the right direction. We are trying to capture packets from an Android phone without rooting the phone. The only option that I have found was to use Android's VPNService to use it as a middle man to capture the packets.
The idea that I had was to create a button to capture the packets, on a onclick event.
package cybutech.com.datacapture;
import android.app.ActionBar;
import android.content.Intent;
import android.graphics.Color;
import android.net.VpnService;
import android.preference.PreferenceFragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private int capture = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar);
setSupportActionBar(myToolbar);
final Button captureData = (Button)findViewById(R.id.capture);
captureData.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (capture == 1) {
captureData.setBackgroundColor(Color.RED);
captureData.setText("Stop Capture!");
Intent intent = VpnService.prepare(getApplicationContext());
if (intent != null) {
startActivityForResult(intent, 0);
} else {
onActivityResult(0, RESULT_OK, null);
}
capture *= -1;
} else {
captureData.setBackgroundColor(Color.GREEN);
captureData.setText("Start!");
capture *= -1;
}
}
});
}
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
Intent intent = new Intent(this, MyVpnService.class);
startService(intent);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_settings:
startActivity(new Intent(this, Settings.class));
break;
default:
break;
}
return true;
}
}
package cybutech.com.datacapture;
import android.content.Intent;
import android.net.VpnService;
import android.os.ParcelFileDescriptor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.channels.DatagramChannel;
public class MyVpnService extends VpnService {
private Thread mThread;
private ParcelFileDescriptor mInterface;
//a. Configure a builder for the interface.
Builder builder = new Builder();
// Services interface
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Start a new session by creating a new thread.
mThread = new Thread(new Runnable() {
#Override
public void run() {
try {
//a. Configure the TUN and get the interface.
mInterface = builder.setSession("MyVPNService")
.addAddress("192.168.0.1", 24)
.addDnsServer("8.8.8.8")
.addRoute("0.0.0.0", 0).establish();
//b. Packets to be sent are queued in this input stream.
FileInputStream in = new FileInputStream(
mInterface.getFileDescriptor());
//b. Packets received need to be written to this output stream.
FileOutputStream out = new FileOutputStream(
mInterface.getFileDescriptor());
//c. The UDP channel can be used to pass/get ip package to/from server
DatagramChannel tunnel = DatagramChannel.open();
// Connect to the server, localhost is used for demonstration only.
tunnel.connect(new InetSocketAddress("127.0.0.1", 8087));
//d. Protect this socket, so package send by it will not be feedback to the vpn service.
protect(tunnel.socket());
//e. Use a loop to pass packets.
while (true) {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while(true) {
String line = reader.readLine();
if (line == null) {
System.out.print("NULLLLLLL");
break;
} else {
System.out.println("line is " + line);
}
// I am guessing that here after reading the packets, I need to forward them to the actual server.
Thread.sleep(100);
}
}
} catch (Exception e) {
// Catch any exception
e.printStackTrace();
} finally {
try {
if (mInterface != null) {
mInterface.close();
mInterface = null;
}
} catch (Exception e) {
}
}
}
}, "MyVpnRunnable");
//start the service
mThread.start();
return START_STICKY;
}
#Override
public void onDestroy() {
// TODO Auto-generated method stub
if (mThread != null) {
mThread.interrupt();
}
super.onDestroy();
}
}
I'm trying to make an application that writes a simple plain text message to an NFC tag. The user writes a message in the EditText box, then on button press, the app writes the text onto a tag.
I've been following this tutorial: http://www.framentos.com/it/android-tutorial/2012/07/31/write-hello-world-into-a-nfc-tag-with-a/
However, when i try to put the NFC tag up next to it, the phone opens up another app, instead of using mine that is already open. I know the problem's with the intents, but i don't want to declare the intent filter in the manifest, because i don't want the app to open up when the tag is placed next to the phone, i want the app to be already open beforehand.
Here's the code for the application:
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.Ndef;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
public class MainActivity extends AppCompatActivity {
NfcAdapter adapter;
PendingIntent pendingIntent;
IntentFilter writeTagFilters[];
Tag mytag;
Context ctx;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ctx=this;
Button btnWrite = (Button) findViewById(R.id.button);
final EditText message = (EditText)findViewById(R.id.edit_message);
btnWrite.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v) {
try {
if(mytag==null){
Toast.makeText(ctx, ctx.getString(R.string.error_detected), Toast.LENGTH_LONG).show();
}else{
write(message.getText().toString(),mytag);
Toast.makeText(ctx, ctx.getString(R.string.ok_writing), Toast.LENGTH_LONG ).show();
}
} catch (IOException e) {
Toast.makeText(ctx, ctx.getString(R.string.error_writing), Toast.LENGTH_LONG ).show();
e.printStackTrace();
} catch (FormatException e) {
Toast.makeText(ctx, ctx.getString(R.string.error_writing) , Toast.LENGTH_LONG ).show();
e.printStackTrace();
}
}
});
adapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter tagDetected = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
tagDetected.addCategory(Intent.CATEGORY_DEFAULT);
writeTagFilters = new IntentFilter[] { tagDetected };
}
private NdefRecord createRecord(String text) throws UnsupportedEncodingException {
//create the message in according with the standard
String lang = "en";
byte[] textBytes = text.getBytes();
byte[] langBytes = lang.getBytes("US-ASCII");
int langLength = langBytes.length;
int textLength = textBytes.length;
byte[] payload = new byte[1 + langLength + textLength];
payload[0] = (byte) langLength;
// copy langbytes and textbytes into payload
System.arraycopy(langBytes, 0, payload, 1, langLength);
System.arraycopy(textBytes, 0, payload, 1 + langLength, textLength);
NdefRecord recordNFC = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], payload);
return recordNFC;
}
private void write(String text, Tag tag) throws IOException, FormatException {
NdefRecord[] records = { createRecord(text) };
NdefMessage message = new NdefMessage(records);
Ndef ndef = Ndef.get(tag);
ndef.connect();
ndef.writeNdefMessage(message);
ndef.close();
}
#Override
protected void onNewIntent(Intent intent){
if(NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())){
mytag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
Toast.makeText(this, this.getString(R.string.ok_detection) + mytag.toString(), Toast.LENGTH_LONG ).show();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
Please help, i don't know what i'm doing wrong!
I'm just a beginner at NFC and Android programming!
You have to use enable forground dispatch : http://developer.android.com/guide/topics/connectivity/nfc/advanced-nfc.html#foreground-dispatch
The foreground dispatch system allows an activity to intercept an
intent and claim priority over other activities that handle the same
intent.
UPDATE1
It's difficult to write on all kind of tags, some of them have closed specifications. You could start by writing on Ndef and NdefFormatable tags.
For instance:
#Override
protected void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
#Override
protected void onResume(){
super.onResume();
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("*/*");
}
catch ( MalformedMimeTypeException e) {
Log.e(TAG,"Bad MIME type declared",e);
return;
}
IntentFilter[] filters=new IntentFilter[]{ndef};
String[][] techLists=new String[][]{new String[]{Ndef.class.getName()},new String[]{NdefFormatable.class.getName()}};
mNfcAdapter.enableForegroundDispatch(this,pendingIntent,filters,techLists);
}
#Override
protected void onNewIntent(Intent intent) {
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String[] techList = tag.getTechList();
for (String tech : techList) {
if (tech.equals(Ndef.class.getName())) {
//write NDEF msg
} else if (tech.equals(NdefFormatable.class.getName())) {
//format and write NDEF msg
}
}
}
Android Wear Java I'm having some trouble finding out how to implement the Wear to Phone call using the Message Api. Can someone give me a simple working example or help me out here?
This is my code for testing...
Wear MainJava
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.support.wearable.view.WatchViewStub;
import android.util.Log;
import android.widget.TextView;
public class MessageActivity extends Activity {
private TextView mTextView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
#Override
public void onLayoutInflated(WatchViewStub stub) {
mTextView = (TextView) stub.findViewById(R.id.text);
}
});
// Register the local broadcast receiver
IntentFilter messageFilter = new IntentFilter(Intent.ACTION_SEND);
MessageReceiver messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String message = intent.getStringExtra("message");
Log.v("myTag", "Main activity received message: " + message);
// Display message in UI
mTextView.setText(message);
}
}
}
Wear Listener Service
import android.content.Intent;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.android.gms.wearable.MessageEvent;
import com.google.android.gms.wearable.WearableListenerService;
public class ListenerService extends WearableListenerService{
#Override
public void onMessageReceived(MessageEvent messageEvent) {
if (messageEvent.getPath().equals("/message_path")) {
final String message = new String(messageEvent.getData());
Log.v("myTag", "Message path received on watch is: " + messageEvent.getPath());
Log.v("myTag", "Message received on watch is: " + message);
// Broadcast message to wearable activity for display
Intent messageIntent = new Intent();
messageIntent.setAction(Intent.ACTION_SEND);
messageIntent.putExtra("message", message);
LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent);
}
else {
super.onMessageReceived(messageEvent);
}
}
}
and the mobile(phone)
package com.spokengiovannie.messageactivity;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.wearable.MessageApi;
import com.google.android.gms.wearable.Node;
import com.google.android.gms.wearable.NodeApi;
import com.google.android.gms.wearable.Wearable;
public class MessageActivity extends ActionBarActivity
implements
GoogleApiClient.ConnectionCallbacks,
GoogleApiClient.OnConnectionFailedListener {
GoogleApiClient googleClient;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_message);
// Build a new GoogleApiClient that includes the Wearable API
googleClient = new GoogleApiClient.Builder(this)
.addApi(Wearable.API)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.build();
}
// Connect to the data layer when the Activity starts
#Override
protected void onStart() {
super.onStart();
googleClient.connect();
}
// Send a message when the data layer connection is successful.
#Override
public void onConnected(Bundle connectionHint) {
String message = "Hello wearable\n Via the data layer";
//Requires a new thread to avoid blocking the UI
new SendToDataLayerThread("/message_path", message).start();
}
// Disconnect from the data layer when the Activity stops
#Override
protected void onStop() {
if (null != googleClient && googleClient.isConnected()) {
googleClient.disconnect();
}
super.onStop();
}
// Placeholders for required connection callbacks
#Override
public void onConnectionSuspended(int cause) { }
#Override
public void onConnectionFailed(ConnectionResult connectionResult) { }
// Unused project wizard code
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_message, 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();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
class SendToDataLayerThread extends Thread {
String path;
String message;
// Constructor to send a message to the data layer
SendToDataLayerThread(String p, String msg) {
path = p;
message = msg;
}
public void run() {
NodeApi.GetConnectedNodesResult nodes = Wearable.NodeApi.getConnectedNodes(googleClient).await();
for (Node node : nodes.getNodes()) {
MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(googleClient, node.getId(), path, message.getBytes()).await();
if (result.getStatus().isSuccess()) {
Log.v("myTag", "Message: {" + message + "} sent to: " + node.getDisplayName());
} else {
// Log an error
Log.v("myTag", "ERROR: failed to send Message");
}
}
}
}
}
All this code is from a tutorial. When I launch de app on the phone it suppose to change the textView wear text. Someone have a sample or app already made for contact the phone I'm stuck :(.
I think the problem is LocalBroadcastManager.getInstance(this).sendBroadcast(messageIntent) in your WearableListenerService. This is a local broadcast which will not be delivered to the phone.
see API doc LocalBroadcastManager
I'm not sure if you figured it by now but for the fresh lads like me this might help.
Add listener service to the respective class, in this example this is the code.
Add this in your Wear's AndroidManifest.xml file.
<service android:name=".ListenerService">
<intent-filter>
<action android:name="com.google.android.gms.wearable.BIND_LISTENER" />
</intent-filter>
</service>
Getting NullPointerException after I moved some of the code to a separate, custom application class called YambaApplication. This application posts to a Twitter enabled service. I checked the code 3 times, and cleaned the project 5 times:
Exception:
06-16 14:08:22.723: E/AndroidRuntime(392): Caused by:
java.lang.NullPointerException 06-16 14:08:22.723:
E/AndroidRuntime(392): at
com.user.yamba.StatusActivity$PostToTwitter.doInBackground(StatusActivity.java:70)
YambaApplication.java (here we initialize and return a twitter object):
package com.user.yamba;
import winterwell.jtwitter.Twitter;
import android.app.Application;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.preference.PreferenceManager;
import android.text.TextUtils;
import android.util.Log;
public class YambaApplication extends Application implements
OnSharedPreferenceChangeListener {
private static final String TAG = YambaApplication.class.getSimpleName();
public Twitter twitter;
private SharedPreferences prefs;
#Override
public void onCreate() {
super.onCreate();
this.prefs = PreferenceManager.getDefaultSharedPreferences(this);
this.prefs.registerOnSharedPreferenceChangeListener(this);
Log.i(TAG, "onCreated");
}
#Override
public void onTerminate() {
super.onTerminate();
Log.i(TAG, "onTerminated");
}
#Override
public synchronized void onSharedPreferenceChanged(
SharedPreferences sharedPreferences, String key) {
this.twitter = null;
}
public synchronized Twitter getTwitter() {
if (this.twitter == null) {
String username, password, apiRoot;
username = this.prefs.getString("username", "");
password = this.prefs.getString("password", "");
apiRoot = this.prefs.getString("apiRoot",
"http://yamba.marakana.com/api");
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)
&& !TextUtils.isEmpty(apiRoot)) {
this.twitter = new Twitter(username, password);
this.twitter.setAPIRootUrl(apiRoot);
}
}
return this.twitter;
}
}
StatusActivity.java (the first activity user sees with an EditText and an update button. Most of the code from YambaApplication class was inside this class.):
package com.user.yamba;
import winterwell.jtwitter.Twitter;
import winterwell.jtwitter.TwitterException;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class StatusActivity extends Activity implements OnClickListener,
TextWatcher {
private static final String TAG = "StatusActivity";
EditText editTextStatusUpdate;
Button buttonStatusUpdate;
TextView textViewCharacterCounter;
//SharedPreferences prefs;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_status);
// Find views
editTextStatusUpdate = (EditText) findViewById(R.id.editStatus);
buttonStatusUpdate = (Button) findViewById(R.id.buttonUpdate);
buttonStatusUpdate.setOnClickListener(this);
textViewCharacterCounter = (TextView) findViewById(R.id.editTextUpdateStatusCounter);
textViewCharacterCounter.setText(Integer.toString(140));
textViewCharacterCounter.setTextColor(Color.GREEN);
editTextStatusUpdate.addTextChangedListener(this);
//prefs = PreferenceManager.getDefaultSharedPreferences(this);
//prefs.registerOnSharedPreferenceChangeListener(this);
// Initialize twitter
// twitter = new Twitter("student", "password");
// twitter.setAPIRootUrl("http://yamba.marakana.com/api");
}
#Override
public void onClick(View v) {
String statusUpdate = editTextStatusUpdate.getText().toString();
new PostToTwitter().execute(statusUpdate);
Log.d(TAG, "onClicked");
}
// Async class to post of twitter
class PostToTwitter extends AsyncTask<String, Integer, String> {
// Async post status to twitter
#Override
protected String doInBackground(String... params) {
try {
YambaApplication yamba = ((YambaApplication) getApplication());
Twitter.Status status = yamba.getTwitter().updateStatus(params[0]); // EXCEPTION FIRED HERE
return status.text;
} catch (TwitterException e) {
Log.e(TAG, "Failed to connect to twitter service");
return "Failed to post";
}
}
// Called when there's status to be updated
#Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
// Not used
}
// Called once async task completed
#Override
protected void onPostExecute(String result) {
Toast.makeText(StatusActivity.this, result, Toast.LENGTH_LONG)
.show();
}
}
#Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// Not in use
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// Not in use
}
// Update characters counter after text
// is changed(entered or deleted)
#Override
public void afterTextChanged(Editable statusText) {
int count = 140 - statusText.length();
textViewCharacterCounter.setText(Integer.toString(count));
textViewCharacterCounter.setTextColor(Color.GREEN);
if (count < 10) {
textViewCharacterCounter.setTextColor(Color.YELLOW);
}
if (count < 0) {
textViewCharacterCounter.setTextColor(Color.RED);
}
}
// When user taps on the menu hardware button inflate
// the menu resource
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
// Determine what item user tapped on the menu
// and start the item's activity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.itemPrefs:
startActivity(new Intent(this, PrefsActivity.class));
break;
}
return true;
}
// private Twitter getTwitter() {
// if (twitter == null) {
// String username, password, apiRoot;
// username = prefs.getString("username", "");
// password = prefs.getString("password", "");
// apiRoot = prefs.getString("apiRoot",
// "http://yamba.marakana.com/api");
//
// // Connect to twitter
// twitter = new Twitter(username, password);
// twitter.setAPIRootUrl(apiRoot);
// }
// return twitter;
// }
// #Override
// public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
// String key) {
// // invalidate twitter
// twitter = null;
//
// }
}
Manifest (added this line to the application tag in the manifest):
android:name=".YambaApplication"
The first thing I saw were the new checks for the username and password to contain text.
Maybe try to debug if they both are set correctly and if a Twitter Object is returned from the Application, or simply null, because of those checks.
Null is because in YambaApplication you check:
if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(password)
&& !TextUtils.isEmpty(apiRoot)) {
...
}
If any field is empty you get twiter == null.