I am using ACTION_UNINSTALL_PACKAGE to uninstall packages and am trying to retrieve the application name of the removed package after it is removed. I can only seem to get the package name. I cannot use ApplicationInfo on the package name since the package is already gone. I tried passing the value into the intent but since it goes to another activity that is not owned by me UninstallerActivity it is not there. I couldn't figure out how to pass the string into the IntentFilter data field since I need to use it for package name. I am not using sendBroadcast so I cannot use that.
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE);
intent.setData(Uri.parse("package:"+packageName));
intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.PACKAGE_REMOVED");
intentFilter.addDataScheme("package");
mContext.registerReceiver(mUninstallReceiver, intentFilter);
startActivity(intent);
}
private BroadcastReceiver mUninstallReceiver = new BroadcastReceiver(){
#Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
if (action != null) {
if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
Uri intentData = intent.getData();
//the above only contains package name
}
}
}
}
How do I pass the application name to this broadcast receiver?
Update
I ended up just using a member variable which isn't what I totally wanted, but it works.
How do I pass the application name to this broadcast receiver?
Define your own custom subclass of BroadcastReceiver, where you supply a PackageManager to the constructor
Have that constructor gather whatever information it needs from the PackageManager
Create an instance of that BroadcastReceiver before you call startActivity()
Hold onto that BroadcastReceiver object somewhere so you can unregister it as soon as you receive your broadcast
If there is a possibility that the user might request to uninstall 2+ apps before the first uninstall completes, have onReceive() confirm that the broadcast it received is for the package it is tracking, as with this plan, you will have 2+ BroadcastReceiver objects outstanding at any point in time
There are other possible ways of organizing this (e.g., Map of package name to data, so you only need one receiver), but they will all be along the same lines: collect the data you need before you uninstall, so that you have the data by the time you receive the broadcast.
Related
I use android:process for my service in AndroidManifest.xml
But i have to share variable with original process(main gui).
I know sharing memory between processes is not possible. So i have to use something like shared memory.
So android:process is also not possible to share variable?
Even though static variable?
jsut sharing data is possible via
String data="whatever you want to call you database"
context.getApplicationContext().getSharedPreferences(data, Context.MODE_PRIVATE).get("variableName")
... .set("variableName","variable");
if you also want to react to events:
LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent("action_value").putExtra("key","value"));
and
IntentFilter iFilter=new IntentFilter();
iFilter.add("action_value") //necessary whitelist per receiver
LocalBroadcastManager.getInstance(context).registerReceiver(new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
//do Stuffs
}
},iFilter);
Looking at the code sample here - I find the following comment puzzling:
// ... We assume here that the
// app has implemented a method called createShortcutResultIntent() that
// returns a broadcast intent.
what does it mean the app has implemented ... where is this implementation done?
is it a broadcast receiver? registered to which intent filter?
is this an abstract method? of which class?
and then I see this code sample - which handles a completely different flow (I think) and I'm lost again
You can obtain feedback via catching the broadcast event which you setup while use requestPinShortcut function.
At first you need a usual broadcast receiver (in the code below it has name ShortcutReceiver). You can even use existing broadcast receiver and simple add new action which it should catch.
Lets the action will be "general.intent.action.SHORTCUT_ADDED" and it will be stored in ShortcutReceiver.kInstalledAction constant. In this case in the manifest you should have:
<receiver android:name=".ShortcutReceiver" >
<intent-filter>
<action android:name="general.intent.action.SHORTCUT_ADDED"/>
</intent-filter>
</receiver>
After this you can use following code in the activity for create a pinned shortcut (in other places change this on object of Context class):
ShortcutManager manager = this.getSystemService(ShortcutManager.class);
Intent targetIntent = new Intent(ShortcutReceiver.kInstalledAction);
targetIntent.setPackage(this.getPackageName());
PendingIntent intent = PendingIntent.getBroadcast(this, 0, targetIntent, 0);
manager.requestPinShortcut(info, intent.getIntentSender());
In this code info is correct object of ShortcutInfo class.
You can handle the event while catch the broadcast:
public class ShortcutReceiver extends BroadcastReceiver {
public static final String kInstalledAction = "general.intent.action.SHORTCUT_ADDED";
#Override
public void onReceive(Context context, Intent intent) {
if (kInstalledAction.equals(intent.getAction())) {
// Handle the event after the shortcut has been added
Toast.makeText(context, "The shortcut has been added", Toast.LENGTH_LONG).show();
}
}
}
Please take into account that from my experience the broadcast event happens after the shortcut has been added but sometimes there can be some delays (at about some minutes). But may be there is some dependency on the launcher.
Update
As described in other answers on Android 8 catching of implicit intent via broadcast in general doesn't work.
So I simple changed the intent to explicit via set package name of the current app. So only our broadcast receiver can catch the intent.
First things first. Implicit intents on Android 8.0 Oreo:
Because Android 8.0 (API level 26) introduces new limitations for broadcast receivers, you should remove any broadcast receivers that are registered for implicit broadcast intents. Leaving them in place does not break your app at build-time or runtime, but they have no effect when your app runs on Android 8.0.
Explicit broadcast intents—those that only your app can respond to—continue to work the same on Android 8.0.
There are exceptions to this new restriction. For a list of implicit broadcasts that still work in apps targeting Android 8.0, see Implicit Broadcast Exceptions.
https://developer.android.com/about/versions/oreo/android-8.0-changes
Note: there are some exceptions: https://developer.android.com/guide/components/broadcast-exceptions (very few)
Instead, we will use the so-called context-registered receiver, it will last as long as our app lives, or until we unregister it.
Also, ShortcutManager requires API 25 that's why we will use it's compat version in order not to duplicate the code for old and new versions. (ShortcutManagerCompat was added in version 26.1.0)
Code to create a pinned shortcut on the Home screen:
public static void addShortcut(Context context, String id) {
if(context == null || note == null)
return;
//there may be various Home screen apps, better check it
if (ShortcutManagerCompat.isRequestPinShortcutSupported(context)){
Intent shortcutIntent = new Intent(context, MainActivity.class);
shortcutIntent.setAction(Constants.ACTION_SHORTCUT); // !!! intent's action must be set on oreo
ShortcutInfoCompat shortcutInfo = new ShortcutInfoCompat.Builder(context, note.get_id().toString())
.setIntent(shortcutIntent)
.setShortLabel("MyShortcut") //recommend max 10 chars
.setLongLabel("Long shortcut name")//recommend max 25 chars
.setIcon(IconCompat.createWithResource(context, R.drawable.ic_shortcut))
.build();
//callback if user allowed to place the shortcut
Intent pinnedShortcutCallbackIntent = new Intent(ACTION_SHORTCUT_ADDED_CALLBACK);
PendingIntent successCallback = PendingIntent.getBroadcast(context, REQ_CODE_SHORTCUT_ADDED_CALLBACK,
pinnedShortcutCallbackIntent, 0);
ShortcutManagerCompat.requestPinShortcut(context, shortcutInfo, successCallback.getIntentSender());
}
And here is the code to receive the broadcast in your Activity, for example. Note that this "callback" will be called only if your app is running, receiver is registered and the user allowed the shortcut:
private ShortcutAddedReceiver shortcutAddedReceiver;
private void registerShortcutAddedReceiver(){
if(shortcutAddedReceiver == null){
shortcutAddedReceiver = new ShortcutAddedReceiver();
}
IntentFilter shortcutAddedFilter = new IntentFilter(ShortcutHelper.ACTION_SHORTCUT_ADDED_CALLBACK);
registerReceiver(shortcutAddedReceiver, shortcutAddedFilter);
}
private void unregisterShortcutAddedReceiver(){
if(shortcutAddedReceiver != null){
unregisterReceiver(shortcutAddedReceiver);
shortcutAddedReceiver = null;
}
}
#Override
public void onStart() {
super.onStart();
registerShortcutAddedReceiver();
}
#Override
public void onStop() {
super.onStop();
unregisterShortcutAddedReceiver();
}
private class ShortcutAddedReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
Snackbar.make(view, "Shortcut added", Snackbar.LENGTH_LONG).show();
}
}
Hope this helps!
I have the activity SingleSpecial where a user clicks to share and initiates the actions below:
inviteFriend.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
// Send broadcast of the sharedId to the SharingAction
Intent i = new Intent();
i.setAction("com.example.specialSharing.SHARED_SPECIAL");
i.putExtra("specialId", specialId);
sendBroadcast(i);
// Open invite activity:
Intent specialSharing = new Intent(getBaseContext(), InviteFriendOrGroup.class);
startActivity(specialSharing);
}
}
The InviteFriendOrGroup.class is intended to open and the user selects a person to share with. Upon selecting the person to share, the SharingAction class will open and is supposed to accept the Broadcast from the activity two steps ago, from the SingleSpecial class.
I have setup the Broadcast receiver to accept the action, and setup in the onCreate method of SharingAction:
BroadcastReceiver:
public class SpecialInfoReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("Shared special received ", "received special id");
Bundle extra = intent.getExtras();
if (extra != null) {
String action = intent.getAction();
if (action.equals("com.example.specialSharing.SHARED_SPECIAL")) {
Toast.makeText(getApplicationContext(), "The shared special Id is ok", Toast.LENGTH_LONG).show();
}
}
}
}
receiver in the onCreate:
SpecialInfoReceiver specialInfoReceiver = new SpecialInfoReceiver();
IntentFilter filter = new IntentFilter("com.example.specialSharing.SHARED_SPECIAL");
this.registerReceiver(specialInfoReceiver, filter);
As can be seen, the receiver is to show a toast upon receiving the sepcialId action. But it does nothing.
How can I set this up to work?
As per android documentation for the constructor for Intent(String action):
Create an intent with a given action. All other fields (data, type, class) are null. Note that the action must be in a namespace because Intents are used globally in the system -- for example the system VIEW action is android.intent.action.VIEW; an application's custom action would be something like com.google.app.myapp.CUSTOM_ACTION.
As well as Intent.setAction()'s action parameter:
An action name, such as ACTION_VIEW. Application-specific actions should be prefixed with the vendor's package name.
Both suggest valid action names are ones that belong within your namespace (base package). Not prefixing the namespace can lead to widespread problems of clashing action names between different apps.
It is possible the broadcast was never successfully made due to an invalid action name. Try changing the action to <package>.SHARED_SPECIAL.
Consider using a LocalBroadcastManager if you only intend to send broadcasts within your application. It is safer (as in other app components won't suddenly trigger if they were listening on the Intent).
Have you added the Broadcast to the Manifest?
<receiver android:name="com.example.SpecialInfoReceiver"/>
Or if Broadcast is inside another class:
<receiver android:name="com.example.YourActivity.$SpecialInfoReceiver"/>
From the examples this looked straightforward. Maybe you can show me what I did wrong. I can't get an activity to receive a broadcast sent from a local service.
I have Activity1 that start Service1:
startService(new Intent(Activity1.this, Service1.class));
Activity1 then starts Activity2:
startActivity(new Intent(Activity1.this, Activity2.class));
Service1, a local service, listens for downloads:
protected final BroadcastReceiver service2DownloadBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(final Context context, final Intent intent)
{
...
broadcastDownloadFinished(Uri.fromFile(downloadedFile));
The broadcast receiver of Service1 then broadcasts its own message:
protected Intent broadcastDownloadFinished(final Uri uri)
{
final Intent intent = new Intent(ACTION_DOWNLOAD_FINISHED).setData(checkNotNull(uri));
sendBroadcast(intent);
Activity2, which is in the foreground at the time, listens for the ACTION_DOWNLOAD_FINISHED intent using its own broadcast receiver:
private final BroadcastReceiver activity2DownloadBroadcastReceiver = new BroadcastReceiver()
{
public void onReceive(final Context context, final Intent intent)
{
Log.i(Activity2.class.getSimpleName(), "Received download event: " + intent.getAction() + " " + intent.getData());
Activity2 of course registers the receiver:
protected void onResume()
{
super.onResume();
final IntentFilter downloadIntentFilter = new IntentFilter();
downloadIntentFilter.addAction(ACTION_DOWNLOAD_FINISHED);
registerReceiver(activity2DownloadBroadcastReceiver, downloadIntentFilter);
In case it matters, ACTION_DOWNLOAD_FINISHED is something like "com.example.intent.action.DOWNLOAD_FINISHED".
Service1 receives the download manager event in its receiver and apparently broadcasts its own custom event, but Activity2 never seems to receive it. What did I do wrong? Is it a problem to broadcast an intent in the middle of processing another one? (I wouldn't think so---this is asynchronous, right?)
Update: Just to make sure there is no problem sending a broadcast in the middle of receiving a broadcast, I changed my broadcast code to actually perform the broadcast three seconds later on the main thread:
Log.i(getClass().getSimpleName(), "...ready to broadcast");
final Intent intent = new Intent(ACTION_DOWNLOAD_FINISHED).setData(checkNotNull(uri));
mainThreadHandler.postDelayed(new Runnable()
{
public void run()
{
Log.i(getClass().getSimpleName(), "...broadcasting");
sendBroadcast(intent);
Log.i(getClass().getSimpleName(), "...broadcasted");
}
}, 3000);
Log.i(getClass().getSimpleName(), "...scheduled to broadcast");
As expected, the log says:
...ready to broadcast
...scheduled to broadcast
...broadcasting
...broadcasted
Yet nothing is received in the activity. Please help.
Eureka! I found it! The problem is that I supplied a data URI in my broadcast intent. The Android intent matching rules get a little complicated. If you supply a data URI, then your intent filter must specify a matching MIME type.
Unfortunately, although the Android documentation says that the data type can be inferred from the data URI, apparently Android doesn't know that a file://.../example.jpg is an image. So this doesn't work:
intentFilter.addDataType("image/*");
However, instead of specifying a type, I can specify a scheme that I accept:
intentFilter.addDataScheme("file");
That works! It's a little rough---and a little artificial to restrict my broadcasts to file: URIs, but as that's all I'm using for the moment, it works.
Note that apparently I could manually specify the MIME type in the intent when I broadcast it, but that's too much trouble for now, as I'm downloading images from Picasa so I already know that they are images (and don't care the specific MIME type). And if it gets too much trouble, I could ditch the whole setData() thing altogether and set an extra---but of course I want to do things the Right Way.
have you included your receiver in your activity's manifest?
<receiver
android:name=".YourReceiver">
<intent-filter>
<action
android:name="intent_name"></action>
</intent-filter>
</receiver>
I am trying to send a Broadcast from a service out to an Activity. I can verify the broadcast is sent from within the service, but the Activity doesn't pick up anything.
Here is the relevant service code:
Intent i = new Intent(NEW_MESSAGE);
i.putExtra(FriendInfo.USERNAME, StringUtils.parseBareAddress(message.getFrom()));
i.putExtra(FriendInfo.MESSAGE, message.getBody());
i.putExtra("who", "1");
sendBroadcast(i);
And the receiving end in the activity class:
public class newMessage extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(action.equalsIgnoreCase(IMService.NEW_MESSAGE)){
Bundle extra = intent.getExtras();
String username = extra.getString(FriendInfo.USERNAME);
String message = extra.getString(FriendInfo.MESSAGE);
String who = extra.getString("who");
}
}
}
The BroadcastReceiver is defined within an Activity. I am registering the receiver in the onCreate method of the Activity, not in the Manifest file.
I'm stumped as to why it won't rec. anything.
Any insight?
EDIT
Registering takes place as follows:
registerReceiver(messageReceiver, new IntentFilter(IMService.NEW_MESSAGE));
Where "messageReceiver" is defined as
private newMessage messageReceiver = new newMessage();
IMService.NEW_MESSAGE is merely a string = "NewMessage"
I'm not sure if it is specific to the set up, or if it is a fix in general, but moving the register/unregister to the onResume/onPause _respectively_ and not registering in the onCreate solved the problem for me.
Try this two things:
Use manifest file to register receiver(but it barely helps)
Try make your Receiver a regular class, not inner one.
Inner class broadcast receiver will not be able to handle broadcast(means it unable to locate that class ).
So make it as a separate class
Definitely it will work.