Android: BroadcastReceiver: UNINSTALL_PACKAGE intent - java

I need to detect when my app is being uninstalled. For that, I've seen logcat sends out UNINSTALL_PACKAGE intent, and I simply added it to existing Broadcast Receiver I have. But it just doesn't catch it, while other intent I'm listening to, TIME_TICK, works perfectly. Why?
Code currently used:
private IntentFilter intentFilter;
static {
intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_TIME_TICK);
intentFilter.addAction(Intent.ACTION_UNINSTALL_PACKAGE);
}
private final BroadcastReceiver receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action.equals(Intent.ACTION_UNINSTALL_PACKAGE) {
Log.e("App", "Uninstalling");
} else if (action.equals(Intent.ACTION_TIME_TICK){
// this works
}
}
};

I need to detect when my app is being uninstalled
There is no supported way to do this, for obvious security reasons.
But it just doesn't catch it
ACTION_UNINSTALL_PACKAGE is an activity action. Nothing on an Android device should be sending it as a broadcast. Hence, you cannot listen to it via a BroadcastReceiver.

I 've seen logcat sends out UNINSTALL_PACKAGE intent, and I simply added it to existing Broadcast Reciever I have. But it just doesn't catch it, while other intent I'm listening to, TIME_TICK, works perfectly. Why?
Whenever your application is being uninstalled, Android OS kills all the components associated with that application as well free memory & resources. Uninstall broadcast receiver intent was to listen uninstall event of others app not for your app.
If you want to capture uninstall event of your app then there is no concept google provides, however you can do by observing data change in your file system where you need to keep monitoring changes in file system.
This solution is not going to work for all phones & different versions of Android.

Can't you just listen for android.intent.action.PACKAGE_REMOVED with your IntentFilter when you uninstall using ACTION_DELETE or ACTION_UNINSTALL_PACKAGE?

Related

startActivity() in BroadcastReceiver

I am trying to create an application that calls the sender of an SMS as soon as the smartphone receives an SMS.
This is my code:
public class SmsReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")){
// ... (Managing SMS)
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + sender));
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
}
But it dials and calls the sender only when the application is in foreground, while I'd like it to work always. Using the debugger, the execution flows, but it is unable to start the ACTION_CALL activity somehow. Am I missing anything? Thank you very much in advance
Since Android 10, there are limitations on when/how background processes (Service, BroadcastReceiver) can launch activities. This is your problem.
See this guide for more details.
while I'd like it to work always
That is not an option on modern versions of Android. You cannot start an activity from the background, because you do not know what is going on in the foreground at the time. For example, if the user is relying on a navigation app for driving, taking over the foreground could cause the user to crash.
You could raise a high-priority Notification instead.

Can a homescreen widget BroadcastReceiver listen for phone events?

I am trying to update my homescreen widget when there is a Do not Disturb change. Because WidgetProvider is a BroadcastReceiver in itself, I thought it would be simple. But I am not seeing any Toast when I switch Dnd on or off. Does it mean that the WidgetProvider can only send broadcasts but not receive them?
Here is my code:
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
String action = intent.getAction();
assert action != null;
if (action.equals(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED)) {
System.out.println("Success!");
}
}
You do not show how you are registering for that broadcast. If it is in the manifest, the broadcast that you are trying to receive is not listed on the implicit broadcast exceptions "whitelist", so you may not receive it on Android 8.0+. The only way that you would be able to receive that broadcast on Android 8.0+ is if you have a foreground service running all the time, and that has costs.
Also:
I am not familiar with that specific broadcast and so I am uncertain if it is sent on a DND change (though it certainly seems plausible)
You are not showing a Toast; instead, you are printing a message to stdout, which should get redirected to Logcat on Android

Background Service for update location in background

it kills background service, to solve your issue you should use foreground service.
my background sticky service is kill on oreo and heigher devices any solution for getting location on background service when Activity is on backound
It's because of Android Oreo behaviour changes for background execution. Suggested alternatives are
1) Foreground service.
Use this if you are ok displaying notification to the user when you are trying to retrieve the location using Location API. This would be reliable and is suggested in the documentation.
Sample app from the documentation :
LocationUpdatesForegroundService project on GitHub
An example of an app that allows the app to continue a user-initiated
action without requesting all-the-time access to background location.
References
https://developer.android.com/training/location/receive-location-updates
2) Work Manager
This approach would be less reliable as you will not be able to control when exactly this would be called but can be used if you don't want to show notification to the user at all.
You would not be able to run background services long running in Oreo as there are behavior changes, now Oreo to optimize system memory, battery etc, it kills background service, to solve your issue you should use foreground service.
Have a look at Background execution limits https://developer.android.com/about/versions/oreo/android-8.0-changes
A suggestion from me, if you can use FCM then go for it, because apps like WeChat, Facebook uses it, to deliver notifications and they don't face any problem.
Alternate solution which I have opted without FCM due to client requirement to run service that updates location in background. Here are steps below:-
You need to start your background service with showing notification in Oreo and above.
Them after that you need to keep in mind that after some time phone enters into Doze mode so you have to tackle that also
In Addition, Battery optimization must be disabled for the application too.
In Some custom ROM you need to manage the Auto-start permission to restart your service if the service is killed by the android.
And the most important part is, if the service is killed by the android system then send a Broadcast Message to the Broadcast receiver to restart your service one again
Hope you will do some more R&D work.
I have shared my experience and the process by which i have done the same to run the service in the background.
you must show notification for ForegroundService
public class ForegroundService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
and add permission
<uses-permissionandroid:name=”android.permission.FOREGROUND_SERVICE” />

How to communicate between android and another process using broadcast receiver

I have a problem with registering a broadcastReceiver between my Activity and my Service which is defined in another process in my manifest.
I've tried some other tips like using handlers or ContentProvider
for communicating but it did't work as I expected, In fact I want to get the data continuously.
Here is my code in my Service:
Intent locationIntent = new Intent("LocationIntent");
locationIntent.setAction("updatedLocations");
locationIntent.setClass(getApplicationContext(), MapBoxActivity.class);
locationIntent.putExtra("list",updatedList);
sendBroadcast(locationIntent);
and I register it in OnCreate of my Activity:
updatedLocationBroadcast = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Timber.tag("localB").d("registered!");
if (intent != null && intent.getAction() != null && intent.getAction().equals("updatedLocations")) {
sawLocationsList = (HashMap<Integer, MarkerItem>)intent.getSerializableExtra("list");
Timber.tag("sawL").d("updated" + sawLocationsList.toString());
}
}
};
registerReceiver(updatedLocationBroadcast , new IntentFilter("updatedLocations"));
As I expected, I wanted to see my broadcastReceiver registers and my Timber logs localB registered! which is defined in my receiver but it doesn't work.
So, What's the best way to communicate between Activity and Service defined in another process and getting data continuously???
Note : my service gets data from server but the server is not realTime so I check the data by requesting periodically to server using handlers.
but it doesn't work
That is because you over-specified your Intent. Replace:
Intent locationIntent = new Intent("LocationIntent");
locationIntent.setAction("updatedLocations");
locationIntent.setClass(getApplicationContext(), MapBoxActivity.class);
locationIntent.putExtra("list",updatedList);
sendBroadcast(locationIntent);
with:
Intent locationIntent = new Intent("updatedLocations");
locationIntent.putExtra("list",updatedList);
sendBroadcast(locationIntent);
Note, though, that any app will be able to listen to this broadcast. Consider using setPackage() on the Intent to restrict the delivery to your own app.
What's the best way to communicate between Activity and Service defined in another process and getting data continuously?
If I were forced into this process separation, I would consider a Messenger.
my service gets data from server but the server is not realTime so I check the data by requesting periodically to server using handlers.
That hasn't been a recommended pattern in years. Please use WorkManager. Or, use JobScheduler, if you are not in position to adopt WorkManager (since it is part of AndroidX). In either of those approaches, you could get rid of the second process and greatly simplify your communications.

Check if downloads are active

So I'm using Download Manager to download multiple files in my app. I need these files to finish downloading before starting a certain activity. How can I check if there are active downloads, so I can tell the user to wait until the downloads are finished. And then, when they are finished, I need to make a button visible. I've googled this, even tried some code myself(blindly) and nothing works. If somebody can nudge me in the right direction I'd be grateful.
Use query() to inquire about downloads. When you call enqueue(), the return value is an ID for the download. You can query by status as well:
Cursor c = downloadManager.query(new DownloadManager.Query()
.setFilterByStatus(DownloadManager.STATUS_PAUSED
| DownloadManager.STATUS_PENDING
| DownloadManager.STATUS_RUNNING));
To be notified when a download is finished, register a BroadcastReceiver for ACTION_DOWNLOAD_COMPLETE:
BroadcastReceiver onComplete = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do something
}
};
registerReceiver(onComplete, new IntentFilter(
DownloadManager.ACTION_DOWNLOAD_COMPLETE));
Note that you should also listen for the ACTION_NOTIFICATION_CLICKED broadcast to know when a user has clicked the notification for a running download.

Categories

Resources