I have a question pretty similar to this one, but it was asked 6 years ago I thought that maybe something has chnaged.
Basically I want no notify user when signal is lost. I've implemented class that inherits from PhoneStateListener and OnServiceStateChanged method in it. Also I have a service that runs in background and listens to changes. Everything works fine as long, as screen is on.
But apparently Android do not invoke OnServiceStateChanged when screen is off. Is there any way to get Android.Telephony.PhoneState directly from service or maybe some other workaround?
My code so far is below:
PhoneStateListener
Service
Try to create BroadcastReciever Class
https://developer.android.com/guide/components/broadcasts
and change the AndroidManifest.xml file, I think you required following permission
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
After creating Broadcast Receiver class insert following code snippet in AndroidManifest.xml
<receiver android:name="//BroadcastReceiver Class Name" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE">
</action>
</intent-filter>
</receiver>
AndroidManifest.xml file, I think you required following permission
<uses-permission
android:name="android.permission.MODIFY_PHONE_STATE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.CALL_PHONE" />
creating Broadcast Receiver class in AndroidManifest.xml
<receiver android:name=".services.Blocker">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
Blocker.java
public class Blocker extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
/* write your code here */
}
}
Related
I've implemented a BroadcastReceiver according to https://developer.android.com/guide/components/broadcasts but it does not seem to work.
The receiver part of my Manifest.xml looks like this (I use android.permission.ACCESS_NETWORK_STATE and android.permission.ACCESS_WIFI_STATE):
...
<receiver android:name=".BackgroundTask">
<intent-filter>
<action android:name="android.net.wifi.WIFI_STATE_CHANGED"/>
<action android:name="android.net.wifi.STATE_CHANGE" />
</intent-filter>
</receiver>
...
and it's declared within my application.
My BroadcastReceiver class looks like this:
public class BackgroundTask extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("Connection changed!");
Toast.makeText(context, "Network state changed", Toast.LENGTH_LONG).show();
}
}
Neither the toast is displayed nor I receive the println-ed output on my logcat.
I also read the note which recommends me to use scheduled jobs instead of receivers, but I could not find an example how to use this for listening to network changes.
The reason I want to use this is because I want my (background)-app only to run while my phone is connected to my WiFi - if you have any different suggestions on how to implement this, I'm also very thankful.
Btw. I'm using Android 8.0.0.
Cheers,
Nikolar
Update:
Somehow it still does not work. Am I forgetting anything?
Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="mypackagename">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<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=".BootReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_BOOT_COMPLETED"></action>
</intent-filter>
</receiver>
<receiver android:name=".BackgroundPoller">
</receiver>
</application>
</manifest>
Just for clearence I renamed my BackgroundTask-Class to BootReceiver:
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.d("INFO", "BootReceiver started");
Intent newIntent = new Intent(context, BackgroundPoller.class);
context.sendBroadcast(newIntent);
Log.d("INFO", "BackgroundPoller activated");
}
}
When I successfully send my broadcast
adb.exe shell am broadcast -a android.intent.action.ACTION_BOOT_COMPLETED
I still don't get a log output.
To get around Oreo's broadcast receiver restrictions, you have to register your receivers using Context.registerReceiver(). You could do this by subclassing Application and registering receivers in onCreate(). The only downside to doing this is your app would have to be launched to have Application.onCreate() get called. To get around this, you could register an ACTION_BOOT_COMPLETED receiver in your manifest as this action is exempt from the restriction. Your ACTION_BOOT_COMPLETED receiver doesn't have to do anything, but it will force your app to start running on boot and therefore Application.onCreate() will get called. Then the only challenge is keeping your app running because the system will kill it if the user doesn't go into it. There's a couple options to solve this. You could write a foreground service whose only purpose is to keep the app alive. Or perhaps use AlarmManager to schedule some intent that will wake your app back up, which will register your receivers again.
In the AndroidManifest file, I want to capture the BOOT_COMPLETED event when the user re-boots their device. I am adding this permission:
"uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"
I have seen two "intent-filters" used by others on Stackoverflow:
"Intent.ACTION_BOOT_COMPLETED" and
"android.intent.action.BOOT_COMPLETED"
What is the preferred action string here? Please advise and explain.
Intent.ACTION_BOOT_COMPLETED == android.intent.action.BOOT_COMPLETED
They're both the same, because if you look into what the value of Intent.ACTION_BOOT_COMPLETED is, you'll see that it's android.intent.action.BOOT_COMPLETED.
Typically in the Manifest, you'll use android.intent.action.BOOT_COMPLETED due to Intent.ACTION_BOOT_COMPLETED being Java code rather than xml.
But in your code, you can use Intent.ACTION_BOOT_COMPLETED as an alternative due to it being much easier to remember.
Here is a complete solution:
Set the permission in the manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
You need a receiver to run when your system restarts so something like this:
public class StartMyActivityAtBootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
// everything here executes after system restart
}
}
}
Include this receiver in your manifest like below:
<receiver
android:name=".service.StartMyActivityAtBootReceiver"
android:label="StartMyServiceAtBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
I'm trying to reset alarms in my app and using a receiver to get onBootCompleted. To see if the intent was received, I'm using a toast. The toast only appears if I immediately open the app. Otherwise, the toast does not appear. I looked at previous questions but almost all of them involve services, which I am not using. I am not sure if that is a part of the problem.
Android Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:installLocation="internalOnly"
package="package.name" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:configChanges="orientation|screenSize|keyboardHidden"
android:name=".MainActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<meta-data android:name="android.app.searchable"
android:resource="#xml/searchable" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
</intent-filter>
</activity>
<receiver android:name=".AlarmReceiver" >
<intent-filter>
<action android:name="android.intent.action.ALARM_SERVICE" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmReset"android:enabled="true" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
Receiver Class
public class AlarmReset extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Hello! Got message",
Toast.LENGTH_LONG).show();
//reset alarms etc. No service set.
}
I also tried writing the manifest receiver as
<receiver android:name=".AlarmReset" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
Key points I found online were to include permissions (which I did) and to watch out for logging.
What I do not understand is why it works if I immediately (within a few seconds, otherwise the toast does not appear) start my activity but is unsuccessful otherwise. I am considering testing a few possibilities like launching the activity itself through code or using a service like most others have. I am currently testing on Android 4.4 on an actual phone.
When an app is installed, it is in a stopped state. None of its components will be activated (such as your BOOT_COMPLETED receiver) until the app is moved out of this state by being launched by the user. This is why your app doesn't work unless you launch it once.
Note that force stopping the app from Settings also moves it into this stopped state.
See this page for more details (search the page for "launch controls").
Starting with Android 3.1 all applications, upon installation, are placed in a "stopped" state.(This is the same state that the application ends up in after the user force-stops the app from the Settings application.)
While in "stopped" state, the application will not run for any reason, except by a manual launch of an activity. (Meaning no BroadcastReceviers(ACTION_PACKAGE_INSTALLED, BOOT_COMPLETED etc.) will be invoked, regardless of the event for which they have registered, until the user runs the app manually.)
But you can start a serivice for ex-
1) In your element:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2) In your element (be sure to use a fully-qualified [or relative] class name for your BroadcastReceiver):
<receiver android:name="com.example.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
In MyBroadcastReceiver.java:
package com.example;
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent startServiceIntent = new Intent(context, MyService.class);
context.startService(startServiceIntent);
}
}
I feel the need to clarify the issue and solution, since the question was not clear (due to confidentiality issues).
The Basic Solution to my problem was just starting a service.
The Problem: I was trying to make the alarm in my class, AlarmReset, through AlarmManager. That in itself may have been an issue, but in addition, I tried to access objects that were instantiated in the MainActivity, furthering my dilemma. The reason why it worked when I opened MainActivity quickly enough, I suspect, is because I was able to instantiate the objects and set up the prerequisites for the class to directly access. I think the toast not appearing is similar to the issue.
The Solution: I set up a service class which I directed AlarmReset to. This is what I changed the AlarmReset class to:
public class AlarmReset extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent)
{
Toast.makeText(context, "Hello! Got message",
Toast.LENGTH_LONG).show();
//Pretty sure the Toast doesn't appear still.
Intent service = new Intent(context, Service.class);
context.startService(service);
}
Then my service class
public class Service extends IntentService {
private DataBaseManager database;
public Service()
{
super("Service");
}
#Override
protected void onHandleIntent(Intent intent)
{
database = new DataBaseManager(this);
Toast.makeText(this, "Hi",
Toast.LENGTH_LONG).show();
Toast.makeText(this, "Hello! Got message",
Toast.LENGTH_LONG).show();
//rest of code
}
Similarly, the text does not appear except if I am on the app immediately (I suspect it has to do with the threads).
Here, I made sure to instantiate my objects before using them (or did so after crashing).
A few possible problems that others may encounter (as I have read) are the following:
Installing in internal storage
android:installLocation="internalOnly"
and receiving permission for booting
<uses-permission
android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Some problems that people had suggested and were not very important were:
Using android:enabled and android:exported. Default values are fine
Writing the full receiver name. For me it wasn't necessary
<action android:name="android.intent.action.QUICKBOOT_POWERON" /> did not seem to do much.
I need to write data in to a file ,when system reboots not on boot complete.
i am using broadcast receiver "android.intent.action.REBOOT" Below is my code and manifest files
public class broadcastreceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Log.i("LOG_TAG","rebooted");
}
manifest file:
<application android:icon="#drawable/icon" android:label="#string/app_name">
<activity android:name=".broadcast"
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="com.example.broadcastreceiver.broadcastreceiver"
android:enabled="true"
android:exported="true"
android:permission="android.permission.REBOOT">
<intent-filter>
<action android:name="android.intent.action.REBOOT" />
</intent-filter>
</receiver>
</application>
but i am not able to write even a log when reboots.
note:i donot want to use Bootcompleted action in broadcast receiver
I can't see why you don't want to use BootCompleted, could you provide your reasons?
There is no other action that will alert your broadcast receiver of the boot. You will have to use BootCompleted.
As a note, I hope you are registering you BroadcastReceiver with the context (since you didn't include that code). If you're not using BootComplete, I don't know what action you've registered to expect your above code to execute.
Add this, to me work, but on new devices, there are no testing.
For example in the recent nexus not working.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
I have implement a feature that will update the database when needed.
(ex. change one of the column value of the database to B)
If system crash or reboot or something that is out of order,
is there any thing I can know then I can handle to recover the database back?
(ex. recover one of the column value of the database back to A)
Thanks for help.
<uses-permission android:name=”android.permission.RECEIVE_BOOT_COMPLETED” />
Define BroadcastReceiver which does the actions you want.
You will need in your manifest sth like:
<receiver android:name=”.MyReceiver”>
<intent-filter>
<action android:name=”android.intent.action.BOOT_COMPLETED” />
</intent-filter>
</receiver>
A crash, by definition, can't be caught.
That's what makes a crash a crash.
When device completes, it Broadcasts a intent and by registering to this broadcast u can get the call:
public class YourReceiverName extends BroadcastReceiver{
#Override
public void onReceive(final Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)){
//Do your task here....
}
}
}
add permission to manifest file:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
and register this receiver in manifest file:
<receiver android:name="Your receiver name">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
and for Database, it is upto you how you handle it and what your app demands.