Android NFC throwing exception - android

I have an android app using P2P NFC. NFC works but i have to tap the devices twice to start it. When i debug my app and tap devices it calls createNdefMessage function but throws an exception at JavaBinder.
In run mode it doesn't crashes but i have to tap the devices twice to start NFC.
Before NFC i call a file selector to select a file to transfer.
Here is my code OnCreate
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// INFO TEXTVIEW
mInfoText = (TextView) findViewById(R.id.info_text_view);
// FILE SELECTOR BUTTON
mStartActivityButton = (Button)findViewById(R.id.start_file_picker_button);
mStartActivityButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.start_file_picker_button:
// Create a new Intent for the file picker activity
Intent intent = new Intent(getApplicationContext(), FilePickerActivity.class);
// Start the activity
startActivityForResult(intent, REQUEST_PICK_FILE);
break;
}
}
});
// CHECK FOR AVAILABLE NFC ADAPTOR
mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
if (mNfcAdapter == null) {
mInfoText.setText("NFC is not available on this device.");
} else {
// Register callback to set NDEF message
mNfcAdapter.setNdefPushMessageCallback(this, this);
// Register callback to listen for message-sent success
mNfcAdapter.setOnNdefPushCompleteCallback(this, this);
}
}
createNdefMessage
public NdefMessage createNdefMessage(NfcEvent event) {
Time time = new Time();
time.setToNow();
mInfoText.setTextColor(Color.WHITE);
mInfoText.setText("File Transfer In Progress ...");
NdefMessage msg = new NdefMessage(NdefRecord.createMime(
"application/com.example.android.beam", text.getBytes()));
return msg;
}
My app throughs an exception at
mInfoText.setTextColor(Color.WHITE);
Is it because i am having two intents?

I think that when you call mInfoText.setTextColor(Color.WHITE) mInfoText is null. Try initialising with findViewById() before you call setTextColor

Related

How to make sure TextToSpeech is initialized before using speak?

I'd like to ask you for some help with Android TextToSpeech feature.
Basically, I'd like to develop a simple AI which speaks, asking a question then waits for an answer, and at last, based on answer asks another question and so on, until user pronounces a keyword which stops everything.
Now I know TextToSpeech has to be initialized before using speak method, and I'm trying to take this into account by using onActivityResult method.
Below some code:
Activity class:
public class MainActivity extends AppCompatActivity implements OnInitListener, Button.OnClickListener{
Button sayHello;
TextView textView;
private static final int CHECK_DATA = 0;
private static final Locale defaultLocale = Locale.UK; // British English
private static final String TAG = "TTS";
private TextToSpeech tts;
private boolean isInit = false;
sayIt Method: used to speak:
public void sayIt(String text, boolean flushQ){
if(isInit){
if(flushQ){
tts.speak(text, TextToSpeech.QUEUE_FLUSH, null, null);
} else {
tts.speak(text, TextToSpeech.QUEUE_ADD, null, null);
}
} else {
Log.i(TAG, "Failure: TTS instance not properly initialized");
}
}
TextToSpeech Listener:
#Override
public void onInit(int status){
if(status == TextToSpeech.SUCCESS){
isInit = true;
// Enable input text field and speak button now that we are initialized
sayHello.setEnabled(true);
// Set to a language locale after checking availability
Log.i(TAG, "available="+tts.isLanguageAvailable(Locale.UK));
tts.setLanguage(defaultLocale);
// Examples of voice controls. Set to defaults of 1.0.
tts.setPitch(1.0F);
tts.setSpeechRate(1.0F);
// Issue a greeting and instructions in the default language
tts.speak("Initialized!", TextToSpeech.QUEUE_FLUSH, null, Integer.toString(12));
} else {
isInit = false;
Log.i(TAG, "Failure: TTS instance not properly initialized");
}
}
Button Listener:
#Override
public void onClick(View v){
if(isInit)
sayIt("You clicked!", true);
}
onActivityResult Method:
// Create the TTS instance if TextToSpeech language data are installed on device. If not
// installed, attempt to install it on the device.
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CHECK_DATA) {
if (resultCode == TextToSpeech.Engine.CHECK_VOICE_DATA_PASS) {
// Success, so create the TTS instance. But can't use it to speak until
// the onInit(status) callback defined below runs, indicating initialization.
Log.i(TAG, "Success, let's talk");
tts = new TextToSpeech(this, this);
// Use static Locales method to list available locales on device
Locale[] locales = Locale.getAvailableLocales();
Log.i(TAG,"Locales Available on Device:");
for(int i=0; i<locales.length; i++){
String temp = "Locale "+i+": "+locales[i]+" Language="
+locales[i].getDisplayLanguage();
if(locales[i].getDisplayCountry() != "") {
temp += " Country="+locales[i].getDisplayCountry();
}
Log.i(TAG, temp);
}
} else {
// missing data, so install it on the device
Log.i(TAG, "Missing Data; Install it");
Intent installIntent = new Intent();
installIntent.setAction(TextToSpeech.Engine.ACTION_INSTALL_TTS_DATA);
startActivity(installIntent);
}
}
}
And, at last, onCreate Method:
#Override
public void onCreate(Bundle savedInstance){
super.onCreate(savedInstance);
setContentView(R.layout.activity_main);
sayHello = findViewById(R.id.sayBtn);
textView = findViewById(R.id.textView);
sayHello.setEnabled(false);
sayHello.setOnClickListener(this);
Intent checkIntent = new Intent();
checkIntent.setAction(TextToSpeech.Engine.ACTION_CHECK_TTS_DATA);
startActivityForResult(checkIntent, CHECK_DATA);
/* THIS SPEAK DOES NOT WORK! */
sayIt("Speech from method!", true);
}
Issue is: Button successfully gets enabled when onInit method initialises TextToSpeech and successfully pronounces text.
My goal is to make the Activity speak from onCreate method, since at the moment it only works from onInit and onClick listeners, bot not in onCreate, even if I check for tts initialization using onActivityResult.
Basically I want the TextToSpeech to speak with no Buttons involved.
I know very similar questions were already posted, but none solved my problem. Have some idea?
Hope I've been clear, Thank you!
UPDATE: Log shows ERROR detected occurs in else branch of onInit method, where Log.i(TAG, "Failure: TTS instance not properly initialized"); line is.
SOLUTION:
The only thing to do here is to wait a little time in order to let TextToSpeech initialize for good.
A good way seems to be by using a delayed Handler as follows:
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
//Waiting for RobotTextToSpeech initialization for 1500ms
rtts.speak("This speak will work!");
rtts.speak("This other speak will work too!");
}
}, 1500);
}
By doing this, looks like TextToSpeech works well even in onCreate method, we just have to wait little time.
Hope this can help.

read a nfc chip after the users clicks a button

is it possible to start reading from a nfc-chip after pressing a button. After pushing the button there should be a message like "please hold your nfc chip close to the device..". I only see tutorials, which show how to start the application when holding a nfc chip to the device (onNewIntent).
Second Question. What if the application is already running and i hold the nfc chip next to my device? Is it forcing a destroy and then launches again?
Thanks!
Regarding the first part of your question, you could use a flag within your activity that indicates the state of your application (ready to write/message is showing, not ready to write/message not showing). YOu can find a simple example here:
private static final int DIALOG_WRITE = 1;
private boolean mWrite = false; // write state
public void onCreate(Bundle savedInstanceState) {
[...]
// Set action for "Write to tag..." button:
mMyWriteButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Switch to write mode:
mWrite = true;
// Show a dialog when we are ready to write:
showDialog(DIALOG_WRITE);
}
});
[...]
}
protected Dialog onCreateDialog(int id, Bundle args) {
switch (id) {
case DIALOG_WRITE:
// A dialog that we show when we are ready to write to a tag:
return new AlertDialog.Builder(this)
.setTitle("Write to tag...")
.setMessage("Touch tag to start writing.")
.setCancelable(true)
.setNeutralButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface d, int arg) {
d.cancel();
}
})
.setOnCancelListener(new DialogInterface.OnCancelListener() {
public void onCancel(DialogInterface d) {
mWrite = false;
}
}).create();
}
return null;
}
// You would call this method from onCreate/onStart/onResume/onNewIntent
// or from whereever you want to process an incoming intent
private void resolveIntent(Intent data, boolean foregroundDispatch) {
String action = data.getAction();
if (NfcAdapter.ACTION_TECH_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_TAG_DISCOVERED.equals(action)
|| NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
// The reference to the tag that invoked us is passed as a parameter (intent extra EXTRA_TAG)
Tag tag = data.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (mWrite) {
// We want to write
mWrite = false;
// TODO: write to tag
} else {
// not in write-mode
// TODO: read tag or do nothing
}
}
}
Regarding the second part of your question, when you want to receive NFC tag discovery events while your activity is already in the foreground, you should register with the NFC foreground dispatch system. See Advanced NFC: Using the NFC Foreground Dispatch System. There is no need to destroy and re-create your activity.

Android: Error transfer data after click of buttons

Hi there I am new to Android Programming
I am trying to create an application in which, the user clicks button on the first page
the text color in the buttons change color and the change is reflected in another activity page.
To do this I have
1) one fragment class(BookLockerFragment) which reference to an xml file containing the buttons
2) The parent activity file (TabActivity.java)
3) The activity file to reflect the change ( complainResponse.java)
Here is the code:
LodgeComplaintFragment.java
ArrayList<String>userSelectedOptions = new ArrayList<String>();
if(btnSis.getCurrentTextColor()==Color.BLUE){
userSelectedOptions.add("SIS");
}
Button but = (Button) root.findViewById(R.id.searchButton);
.....
but.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
buttonListener.onMakeBookingButtonPressed(userSelectedOptions);
}
});
TabMainActivity.java
public void onMakeBookingButtonPressed(ArrayList<String> list) {
// TODO Auto-generated method stub
Intent intent = new Intent(TabMainActivity.this,
complainResponse.class);
intent.putStringArrayListExtra("userSelectOptions",list);
startActivity(intent);
}
complainResponse.java
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get the message from the intent
Intent intent = getIntent();
setContentView(R.layout.complainresponse);
userInput = intent.getStringArrayListExtra("userSelectOptions");
// Creates the window used for the UI
if (userInput != null) {
if (userInput.get(0) != null) {
textview1 = (TextView) findViewById(R.id.textView1);
textview1.setText(userInput.get(0));
}
}
}
Error occurs at this line:
if (userInput != null) {
//of complainResponse.java
Logcat:
java.lang.IndexOutOfBoundsException
Please help
There's nothing in the ArrayList that you pass to your activity.
I suspect this bit of code isn't being executed -
if(btnSis.getCurrentTextColor()==Color.BLUE){
userSelectedOptions.add("SIS"); <------------ never gets here
}
To verify this, run the application in debug mode, and place a breakpoint at the if statement
userInput.get(0) != null
this is the cause of error in my opinion, list can be initialized but empty.
instead you should use,
if (!userInput.isEmpty())

Unable to both start and discover a specific service with Wifi Direct

I'm pretty new with Android programming. But I have been working on this for over a week now, and it starts to get booooring.
My idea is that I want to connect two devices using Wifi Direct. But I only want to connect to those which are running my application. Besides, I want the users to be able to see some information of the other devices (such as user name), not just the MAC or the Android_XXXX name included in the WifiP2pDevice. That's why I decided that a device looking for other devices, should both start the application service and search for peers which are also broadcasting this service.
The problem (I'm testing with two real devices) is that, even though they are running exactly the same code, only one of them is getting the service discovery callbacks (the onDnsSd... listeners below). So, one side acts in the proper way, but not the other. Moreover I'm getting "old" services, meaning that apparently each time I start de service (even though I cancel previously started services), that service seems to be still broadcast during at least some minutes.
I include a shortened version of my code:
public class MoveFlufietsDialogFragment extends DialogFragment implements ChannelListener, DeviceActionListener {
public final HashMap<String, FlufietsPeer> mBuddies = new HashMap<String, FlufietsPeer>();
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
...
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
mManager = (WifiP2pManager) getActivity().getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mManager.initialize(getActivity(), getActivity().getMainLooper(), null);
...
startRegistration();
discoverFlufietsService();
...
}
public void discoverFlufietsService() {
DnsSdTxtRecordListener txtListener = new DnsSdTxtRecordListener() {
#Override
public void onDnsSdTxtRecordAvailable(String fullDomain, Map record, WifiP2pDevice device) {
// This and the next listener are only called in one of the devices.
String serviceName = (String) record.get("serviceName");
if ((serviceName != null) && (serviceName.equals("flufiets")) {
// I put the record data in the mBuddies HashMap.
...
mBuddies.put(device.deviceAddress, myPeerDataStructure);
}
}
};
DnsSdServiceResponseListener servListener = new DnsSdServiceResponseListener() {
#Override
public void onDnsSdServiceAvailable(String instanceName, String registrationType, WifiP2pDevice resourceType) {
if (mBuddies.containsKey(resourceType.deviceAddress)) {
FlufietsPeer flufietsPeer = mBuddies.get(resourceType.deviceAddress);
WiFiPeerListAdapter adapter = ((WiFiPeerListAdapter) mFragmentList.getListAdapter());
adapter.add(flufietsPeer);
adapter.notifyDataSetChanged();
}
}
};
mManager.setDnsSdResponseListeners(mChannel, servListener, txtListener);
WifiP2pDnsSdServiceRequest serviceRequest = WifiP2pDnsSdServiceRequest.newInstance();
mManager.addServiceRequest(mChannel, serviceRequest, new ActionListener() {
// onSuccess/onFailure toasts.
});
mManager.discoverServices(mChannel, new WifiP2pManager.ActionListener() {
// onSuccess/onFailure toasts.
});
}
public void startRegistration() {
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
Map record = new HashMap();
record.put("serviceName", "flufiets");
...
WifiP2pDnsSdServiceInfo serviceInfo = WifiP2pDnsSdServiceInfo.newInstance(flufietsService, "_tcp", record);
mManager.addLocalService(mChannel, serviceInfo, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
#Override
public void onResume() {
super.onResume();
mReceiver = new WiFiDirectBroadcastReceiver(mManager, mChannel, this);
getActivity().registerReceiver(mReceiver, mIntentFilter);
}
#Override
public void onPause() {
super.onPause();
getActivity().unregisterReceiver(mReceiver);
}
#Override
public void onStop() {
super.onStop();
mManager.clearLocalServices(mChannel, new ActionListener() {
// onSuccess/onFailure toasts.
});
}
...
}
The problem doesn't seem to be related with the device itself (sometimes it works, sometimes it doesn't, but always only in one of them). I suspect it has to do with either trying to discover a service that we ourselves are broadcasting, or having the same service being offered by two devices. I have tried changing the names of the service, so each device would offer either a "send" or "receive" service, but it doesn't work. I only get the callbacks called (onDnsSd...) in one of the devices.
And that thing about getting old services, when I always clear them, is weird (I do include a timestamp in the service record data, and I could always discard all but the last, but doesn't seem to be logical).
Any ideas? ANY help would be VERY appreciated, because writing the application is not funny any more (:-)=
Thanks a lot!
You need to wait until the clearLocalService call succeeds before adding the local service later. So put the addLocalService call into the onSuccess callback of the clearLocalServices.

Send NDEF message from Android device using Xamarin

I want to send an NDEF message from one Android device to other device. Not to write in a tag, but send the message to the nearby device.
I'm using Xamarin.Android to develop the Android app and I create the message like this:
NdefRecord uriRecord = NdefRecord.CreateUri("http://myURL");
NdefMessage message = new NdefMessage(new[] { uriRecord });
I now want to send the message when nearby device is detected, but I don't know how it is done. Xamarin's documentation is not complete, and I'm not familiar with Android development.
Could anyone help me or show a simple example?
I figured out.
The main activity has to implement NfcAdapter.ICreateNdefMessageCallback and NfcAdapter.IOnNdefPushCompleteCallback interfaces.
Implement CreateNdefMessage and OnNdefPushComplete methods.
Call SetNdefPushMessageCallback and SetOnNdefPushCompleteCallback methods of NfcAdapter in the OnCreate method of the main activity.
public class Activity1 : Activity, NfcAdapter.ICreateNdefMessageCallback, NfcAdapter.IOnNdefPushCompleteCallback
{
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
...
NfcAdapter adapter = NfcAdapter.GetDefaultAdapter(this);
adapter.SetNdefPushMessageCallback(this, this);
adapter.SetOnNdefPushCompleteCallback(this, this);
}
public NdefMessage CreateNdefMessage(NfcEvent e)
{
NdefRecord uriRecord = NdefRecord.CreateUri("http://myURL");
NdefMessage message = new NdefMessage(new[] { uriRecord });
return message;
}
public void OnNdefPushComplete(NfcEvent e)
{
//throw new NotImplementedException();
}
}

Categories

Resources