Speed up the startup of BroadcastReceiver at reboot - java

I've an app where the user can call custom lock screen to lock his/her mobile, that is an activity called LockScreen.class.
One this screen is loaded, i.e. the deviced is locked, a SharedPreferences called IsLocked is assigned to be true.
once the user do what he need with tthe lock screen this islocked became false, and the mobile is back to normal.
Every hing is working fine as expected.
The problem is, if for some reason the mobile had been rebooted while the lock screen is active, it is not running back upon a reboot.
So, I created a BootReciever as below, this works fine BUT after having the reboot process completed, and the user can do many things before it is loaded, my question is how can I make it loaded faster? so that the mobile screen is locked again with the custom activity before giving the chance for the user to do anything with the mobile?
public class BootReciever extends BroadcastReceiver
{
SharedPreferences mPrefs;
final String IsLockedPref = "IsLocked";
#Override
public void onReceive(Context context, Intent intent) {
mPrefs = PreferenceManager.getDefaultSharedPreferences(context);
Boolean islocked = mPrefs.getBoolean(IsLockedPref, false);
Intent i;
if (islocked)
i = new Intent(context, LockScreen.class);
else
i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
}
part of the manifiest file is:
<receiver android:name=".BootReciever"
android:enabled="true"
android:exported="true">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
UPDATE
I tried to get use of this by granting Device Admin by adding the below, but nothing improved:
In the main Activity:
private static final int ADMIN_INTENT = 15;
private static final String description = "Some Description About Your Admin";
private DevicePolicyManager mDevicePolicyManager;
private ComponentName mComponentName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mDevicePolicyManager = (DevicePolicyManager)getSystemService(
this.DEVICE_POLICY_SERVICE);
mComponentName = new ComponentName(this, AdminReceiver.class);
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mComponentName);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,description);
startActivityForResult(intent, ADMIN_INTENT);
.
.
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ADMIN_INTENT) {
if (resultCode == RESULT_OK) {
Toast.makeText(getApplicationContext(), "Registered As Admin", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getApplicationContext(), "Failed to register as Admin", Toast.LENGTH_SHORT).show();
}
}
}
and created empty receiver to extend the DeviceAdminReceiver as:
public class AdminReceiver extends DeviceAdminReceiver {
}
and added the below to the manifiest:
<receiver
android:name="AdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="#xml/admin"/>
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>

One thing you can do from your side is to set a priority to your intent-filter. From documentation
It controls the order in which broadcast receivers are executed to receive broadcast messages. Those with higher priority values are called before those with lower values.
<intent-filter
android:priority="100">
...
</intent-filter>
The value must be an integer, such as "100". Higher numbers have a higher priority. The default value is 0. The value must be greater than -1000 and less than 1000.

Related

Android 8.0 - Job Intent Service does not run application on bootup

Initially I had Android 7.0 and didn't have any issues using a BroadcastReceiver and service. However with changes to Android 8.0. I needed to switch to a JobIntentService so my application can run on bootup.
I have tried migrating my code to match the JobIntentService but nothing is happening on bootup.
I am unsure whether the reason is because of my service class or my BroadcastReceiver class.
AndroidManifest.xml
<service android:name=".backgroundService"
android:permission="android.permission.BIND_JOB_SERVICE"/>
backgroundService.java
public class backgroundService extends JobIntentService {
public static final int JOB_ID = 0x01;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, backgroundService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
Toast.makeText(this, "Application and Service Started", Toast.LENGTH_LONG).show();
Intent dialogIntent = new Intent(this, Home.class);
dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(dialogIntent);
}
}
startOnBoot.java
public class startOnBoot extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_BOOT_COMPLETED)) {
Log.i("In" , "getAction() - Boot");
backgroundService.enqueueWork(context, intent);
}
else
Log.i("No" , "Boot");
}
}
So I am trying to essentially start the Home.class on bootup.
I tried it and it could run normally. You could check three tips below.
1.Check whether you have declared RECEIVE_BOOT_COMPLETED permission or not.
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
2.Check whether you have declared the receiver with BOOT_COMPLETED action.
<receiver android:name=".startOnBoot">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
3.Remove Toast.makeText(this, "Application and Service Started", Toast.LENGTH_LONG).show(); in your service or toast it in main thread. Otherwise it gives you the error java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare().

Broadcast receiver not working when app is closed

So I have two different apps made, one sends a broadcast and another receives it and displays a toast. However, when I close the receiver app the broadcast is no longer received by the second app even though I defined the receiver in the manifest file.
The broadcast sender in the MainActivity of app1.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b = (Button)findViewById(R.id.button2);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent();
i.setAction("com.example.ali.rrr");
i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
sendBroadcast(i);
Log.e("Broadcast","sent");
}
});
}
App 2 broadcast receiver:
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "Broadcast has been recieved!", Toast.LENGTH_SHORT).show();
Log.e("SUCCESS", "IN RECIEVER");
//throw new UnsupportedOperationException("Not yet implemented");
}
App 2s Manifest:
<?xml version="1.0" encoding="utf-8"?>
<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">
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.ali.rrr" />
</intent-filter>
</receiver>
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main"
android:theme="#style/AppTheme.NoActionBar" />
<activity
android:name=".Main2Activity"
android:label="#string/title_activity_main2"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
After registering my BroadcastReceiver (BR) statically in the manifest, applying the proper intent filters, using JobIntentService (and registering it in the manifest) to handle the work that was called from my BR, I was still getting inconsistent results.
Once all of what I listed above has been done you should be able to send an ADB command to activate your broadcast and process the work in your service even if the app is closed. This was working for me some of the time, but not all of the time.
This article describes limitation to BRs.
"As of Android 3.1 the Android system excludes all receiver from receiving intents by default if the corresponding application has never been started by the user or if the user explicitly stopped the application via the Android menu" (AKA a user executes Force Stop)
When I start the app by debugging it, then swipe it closed on my device, my ADB command never activates my BR. However, after my debugging session is over, when I open up the app on my device and swipe it closed, I can activate my BR through ADB commands.
This occurs because when you debug an application, then manually swipe it closed on the device, Android considers this a Force Stop hence why my BR cannot be activated until I re-open the app on the device without debugging.
Scoured the internet for hours, and wasn't able to find my solution, so I thought I'd post it here just in case some poor unfortunate soul is encountering the same weird functionality I was.
Happy coding :)
First of all you need to use the Service for this functionality to work.
In the Activity you can start and stop the service by using the below codes.
// to start a service
Intent service = new Intent(context, MyBrodcastRecieverService.class);
context.startService(service);
// to Stop service
Intent service = new Intent(context, MyBrodcastRecieverService.class);
context.stopService(service);
Then you can use the below service
public class MyBrodcastRecieverService extends Service
{
private static BroadcastReceiver br_ScreenOffReceiver;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onCreate()
{
registerScreenOffReceiver();
}
#Override
public void onDestroy()
{
unregisterReceiver(br__ScreenOffReceiver);
m_ScreenOffReceiver = null;
}
private void registerScreenOffReceiver()
{
br_ScreenOffReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
Log.d(TAG, "ACTION_SCREEN_OFF");
// do something, e.g. send Intent to main app
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(br_ScreenOffReceiver, filter);
}
}
I faced this issue recently. The BroadcastReceiver was working fine even if the app was removed from the background in the emulator and Samsung phones. But it failed to start my app in Chinese manufactured phones like Realme, Mi etc. While struggling to find a way to fix this I found that in the app details page there is battery optimisation settings where the Auto-launch feature was disabled. After I enabled it the app was working fine and BroadcastReceiver was able to start the app. I was unable ti find a way to enable this setting programmatically but I found this question which helped me direct the user to that setting page.
You can go through below solution;
Activity.java
Intent intent=new Intent(MainActivity.this,BroadcastService.class);
startService(intent);
BroadcastService.java
public class BroadcastService extends Service {
private static MusicIntentReceiver br_ScreenOffReceiver;
#Override
public IBinder onBind(Intent arg0)
{
return null;
}
#Override
public void onCreate()
{
registerScreenOffReceiver();
}
#Override
public void onDestroy()
{
}
private void registerScreenOffReceiver()
{
br_ScreenOffReceiver = new MusicIntentReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(Intent.ACTION_HEADSET_PLUG)) {
int state = intent.getIntExtra("state", -1);
switch (state) {
case 0:
Log.e("AAAAAAAAAA", "Headset is unplugged");
break;
case 1:
Log.e("AAAAAAAAA", "Headset is plugged");
break;
default:
Log.e("AAAAAAAAAAAA", "I have no idea what the headset state is");
}
}
}
};
IntentFilter filter = new IntentFilter(Intent.ACTION_HEADSET_PLUG);
registerReceiver(br_ScreenOffReceiver, filter);
}
}
Menifest
<service android:enabled="true" android:name=".BroadcastService" />
Try this way..
Intent i = new Intent();
i.setAction("com.example.ali.rrr");
i.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
i.setComponent(
new ComponentName("PackageNameApp2","PackageNameApp2.MainActivity"));
sendBroadcast(i);

Android - Unable to receive local broadcast in my activity from service

I have my main activity that start a service (Location service) and I want that service to broadcast the new location each time a new location is found.
Thanks to the log I know the service is working and I have new locations every seconds or so, but I never get the broadcast.
MainActivity.java
public class MainActivity extends Activity {
private static final String TAG = "mainActivity";
private CMBroadcastReceiver mMessageReceiver = new CMBroadcastReceiver();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// Start Service
startService(new Intent(this, LocationService.class));
super.onCreate(savedInstanceState);
}
#Override
public void onResume()
{
LocalBroadcastManager.getInstance(this).registerReceiver(
mMessageReceiver, new IntentFilter(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE));
super.onResume();
}
#Override
public void onPause()
{
LocalBroadcastManager.getInstance(this).unregisterReceiver(mMessageReceiver);
super.onPause();
}
}
CMBroadcastReceiver.java
public class CMBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "CMBroadcastReceiver";
public static final String RECEIVE_LOCATION_UPDATE = "LOCATION_UPDATES";
#Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "Received broadcast");
String action = intent.getAction();
if (action.equals(RECEIVE_LOCATION_UPDATE))
{
Log.i(TAG, "Received location update from service!");
}
}
}
LocationService.java
/**
* Callback that fires when the location changes.
*/
#Override
public void onLocationChanged(Location location) {
mCurrentLocation = location;
mLastUpdateTime = DateFormat.getTimeInstance().format(new Date());
Log.i(TAG, "onLocationChanged " + location);
Intent intent = new Intent(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Log.i(TAG, "Broadcast sent");
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cyclemapapp.gpstracker">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<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:label="#string/title_activity_main"
android:theme="#style/AppTheme.NoActionBar">
android:configChanges="orientation|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".LocationService" android:process=":location_service" />
</application>
I the log I can see that "Broadcast Sent" But I never get the "Broadcast Received"
Any help will would be greatly appreciated.
EDIT:
Edited how the intent was created in the location service as Shaishav suggested.
Still doesn't work.
LocalBroadcastManager does not work across processes. Your Service is running in a separate process.
You can either run your Service in the same process as the Activity - by removing the process attribute from the <service> element - or use some sort of IPC instead - e.g., by sending and receiving the broadcasts on a Context instead of LocalBroadcastManager.
In your LocationService, send local broadcast using:
Intent intent = new Intent(CMBroadcastReceiver.RECEIVE_LOCATION_UPDATE);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
<service android:name=".LocationService" android:process=":location_service" />
Your service is in a separate process from the activity. LocalBroadcastManager is only for use in one process. Either remove android:process from the <service>, or use some IPC mechanism (e.g., system broadcasts, properly secured).

BroadcastReceiver not receiving boolean value after AlarmManager finishes set time

I am using a BroadcastReceiver to enable a button when it is triggered. I have an AlarmManager that runs for a certain amount of time. When the time has elapsed, it sends a broadcast like this:
Intent i = new Intent("polarCap1Status");
i.putExtra("polarCap1Stat", true);
LocalBroadcastManager.getInstance(context).sendBroadcast(i);
I use this code to receive the broadcast:
//broadcast receiver to allow button to be clicked again
mMessageReceiver1 = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
clickOnOff1 = intent.getBooleanExtra("polarCap1Stat", false);
polarCap1.setEnabled(clickOnOff1);
updateScores();
resources.edit().putBoolean("pc1Set", false).commit();
}//end onReceive function
};
LocalBroadcastManager.getInstance(getApplicationContext()).registerReceiver(mMessageReceiver1, new IntentFilter("polarCap1Status"));
I have the receiver setup in my manifest like so:
<receiver android:name="com.twentytwentythree.sab.SetupTimerPC1" >
<intent-filter>
<action android:name="polarCap1Status" />
</intent-filter>
</receiver>
SetupTimerPC1 is the name of the class that is sending the broadcast. It is sending it to another class called runGraphics.
Please let me know if you need any more information.
Edit:
I added an intent-filter to the receiver in the manifest but it has not changed anything.

Sending data from service to activity

I am having issue when sending data from Service to Activity through Notification , I click a Notification an Activity get invoked but when i try to add some parameters through bundle i am not able to get the parameters in that called intent , I have gone through the link
How to send parameters from a notification-click to an activity?
But still no luck.
Has the same issue occurred with somebody else ?
Thanks in advance.
You have to modify the Manifest file as well.
Here is the example that works:
These variables and methods are members of Service class:
public static final String MOVEMENT_UPDATE = "com.client.gaitlink.AccelerationService.action.MOVEMENT_UPDATE";
public static final String ACCELERATION_X = "com.client.gaitlink.AccelerationService.ACCELERATION_X";
public static final String ACCELERATION_Y = "com.client.gaitlink.AccelerationService.ACCELERATION_Y";
public static final String ACCELERATION_Z = "com.client.gaitlink.AccelerationService.ACCELERATION_Z";
private void announceAccelerationChanges()//this method sends broadcast messages
{
Intent intent = new Intent(MOVEMENT_UPDATE);
intent.putExtra(ACCELERATION_X, accelerationX);
intent.putExtra(ACCELERATION_Y, accelerationY);
intent.putExtra(ACCELERATION_Z, accelerationZ);
sendBroadcast(intent);
}
And this are the methods from Main activity:
You have to register receiver in the onResume method:
#Override
public void onResume()
{
IntentFilter movementFilter;
movementFilter = new IntentFilter(AccelerationService.MOVEMENT_UPDATE);
accelerationReceiver = new AccelerationServiceReceiver();
registerReceiver(accelerationReceiver, movementFilter);
startAccelerationService();
super.onResume();
}
private void startAccelerationService()
{
startService(new Intent(this, AccelerationService.class));
}
public class AccelerationServiceReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)//this method receives broadcast messages. Be sure to modify AndroidManifest.xml file in order to enable message receiving
{
accelerationX = intent.getDoubleExtra(AccelerationService.ACCELERATION_X, 0);
accelerationY = intent.getDoubleExtra(AccelerationService.ACCELERATION_Y, 0);
accelerationZ = intent.getDoubleExtra(AccelerationService.ACCELERATION_Z, 0);
announceSession();
updateGUI();
}
}
This is the part of AndroidManifest.xml file that has to be set in order to receive broadcast messages:
<activity android:name=".GaitLink"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="com.client.gaitlink.CommunicationService.action.ACTIVITY_STATUS_UPDATE" />
</intent-filter>
</activity>

Categories