I am working on my first Android app, which is a paging device. It will intercept a SMS message from a certain number with a certain content in it, display that and then allow the user to send a pre-defined reply back to that same number. I have gathered up code snippets from numerous sources (including stackoverflow of course) but I haven't yet got it working.
My file structure is as shown here
The part I am struggling with is SmsBroadcastReceiver and ReceiveAlert, which should display the content of the SMS and has a button to initiate the reply.
SmsBroadcastReceiver.java looks like this:
package com.example.alert6;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.provider.Telephony;
import android.telephony.SmsMessage;
public class SmsBroadcastReceiver extends BroadcastReceiver {
public static final String EXTRA_MESSAGE = "com.example.alert6.MESSAGE";
#Override
public void onReceive(Context context, Intent intent) {
String smsSender = "";
String smsBody = "";
for (SmsMessage smsMessage : Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
smsSender = smsMessage.getOriginatingAddress();
smsBody = smsMessage.getMessageBody();
}
if (smsSender.equals("+420775367297")) {
if (smsBody.contains("Test")) {
intent.putExtra(EXTRA_MESSAGE, smsBody);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // adding this flag starts the new Activity in a new Task
context.startActivity();
}
}
}
}
ReceiveAlertActivity.java is this:
package com.example.alert6;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
public class ReceiveAlertActivity extends AppCompatActivity {
private static final int SMS_PERMISSION_CODE = 101;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receive_alert);
}
// Get the Intent that started this activity and extract the string
Intent intent = getIntent();
String taskingalert = intent.getStringExtra(SmsBroadcastReceiver.EXTRA_MESSAGE);
// Capture the layout's TextView and set the string as its text
TextView receivedAlert = findViewById(R.id.receivedAlert);
receivedAlert.setText(taskingalert);
public boolean respond(View view) {
if (!hasReadSmsPermission()) {
requestReadAndSendSmsPermission();
return false;
}
Intent intent = new Intent(this, SendResponseActivity.class);
startActivity(intent);
return false;
}
/**
* Runtime permission shenanigans
*/
private boolean hasReadSmsPermission() {
return (ContextCompat.checkSelfPermission(ReceiveAlertActivity.this,
Manifest.permission.READ_SMS) == PackageManager.PERMISSION_GRANTED) &&
(ContextCompat.checkSelfPermission(ReceiveAlertActivity.this,
Manifest.permission.RECEIVE_SMS) == PackageManager.PERMISSION_GRANTED) &&
(ContextCompat.checkSelfPermission(ReceiveAlertActivity.this,
Manifest.permission.SEND_SMS) == PackageManager.PERMISSION_GRANTED);
}
private void requestReadAndSendSmsPermission() {
ActivityCompat.requestPermissions(ReceiveAlertActivity.this, new String[]{Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS, Manifest.permission.SEND_SMS},
SMS_PERMISSION_CODE);
}
}
And the manifest is this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.alert6">
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.Alert6">
<activity
android:name=".SendResponseActivity"
android:parentActivityName=".ReceiveAlertActivity">
</activity>
<activity
android:name=".ReceiveAlertActivity"
android:parentActivityName=".MainActivity">
</activity>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".SmsBroadcastReceiver"
android:enabled="true"
android:exported="true"
tools:ignore="Instantiatable">
<intent-filter android:priority="999" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
Android Studio is showing errors in SmsBroadcastReceiver and ReceiveAlertActivity but not giving enough information to resolve them.
In SmsBroadcastReceiver, it tells me it cannot resolve method 'startActivity()'. Something needs to go in the brackets, but what?
In ReceiveAlertActivity the problems revolve around receivedalert and taskingalert. It cannot resolve setText because taskingalert is an unknown class. Obviously it's not a class, it's a string so I'm doing something wrong, but what?
Sorting out these problems may not be the end. At the moment I can't test if the app works because the build fails due to the above. Then if I get this lot working, I have some other challenges, like waking up the screen and playing a sound the broadcast receiver is triggered, and stopping the sound when the button is pressed.
You can use an Observable object in your BroadcastReceiver to store the piece of information you want to send and implement the Observer interface in your Activity so that it will be warned of every change occuring to the Observable object.
Related
What is the proper way to handle Bluetooth media buttons in an Android app? At this point, all I want is an event to fire when I press the pause/play button on my Bluetooth headset. Somehow, I had a working solution yesterday, and today it just doesn't work. Without reinstalling the app, or any update happening on my phone, the onReceive method of my subclass of BroadcastReceiver is never entered. I'm targeting Android 9.0, since this is just for myself.
I used the information in these two questions for the solution:
How to capture key events from bluetooth headset with android
BroadcastReceiver for ACTION_MEDIA_BUTTON not working
This is a bare minimum version of what was working yesterday, which currently does not work:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<uses-permission android:name="android.permission.BLUETOOTH" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".MediaButtonIntentReceiver">
<intent-filter android:priority="2139999999">
<action android:name="android.intent.action.MEDIA_BUTTON" />
</intent-filter>
</receiver>
</application>
</manifest>
MainActivity.java
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.AudioManager;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
MediaButtonIntentReceiver mMediaButtonReceiver = new MediaButtonIntentReceiver();
IntentFilter mediaFilter = new IntentFilter(Intent.ACTION_MEDIA_BUTTON);
AudioManager mAudioManager = null;
ComponentName mReceiverComponent = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
mReceiverComponent = new ComponentName(this, MediaButtonIntentReceiver.class);
mediaFilter.setPriority(2139999999);
registerReceiver(mMediaButtonReceiver, mediaFilter);
}
}
MediaButtonIntentReceiver.java
package com.example.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class MediaButtonIntentReceiver extends BroadcastReceiver {
public MediaButtonIntentReceiver() {
super();
Log.i("mylog", "init");
}
#Override
public void onReceive(Context context, Intent intent) {
Log.i("mylog", "receive");
abortBroadcast();
}
}
I tried to do a broadcast receiver dynamically for incoming SMS will show a toast but the app doesn't show anything.
I register the broadcast dynamically in the mainActivity like this.
MainActivity.java
package com.example.smsreader;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
public class MainActivity extends AppCompatActivity {
BroadcastReader reader = new BroadcastReader();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
IntentFilter filter = new IntentFilter("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(reader, filter);
}
}
This is brodcast class, the app will show a toast when the phone will receive a SMS but it doesn't
package com.example.smsreader;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BroadcastReader extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if("android.provider.Telephony.SMS_RECEIVED".equals(intent.getAction())){
Toast.makeText(context, "it is working", Toast.LENGTH_LONG).show();
}
}
}
I don't register anything in the manifest file.
Manifest file
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.smsreader">
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Try the following :
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
You need to use the following method for registering local broadcastReceiver ;)
LocalBroadcastManager.getInstance(this).registerReceiver(reader, filter)
I am trying to detect if any calls are presently being attended or the cell phone is ringing.If not, the cell radio should switch off.Since I am using telephony manager for the first time. I am not able to rectify the error.
The error is " cannot resolve 'setRadioPower(?)'.
My MainActivity.java is:
public class MainActivity extends AppCompatActivity {
private TelephonyManager tm;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TelephonyManager telephonyManager =
(TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
PhoneStateListener callStateListener = new PhoneStateListener() {
public void onCallStateChanged(int state, String incomingNumber)
{
if(state==TelephonyManager.CALL_STATE_RINGING){
Toast.makeText(getApplicationContext(),"Phone Is Ringing",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_OFFHOOK){
Toast.makeText(getApplicationContext(),"Phone is Currently in A call",
Toast.LENGTH_LONG).show();
}
if(state==TelephonyManager.CALL_STATE_IDLE){
tm.setRadioPower(disabled);
}
}
};
telephonyManager.listen(callStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
}
My AndroidManifest.xml is:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.vk9621.radiocall">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
</manifest>
My imports are:
import android.content.Context;
import android.content.Intent;
import android.provider.Settings;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.Menu;
import android.view.View;
import android.widget.Toast;
Can someone tell me how to rectify this error?
The reason you won't find it in the developer docs is that it is hidden.
However, you may always find hidden methods in the Android Source Code.
Code reference: public boolean setRadioPower(boolean turnOn){}
If your phone is not rooted, or if you do not have system permission android.Manifest.permission.MODIFY_PHONE_STATE, you won't be able to access this API.
However, if you do have those permissions, you can easily achieve this using the following code:
ITelephony iTelephony = ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
try {
iTelephony.setRadioPower(true);
} catch (RemoteException e) {
e.printStackTrace();
}
I want to block incoming SMS message as long as my application is running . I could achieve that but the problem is after I close the app or even restart or even uninstall it the user will not be able to receive SMS message anymore . So How can I make the application to block incoming SMS only when it's running and when it gets closed or uninstalled etc.. to stop blocking SMS. Here's my code :
BroadCastReceiver.Java
package com.example.sms;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
public class BroadCastReceiver extends BroadcastReceiver
{
public void onReceive(Context context, Intent intent)
{
abortBroadcast();
}
}
MainActivity.java
package com.example.sms;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
Manifiest :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.sms"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver android:name=".BroadCastReceiver">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<activity
android:name="com.example.sms.MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Note: I've tested the application on android 2.2 on my android emulator "Sent SMS messages using Telnet"
Check if your app is running then only abort broadcast receiver else not
//define this variable above onReceive() with default value as false;
boolean appRunningInBack=false;
ActivityManager am = (ActivityManager) mContext.getSystemService(Activity.ACTIVITY_SERVICE);
String packageName = am.getRunningTasks(1).get(0).topActivity.getPackageName();
if(packageName.equalIgnoreCase("your app package name") || appRunningInBack)
{
appRunningInBack=true;
abortBroadCast();
} else {
}
Also add Permission in AndroidManifest.xml
<uses-permission android:name="android.permission.GET_TASKS" />
After this when your app goes in background.or while running .this variable will be true.
I've been puzzling over this one recently, prior to 2.3.5 this seems to work fine (on my colleagues devices). However on mine it now never triggers.
I've stripped the code right back and made a very simple test application to see what's going on. Basically the onReceive code doesn't ever appear to trigger, even though adb/logcat does seem to show the register of the BroadcastReveiver does take place.
Here's the simple code I've gone for:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.broadcasttech.testsmsreceive"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk android:minSdkVersion="9" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<activity
android:label="#string/app_name"
android:name=".TestSMSReceiveActivity" >
<intent-filter >
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".mysmstestcall">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
</manifest>
Then:
package com.broadcasttech.testsmsreceive;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
import android.os.Bundle;
import android.util.Log;
public class TestSMSReceiveActivity extends Activity {
private BroadcastReceiver receiver;
private static final String TAG = "TestSMSApp";
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.i(TAG, " App has started up");
IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
Log.i(TAG, " Filter SMS_RECEIVED has been added");
//Extends BroadcastReceiver
receiver = new mysmstestcall();
registerReceiver(receiver,filter);
Log.i(TAG, " registerReceiver sorted");
}
//Also, to save headaches later
#Override
protected void onDestroy() {
Log.i(TAG, " unregistering Receiver");
unregisterReceiver(receiver);
Log.i(TAG, " done");
}
}
And finally
package com.broadcasttech.testsmsreceive;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
public class mysmstestcall extends BroadcastReceiver {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private static final String TAG = "TestSMSApp";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Intent recieved: " + intent.getAction());
if (intent.getAction() == SMS_RECEIVED) {
//any action you want here..
Log.i(TAG, "SMS received has triggered");
}
}
}
So it is a fairly simple app that should just log and tell me when the BroadcastReceiver is triggered, but it just won't fire at all.
Can anyone suggest whats wrong, I've checked various tutorials, checked as I know IceCreamSandwich is different, but tried to incorporate those fixes too and this doesn't make a difference either.
Thanks in advance!
The main problem is that this line in "mysmstestcall" is wrong:
if (intent.getAction() == SMS_RECEIVED)
should be changed to this:
if (intent.getAction().equals(SMS_RECEIVED))
Is there a reason that you have two recievers? You have a programatic listener and you have an XML listener
Programatic:
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
Log.i(TAG, " Filter SMS_RECEIVED has been added");
//Extends BroadcastReceiver
receiver = new mysmstestcall();
XML Listener:
<receiver android:name=".mysmstestcall">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"></action>
</intent-filter>
Are you sure you want these two? If you have two you will RECEIVE the same broadcast 2 times...
As for another ISSUE that I see is this line
if (intent.getAction() == SMS_RECEIVED)
When comparing strings you DO NOT compare them like this instead you'd have something like this:
if (intent.getAction().equalsIgnoreCase(SMS_RECEIVED))
I've got this once. It can be network's issue. These were my question and answer. You can add a sending intent and catch the result code. In my case, it was RESULT_ERROR_GENERIC_FAILURE. I tried to find other solutions for months but no luck, so I accepted that even though I don't want to :-(
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
import android.widget.Toast;
public class SmsBroadcastReceiver extends BroadcastReceiver{
public static final String SMS_BUNDLE = "pdus";
#Override
public void onReceive(Context context, Intent intent) {
Bundle intentExtras = intent.getExtras();
if (intentExtras != null) {
Object[] sms = (Object[]) intentExtras.get(SMS_BUNDLE);
String smsMessageStr = "";
for (int i = 0; i < sms.length; ++i) {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) sms[i]);
String smsBody = smsMessage.getMessageBody().toString();
String address = smsMessage.getOriginatingAddress();
smsMessageStr += "SMS From: " + address + "\n";
smsMessageStr += smsBody + "\n";
}
Toast.makeText(context, "A new message is added to the SMS List!!!\n"+smsMessageStr, Toast.LENGTH_SHORT).show();
//this will update the UI with message
InboxMain inst = InboxMain.instance();
inst.updateList(smsMessageStr);
}
}
}
manifest::
<receiver android:name=".SmsBroadcastReceiver" android:permission="android.permission.BROADCAST_SMS" android:exported="true">
<intent-filter android:priority="2147483647" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
permission::
<uses-permission android:name="android.permission.SEND_SMS"></uses-permission>
<uses-permission android:name="android.permission.RECEIVE_SMS"></uses-permission>
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.WRITE_SMS" />
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />