When I need to use Internet connection and it is not posible I want to set a broadcast receiver which keeps working if the app is closed.
I am using a service for that, but that it is not working. It works fine when the app is on screen or paused but it stops working if I close it. I am not pretty sure if I should use other thing or if I am doing something wrong.
This is my code:
package com.example.ana.exampleapp;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.util.Log;
public class TestsService extends Service {
private static BroadcastReceiver networkChangeReceiver;
private static String TAG = "Service";
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
Log.v(TAG, "Service created");
boolean keep = needTokeepWaiting()
if(!keep)
stopSelf();
}
#Override
public void onDestroy() {
if (networkChangeReceiver != null)
unregisterReceiver(networkChangeReceiver);
networkChangeReceiver = null;
Log.v(TAG, "Service destroyed");
}
private void registerNetworkChangeReceiver() {
networkChangeReceiver = new BroadcastReceiver() {
private String TAG = "NetworkReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.v(TAG, "Connection changed received");
boolean keep = needTokeepWaiting()
if(!keep)
stopSelf();
}
};
IntentFilter filter = new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkChangeReceiver, filter);
}
}
And my manisfest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ana.exampleapp">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".MainActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RegisterActivity"></activity>
<activity android:name=".FinishRegisterActivity"></activity>
<activity android:name=".TestActivity"></activity>
<activity android:name=".InformationActivity"></activity>
<service android:name=".TestsService"></service>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
And in the TestActivity when it is necessary I do:
Intent service = new Intent(this, TestsService.class);
startService(service);
What I am doing is similar to what it is suggested here, but it doesn't work:
Keep broadcast receiver running after application is closed
I have also tried to do it without a service and registering in the manifest, but It didn't work neither:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.ana.exampleapp">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity"
android:windowSoftInputMode="stateHidden">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".RegisterActivity">
</activity>
<activity android:name=".FinishRegisterActivity" >
</activity>
<activity android:name=".TestActivity">
</activity>
<activity android:name=".InformationActivity" >
</activity>
<receiver android:name=".NetworkChangeReceiver"
android:enabled="false">
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
</intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>
I have just found the problem. There is a bug in Android 4.4.x which kills background services when closing the app. I was testing my app in Android 4.4.2. Here there is a detailed explanation:
http://www.androidpolice.com/2014/03/07/bug-watch-stopping-apps-on-android-4-4-2-can-silently-kill-related-background-services-a-fix-is-on-the-way/
So my code was right as I have tried in Android 4.2.2 and it works (I have tried overriding onStartCommand() so maybe that was needed).
If you don't want your service to stop when the app is closed, you should override onStartCommand() method doing something like this:
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_REDELIVER_INTENT;
}
You can return START_STICKY or START_REDELIVER_INTENT, whatever works better for you
Related
i wrote this code in android studio , it wont show me the toast message :
here is the manifest file :
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application
android:allowBackup="true"
android:dataExtractionRules="#xml/data_extraction_rules"
android:fullBackupContent="#xml/backup_rules"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:supportsRtl="true"
android:theme="#style/Theme.MyApplication"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".BoradCastReciever"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.AIRPLANE_MODE"/>
</intent-filter>
</receiver>
</application>
</manifest>
and here is the java code class reciever :
package com.mohapp.myapplication;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class BoradCastReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean is_on = intent.getBooleanExtra("air", false);
if (is_on == true) {
Toast.makeText(context, "Air Plane mode is on", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(context, "Air Plane mode is false", Toast.LENGTH_LONG).show();
}
}
}
i am using API 33 with Gradle version 7.5 and Embedd JDK(jdk 11)
In API 30 and plus , it uses the java code more than manifest file and xml files
use onStart and onStop method and add intent inside and use this.register(obj claa of reciever) and unregister on stop method
I try to launch a service at boot, but it never starts the service. I added <action android:name="android.intent.action.ACTION_POWER_CONNECTED"/> to the intent-filter of the receiver, but when I connect my android 8.0 phone to power, it also doesn't work.
manifest:
<?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.madmagic.oqrpc">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:usesCleartextTraffic="true"
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" />
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MainService" />
<receiver
android:name=".StartAtBoot">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
</intent-filter>
</receiver>
</application>
</manifest>
StartAtBoot:
public class StartAtBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received", Toast.LENGTH_LONG).show(); //this never shows up when connecting to power
Intent i = new Intent(context, MainService.class);
context.startService(i);
}
}
MainService:
public class MainService extends Service {
public static boolean isRunning = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
isRunning = true;
Toast.makeText(this, "Service started", Toast.LENGTH_LONG).show();
ConnectionChecker.run(this); //when device has wifi connection, this will run connected() method
}
#Override
public void onDestroy() {
isRunning = false;
}
public void connected() {
//things to do when it has wifi connection
}
}
In my MainActivity class, I start this service using the same way as in my StartAtBoot class, and there it works fine when I open the application. So the service is working fine, its just that the StartAtBoot class doesn't run the code.
ACTION_POWER_CONNECTED is not a listed exception to the limits on implicit Intent broadcasts. Your app cannot register for it in the manifest.
If your goal is to do work periodically, but only if the device has power, use JobScheduler or WorkManager.
UPDATE 1:
I found the problem! When installing the APP, the user is not being asked for permission. I did it manually and it worked. New question, how do I get the app to request permission at startup?
ORIGINAL TEXT
I am trying to capture the incoming call number, but to no avail!
No error appears, that's the problem, so I must be missing some detail!
Here on stackoverflow, there are a lot of topics, but all are very old, and the answers don't 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="net.aaa.androidcall">
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PHONE_STATE" />
<application
android:allowBackup="false"
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=".ServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
</application>
</manifest>
ServiceReceiver.java
package net.aaaa.androidcall;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.view.Gravity;
import android.widget.Toast;
public class ServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.PHONE_STATE")){
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
String Number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
Toast toast = Toast.makeText(context, "Number: " +Number+ ", Status: "+ state,Toast.LENGTH_LONG);
toast.setGravity(Gravity.BOTTOM|Gravity.LEFT,3,0);
toast.show();
}
}
}
What am I missing that is not displaying the number in the toast?
I have been fighting with this problem for a week and after I read your entry, I solved the problem, Thank you very much.
It is adding this line to main activity:
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_CALL_LOG}, 1);
I just wrote this small app to show a small Toast everytime the Airplane Mode was changed. It doesn't work
package com.example.android.broadcastreceiverexample;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
import static android.widget.Toast.*;
public class MyReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent){
makeText(context, "Intent detected", LENGTH_LONG).show();
}
}
Here's the manifest file:
<?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.android.broadcastreceiverexample">
<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>
<receiver android:name=".MyReceiver" android:exported="true">
<intent-filter tools:ignore="ExtraText">
<action android:name="android.intent.action.AIRPLANE_MODE></action>
</intent-filter>
</receiver>
</application>
</manifest>
Is there something that I am missing here, conceptually or in the code?
I'm writing an app with a SmsReceiver. I want this class to receive message texts that contains a special word, like "SPY", and don't let other recievers, receive such messages. how can I do it?
here is the receiver class
package com.newidea.repairmycontacts;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import android.telephony.SmsMessage;
public class SmsReceiver extends BroadcastReceiver {
private final static String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
private final String TAG = "SmsReceiver";
#Override
public void onReceive(Context context, Intent intent) {
//onReceiveWithPrivilege(context, intent, false);
if(!intent.getAction().equals(SMS_RECEIVED))
return;
Bundle bundle = intent.getExtras();
if(bundle==null)
return;
Object[] pdus=(Object[]) bundle.get("pdus");
String Body="";
for(int i=0;i<pdus.length;i++)
Body += SmsMessage.createFromPdu((byte[]) pdus[i]).getMessageBody().toString()+"\n";
String Address=SmsMessage.createFromPdu((byte[]) pdus[0]).getOriginatingAddress();
Toast.makeText(context, "Message from "+Address+" : "+Body, Toast.LENGTH_LONG).show();
}
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.newidea.repairmycontacts"
android:versionCode="1"
android:versionName="1.0" >
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-sdk
android:minSdkVersion="11"
android:targetSdkVersion="17" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#android:style/Theme.NoTitleBar" >
<activity
android:name="com.newidea.repairmycontacts.SMSList"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
You have to set a priority on your intent-filter tag for .SmsReceiver like this:
<receiver android:name=".SmsReceiver">
<intent-filter android:priority="999">
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Be aware that this will work with stock messaging app, but some other sms apps use other priorities and may get on top of yours...
After if you want to prevent other apps from receiving the broadcast, you can use:
BroadcastReceiver.abortBroadcast()
Keep in mind that this is fragile specially with other sms apps.