I'm am fairly new to Android, and I'm trying to develop an app for a small project of mine using an example Bluetooth Chat App and Spotify Media Notifications. I could not provide the links because stack overflow did not let me but they are available online with a quick google search. I was wondering why I was getting this exception and is there any solution to this?
java.lang.NullPointerException
The line numbers correspond to each of the pieces of code below:
Line 269 if (message.length() > 0)
Line 56 public class BluetoothChatFragment extends Fragment
Line 131 sendMessage(artistName);
How my code is set up:
I have a static broadcast receiver set up exactly like the Spotify link below. I grab the song name and artist and package them into strings. Then I have another broadcast receiver in my Bluetooth fragment. I used another one because I did not know how to get the string into the Bluetooth fragment because I needed to call sendMessage() a private method in the fragment class. It seems like the exception is throwing when I call sendMessage(string) in my fragment.
Static Spotify Broadcast Receiver
package com.example.android.bluetoothchat;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.example.android.common.logger.Log;
public class MyBroadcastReceiver extends BroadcastReceiver {
static final class BroadcastTypes {
static final String SPOTIFY_PACKAGE = "com.spotify.music";
static final String PLAYBACK_STATE_CHANGED = SPOTIFY_PACKAGE + ".playbackstatechanged";
static final String QUEUE_CHANGED = SPOTIFY_PACKAGE + ".queuechanged";
static final String METADATA_CHANGED = SPOTIFY_PACKAGE + ".metadatachanged";
}
#Override
public void onReceive(Context context, Intent intent) {
// This is sent with all broadcasts, regardless of type. The value is taken from
// System.currentTimeMillis(), which you can compare to in order to determine how
// old the event is.
long timeSentInMs = intent.getLongExtra("timeSent", 0L);
Intent sendBack = new Intent("Received");
String action = intent.getAction();
String artistName;
String trackName;
if (action.equals(BroadcastTypes.METADATA_CHANGED)) {
artistName = intent.getStringExtra("artist");
trackName = intent.getStringExtra("track");
String msg = "S a " + artistName + '\0';
String msg2 = "S n " + trackName + '\0';
Log.d("Song", msg);
Log.d("Artist", msg2);
sendBack.putExtra("Song", msg);
sendBack.putExtra("Artist", msg2);
} else if (action.equals(BroadcastTypes.PLAYBACK_STATE_CHANGED)) {
boolean playing = intent.getBooleanExtra("playing", false);
// Do something with extracted information
if(playing) {
Log.d("Playing", "S p\0");
sendBack.putExtra("Playing", "S p\0");
}
else {
Log.d("Playing", "S s\0");
sendBack.putExtra("Playing", "S s\0");
}
}
context.sendBroadcast(sendBack);
}
}
Broadcast Receiver in Fragment:
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String artistName = intent.getStringExtra("Song");
String trackName = intent.getStringExtra("Artist");
String playing = intent.getStringExtra("Playing");
Log.d("Please", artistName);
Log.d("Please", trackName);
Log.d("Please", playing);
sendMessage(artistName);
sendMessage(trackName);
sendMessage(playing);
}
};
sendMessage Method():
private void sendMessage(String message) {
// Check that we're actually connected before trying anything
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED) {
Toast.makeText(getActivity(), R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
// Check that there's actually something to send
if (message.length() > 0) {
// Get the message bytes and tell the BluetoothChatService to write
byte[] send = message.getBytes();
mChatService.write(send);
// Reset out string buffer to zero and clear the edit text field
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
Any help would be much appreciated!
http://developer.android.com/samples/BluetoothChat/index.html
To me it looks like sendMessage gets called with null instead of an actual string. Note that intent.getStringExtra(some_string) can return null, if some_string cannot be found.
Related
So, i am creating a virtual assistant app which after listening to user suppose to update the ui and then take another input but it updating the ui at once and then listening and speaking at once and taking no input
messageHolder = "The Global text get from Recognizer";
private void sendChatMessage(boolean side){
if(side != true){
tts.speak(messageHolder,TextToSpeech.QUEUE_ADD,null);
}
chatArrayAdapter.add(new ChatMessage(side,messageHolder));
chatArrayAdapter.notifyDataSetChanged();
}
startSpeechToText() -> get the result from the speechrecognizerIntent
private class SeprateQuery extends AsyncTask<String,String,query>{
#Override
protected query doInBackground(String... strings) {
String v_query = strings[0].toString();
Log.e("APP","String recieved inn seprateQuery and is"+v_query);
if(v_query.indexOf("create contact")!=-1){
v_query = v_query.replace("create contact ","");
return new query(4,v_query);
return new query(-1,"null");
}
#Override
protected void onPostExecute(query code) {
super.onPostExecute(code);
if(code.code==4){
messageHolder = "Enter the name";
sendChatMessage(false);
startSpeechToText(speechRecognizerIntent,false);
String name = messageHolder;
messageHolder = "Enter the number";
sendChatMessage(false);
startSpeechToText(speechRecognizerIntent,false);
String contact = messageHolder;
addContact(name,contact);
//addContact(name,contact);
}else
is there any way i can perform the code in onPostExecute procedurally one by one instead ui updating at once without listening to users
I'm currently building a spam-call blocking app as a fun project to get better with Android development, and am running into this odd bug.
I have a Broadcast Receiver setup to listen for changes in the call state, and logic to check if the call is incoming or not, and basically end the call if the number is not in the user's contact list or a "whitelist" of approved numbers held in a database. However, even after the call has been ended, the receiver continues to be called multiple times (sometimes 8 or more times) and will often be called with Call State set as ringing (again, despite the fact that the call has been ended).
Basically, I'm trying to keep track of how many times each unknown number calls the phone, but for each single call it records it as anywhere from 2 - 6 calls.
Here is the onReceive function I have set up:
public void onReceive(final Context con, Intent intent) {
System.out.println(intent);
final TelephonyManager telephony = (TelephonyManager) con.getSystemService(Context.TELEPHONY_SERVICE);
telephony.listen(new PhoneStateListener() {
#RequiresApi(api = Build.VERSION_CODES.P)
#Override
public void onCallStateChanged(int state, String incomingNumber) {
super.onCallStateChanged(state, incomingNumber);
System.out.print(state);
//Toast.makeText(con, incomingNumber, Toast.LENGTH_LONG).show();
if (TelephonyManager.CALL_STATE_RINGING == state) {
checkIfNumberInContacts(con, incomingNumber, telephony, state);
}
}
}, PhoneStateListener.LISTEN_CALL_STATE);
}
and here is the custom function that checks if the incoming number is in contacts/whitelisted and ends the call:
#RequiresApi(api = Build.VERSION_CODES.P)
public void checkIfNumberInContacts(Context con, String incomingNumber, TelephonyManager telephony,
int state) {
db = Room.databaseBuilder(con, SpamBlockerDB.class,
"spamblocker.db").createFromAsset("databases/spamblocker.db").allowMainThreadQueries().build();
FilteredCalls call = new FilteredCalls();
call.calltime = Calendar.getInstance().getTime().toString();
call.deleted = 0;
call.number = incomingNumber;
call.whitelisted = 0;
call.callcount = 1;
List<FilteredCalls> allCalls = db.callsDao().getAll();
boolean callerExistsInDB = false;
for (FilteredCalls item : allCalls) {
if (incomingNumber.equals(item.number)) {
callerExistsInDB = true;
String updatedTime = Calendar.getInstance().getTime().toString();
db.callsDao().updateCallTime(updatedTime, item.recID);
}
if (TelephonyManager.CALL_STATE_RINGING == state) {
int currentCount = db.callsDao().getCallCount(item.recID);
db.callsDao().updateCallCount(currentCount + 1, item.recID);
}
}
ContentResolver contentResolver = con.getContentResolver();
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(incomingNumber));
String contact = "";
Cursor c = contentResolver.query(uri, new String[]{ContactsContract.PhoneLookup.HAS_PHONE_NUMBER}, null, null);
if (c != null) {
if (c.moveToFirst()) {
do {
contact = c.getString(c.getColumnIndex("NUMBER"));
} while (c.moveToNext());
}
}
if (contact == "" && !checkIfNumberIsWhitelisted(con, incomingNumber)) {
TelecomManager telecomManager = (TelecomManager) con.getSystemService(Context.TELECOM_SERVICE);
telecomManager.endCall();
if (!callerExistsInDB) {
db.callsDao().insert(call);
}
}
}
Any ideas why the BroadCast receiver is called more than twice (once for incoming, once for hanging up), and why when it's called the subsequent times it still thinks the phone is ringing?
Appreciate the help in advance.
There are two ways to get callbacks when the phone state changes: PhoneStateListener and a BroadcastReceiver that listens to android.intent.action.PHONE_STATE.
It looks like you're mixing the two methods together, which means that whenever your BroadcastReceiver is called, you're registering another new PhoneStateListener, so you keep adding more and more listeners that do the same thing.
I would recommend not using PhoneStateListener at all, and go with the BroadcastReceiver approach only, which can be setup via AndroidManifest which allows it to be called even when the app is asleep.
See this tutorial: https://medium.com/#saishaddai/how-to-know-when-a-device-is-ringing-in-android-57e516d0ab42
I know this is a big topic, as seen here and here, so I just wanted to post how I solved both the issue of receiving incoming MMS and SMS messages and the issue of grabbing data from those MMS and SMS messages on Android 9.0 version 28+ using Xamarin.Forms. This code can easily be translated to Java. Here is the completed Android app so you can try it yourself. It also shows how to do some Azure machine learning if you're interested in that.
For Broadcast Receivers:
Classes, registering class instances , permissions needed.
Note that the broadcast receivers were added dynamically, they can be added statically using Xamarin's intent-filter decorator , or (if you're not using Xamarin) the AndroidManifest.xml file.
Here is a code snippet to show how to parse incoming SMS data with a Broadcast Receiver:
public override void OnReceive(Context context, Intent intent)
{
Log.Info(TAG, "Intent action received: " + intent.Action);
// Retrieve message from the intent and analyze it.
SmsMessage msg = Android.Provider.Telephony.Sms.Intents.GetMessagesFromIntent(intent)[0];
string message = msg.DisplayMessageBody;
(string, bool) result = MMSReceiver.CleanUpMessage(message);
// If there were one or more rooster words.
if (result.Item2)
{
string title = "Rooster Text Received From: " + msg.DisplayOriginatingAddress;
DependencyService.Get<INotificationManager>().ScheduleNotification(title, result.Item1);
}
}
And here is a code snippet to show how to parse incoming MMS data with a Broadcast Receiver:
public override void OnReceive(Context context, Intent intent)
{
Log.Info(TAG, "Intent action received: " + intent.Action);
// Get the MMS ID. Adapted from: https://stackoverflow.com/questions/10065249/how-to-get-mms-id-android-application
ContentResolver contentResolver = AndroidApp.Context.ContentResolver;
Android.Net.Uri mmsInboxUri = Android.Net.Uri.Parse("content://mms");
Android.Database.ICursor mmsInboxCursor = contentResolver.Query(mmsInboxUri, new string[]
{"_id","msg_box","ct_t","date"}, "msg_box=1 or msg_box=2", null, null);
int id = -1;
if (mmsInboxCursor != null)
{
try
{
if (mmsInboxCursor.MoveToFirst())
{
id = Int32.Parse(mmsInboxCursor.GetString(0));
Log.Info(TAG, "Id is this: " + mmsInboxCursor.GetString(0));
}
}
catch (System.Exception error)
{
Log.Error(TAG, "Error requesting the MMS ID: " + error.Message);
}
}// if (mmsInboxCursor != null)
// Get text and picture from MMS message. Adapted from: https://stackoverflow.com/questions/3012287/how-to-read-mms-data-in-android
string message = ""; // text
Android.Graphics.Bitmap bitmap = null; // picture
string selectionPart = "mid=" + id;
Android.Net.Uri mmsTextUri = Android.Net.Uri.Parse("content://mms/part");
Android.Database.ICursor cursor = contentResolver.Query(mmsTextUri, null,
selectionPart, null, null);
if (cursor.MoveToFirst())
{
do
{
string partId = cursor.GetString(cursor.GetColumnIndex("_id"));
string type = cursor.GetString(cursor.GetColumnIndex("ct"));
// Get text.
if ("text/plain".Equals(type))
{
string data = cursor.GetString(cursor.GetColumnIndex("_data"));
if (data != null)
{
message = GetMmsText(partId);
Log.Info(TAG, "Body is this: " + message);
}
else
{
message = cursor.GetString(cursor.GetColumnIndex("text"));
Log.Info(TAG, "Body is this: " + message);
}
}
//Get picture.
if ("image/jpeg".Equals(type) || "image/bmp".Equals(type) ||
"image/gif".Equals(type) || "image/jpg".Equals(type) ||
"image/png".Equals(type))
{
bitmap = GetMmsImage(partId);
}
} while (cursor.MoveToNext());
}// if (cursor.MoveToFirst())
}
I have a IncomingSmsReceiver class that receives a sms message but the problem is it takes a while to receive the text message, I know that the BroadcastReceiver class automatically stop the process if it's listening for more the 10 seconds, is there any way to disable this?
heres my code:
public class IncomingSmsReceiver extends BroadcastReceiver {
private ShowDialogInterface callback;
public void onReceive(Context context, Intent intent) {
if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) {
String messageBody = "no data";
String messageFrom = "no data";
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
messageBody = smsMessage.getMessageBody();
messageFrom = smsMessage.getDisplayOriginatingAddress();
}
if(callback != null) {
callback.smsDetails(messageFrom, messageBody);
}
}
}
public void registerReceiver(ShowDialogInterface receiverCallback) {
this.callback = receiverCallback;
}
// Show different UI elements to notifying the user of an incoming SMS
public interface ShowDialogInterface {
void smsDetails(String from, String message);
}
}
Here is my debug error:
enter image description here
Best Regards,
Noob Android_dev
You can start service from your BroadcastReceiver and do all job in it. It's a standard way to do such things.
I have my smartphone connected to a wear emulator and I use Android Studio.
The emulator and my phone app are both using WearableListenerService with an overridden onMessageReceived() and while the emulator is able to successfully send a message to my phone using MessageApi, the device cannot send one back - the no nodes are found at all despite the emulator finding my phone as a node. I originally used the MessageEvent.getSourceNodeId() method with the MessageEvent argument supplied to onMessageReceived() but that didn't work either.
My plan is to send a message to my phone with and have the phone relay a message back instantly after.
Is there something I need to do on the phone side of things in order to message my wear device? I have followed the instructions of many guides: both applicationIds are the same, the directories are the same, Manifests are fine, I used Generate Signed APK... still nothing!
Thanks.
Code used to send a message to phone:
import android.content.Context;
import android.util.Log;
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;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
public class SendToWear {
public static final String TAG = "DEMO_WEAR_LOG";
private static GoogleApiClient sClient = null;
public static int sendMessage(Context context, String path, String data){
Log.d(TAG, "Path: " + path);
ArrayList<String> nodes;
int sent, connectCount = 0;
if(context == null || path == null){
Log.d(TAG, "Context or Path is null.");
return 0;
}
if(sClient == null) {
sClient = new GoogleApiClient.Builder(context)
.addApi(Wearable.API)
.build();
}
sClient.connect();
ConnectionResult connectionResult =
sClient.blockingConnect(5, TimeUnit.SECONDS);
if (!connectionResult.isSuccess()) {
Log.e(TAG, "Failed to connect to sClient.");
return 0;
} else Log.d(TAG, "sClient connected!");
// no nodes, loop useless
nodes = getNodes(sClient);
if(nodes.size() == 0) return 0;
for(int i = sent = 0; i < nodes.size(); i++) {
MessageApi.SendMessageResult result = Wearable.MessageApi.sendMessage(
sClient, nodes.get(i), path, data.getBytes()).await(3, TimeUnit.SECONDS);
// was not able to send message
if(result.getStatus().isSuccess())
++sent;
}
sClient.disconnect();
Log.d(TAG, "SENT: " + sent);
return sent;
}
private static ArrayList<String> getNodes(GoogleApiClient client) {
Log.d(TAG, "in getNodes");
ArrayList<String> results = new ArrayList<String>();
NodeApi.GetConnectedNodesResult nodes =
Wearable.NodeApi.getConnectedNodes(client).await(3, TimeUnit.SECONDS);
if(nodes == null || !nodes.getStatus().isSuccess())
return results;
for (Node node : nodes.getNodes()) {
results.add(node.getId());
}
return results;
}
}