Handle Android App removing programmatically - android

I am trying to handle app removing.
My AndroidManifest.xml looks like this:
<uses-permission android:name="android.permission.GET_TASKS"/>
<receiver android:name=".receivers.UninstallIntentReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<data android:scheme="package" />
</intent-filter>
</receiver>
UninstallIntentReceiver.java
public class UninstallIntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// fetching package names from extras
LogUtils.i("HK_LOG " + this.getClass().getSimpleName(), "onReceive");
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("com.betconstruct.sportsbookModule")){
// User has selected our application under the Manage Apps settings
// now initiating background thread to watch for activity
new UninstallActivity(context).start();
}
}
}
}
}
When apps is stopped, onReceive() method is called, but when app is running, onReceive() method is not getting called.
In this case onReceive() is called:
But in this case onReceive() is not called:
If I click on close button (from settings, pic that I show with arrow), after that onReceive() method is called.
I feel that I must guest how to handle this action, and solve this problem.
Any kind of suggestion will help me. Thanks.

I am trying to handle app removing.
I'm not sure android.intent.action.QUERY_PACKAGE_RESTART is the intent you need.
From javadocs:
Ask system services if there is any reason to restart the given package. The data contains the name of the package.
This looks like an action that's needed for system services, it doesn't even have a documentation. Also note the #hide annotation, which means that this action is not exposed to public API and you shouldn't rely on that.
The actual action you are interested in should be android.intent.action.PACKAGE_REMOVED.
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package"/>
</intent-filter>
</receiver>
If I understand your question correct, you are trying to handle an action of removing an application within the same application, meaning you expect onReceive() method of BroadcastReceiver which is in Sportsbook application to be fired as soon as user removes Sportsbook application. That's not possible, because when user uninstalls your application, all your app data, apk, classes are removed, thus there doesn't exist that receiver anymore.
If you try to detect removal of application from another application (let's say you have 2 applications, and you want to track whether user removes one of your apps), then that would make sense, and onReceive() would be called as expected.

Related

Get notified when PlayStore adds app icon to home screen

Does PlayStore send any broadcast message with "com.android.launcher.action.INSTALL_SHORTCUT" action, when it adds app shortcut to home screen before/after the app get installed?
I heard of the following method:
Add <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> to manifest.xml
Extend BroadcastReceiver class, then override onReceive() method
Is it true that the above 2 steps will let app get notified when Play Store add app shortcut to home screen?
Here I don't think there is any listener available to listen shortcuts directly. but you could go through some tricky way like :
1) Listen to application install using listener. you could achieve it by registering following way :
<receiver android:name=".apps.AppListener">
<intent-filter android:priority="999">
<action android:name="android.intent.action.PACKAGE_ADDED"/>
<action android:name="android.intent.action.PACKAGE_INSTALL"/>
<data android:scheme="package"/>
</intent-filter>
2) In your AppListener broadcast receiver whenever you will get it triggered, keep delay of 5 to 10 second and perform action to get all installed applications using :
List<ApplicationInfo> packs = pm.getInstalledApplications(0);
Now you have all installed packages, iterate through them and callgetLaunchIntentForPackage() on each item
If a valid intent is returned, that means it exists on launcher, else if it returns null, the package doesn't launch from home screen.
REASON : Home screens shortcuts are subset of the launcher apps :)

Is it possible to have Android app without any Activities, but only with Services?

How can you make an app that does not contain Activity as main launcher, but contain service as main launcher?
Yes it is possible. Just don't define any activity in your AndroidManifest and you're fine.
What you should do however to be able for your services to be called, is to listen on some phone-actions with a broadcast receiver.
Something like this:
<receiver android:name="com.example.MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
</intent-filter>
</receiver>
The actions BOOT_COMPLETED and MY_PACKAGE_REPLACED are triggered when the user's device is rebooted (obviously) but also whenever an upgrade of your application (or initial install) is done (via the Play Store for example).
Then you can start your service again (or schedule an alarm for you service to be triggered x minutes/hours/days/...).
If you don't have any possible user input, another useful action is ACTION_USER_PRESENT. This one will be triggered whenever your user unlocks his phone.
CAUTION:
For the BOOT_COMPLETED action you need to add a permission in the manifest:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
Then in your 'MyBroadcastReciever' class you should not do anything special to check the actions. You know you will only get in there by the actions specified in the manifest, so your broadcast receiver will look something like this:
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Do your work here...
}
}
All services that will be ever triggered should be defined in the manifest also! Don't forget about that!

Widget onUpdate called when Configuration Activity is launched

I'm implementing a widget and I'm facing the following problems:
1) onUpdate is called when I add the widget to the home screen, even if I specified a Configuration Activity. As soon as I add it to the home screen, the APPWIDGET_ENABLED broadcast is sent, followed by the APPWIDGET_UPDATE and then the configuration activity is launched.. Is this a bug? How should I understand in the onUpdate method that is being invoked before the configuration activity has returned? I can do it through a shared preference value, but I'd like it to behave as written on the developer guide, i.e. the onUpdate method should not be called.
2) onUpdate is not called every updatePeriodMillis seconds, which have been set to 10000, i.e. 10 seconds for testing purposes.. Did I miss something in the receiver declaration within the Manifest file? I keep receiving the Lint warning Exported receiver does not require permission but I think this is a Lint issue and not my fault.
EDIT: I've just found this within the reference docs: Note: Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes. So it is correct that the widget is not updated how often I'd specified and I've changed the time to 1800000 milliseconds.
3) I want to deliver my own broadcast action to the widget provider, is it correct to add another receiver block in the Manifest targeting the same provider class or should I add only another intent action within the intent-filter that contains the APPWIDGET_UPDATE action? BTW, I've commented my second receiver block and it is not the cause of the problems above. I created another receiver block because I wanted to declare it as not exported, in order to let the intent-filter action be triggered only by my app code and not anyone else.
AndroidManifest.xml
<receiver android:name="MyWidgetProvider"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/my_widget_info" />
</receiver>
<receiver android:name="MyWidgetProvider"
android:exported="false">
<intent-filter>
<action android:name="org.test.mywidget.FORCE_SMALL_WIDGET_UPDATE" />
</intent-filter>
</receiver>
my_widget_info.xml
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="110dp"
android:updatePeriodMillis="1800000"
android:initialLayout="#layout/my_widget_layout"
android:configure="org.test.mywidget.MyWidgetConfiguration"
android:resizeMode="none">
</appwidget-provider>
Providing an answer after digging into the source code:
1) This is expected behavior see here
This method is also called when the user adds the App Widget
2) Seems you have found your own answer. For others looking for the docs go here
Note: Updates requested with updatePeriodMillis will not be delivered more than once every 30 minutes
3) Since the AppWidgetProvider extends BroadcastReceiver but is not declared final you can add the action from your second receiver
<receiver android:name="MyWidgetProvider"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.test.mywidget.FORCE_SMALL_WIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/my_widget_info" />
</receiver>
then you can override onReceive in your MyWidgetProvider class and if the action is your custom action handle it, otherwise call to the super.onRecieve(Context context, Intent intent) like so:
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction()
.equals("org.test.mywidget.FORCE_SMALL_WIDGET_UPDATE")){
// handle your action
} else {
super.onRecieve(context, intent);
}
}
as per the Guide:
AppWidgetProvider is just a convenience class. If you would like to
receive the App Widget broadcasts directly, you can implement your own
BroadcastReceiver or override the onReceive(Context, Intent) callback.
One thing to note with this, the update to the remote view will only be called at the updatePeriodMillis, regardless of you adding your own action to the Intent for the provider to handle.
Good Luck and Happy Coding!

PACKAGE_ADDED BroadcastReceiver doesn't work

I have a broadcast receiver registered in Manifest:
<application ...>
<receiver android:name="com.some.pkg.NewAppReceiver" >
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
</intent-filter>
</receiver>
</appcication>
And the receiver:
public class NewAppReceiver extends BroadcastReceiver {
private static final String TAG = "NewAppReceiver";
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "Intent: " + intent.getAction());
}
}
And nothing is received when I install APK manually or from the Android Market. Why?
Did you run the app that contains this broadcastReceiver before installing the other apps?
Starting at some API version, broadcastReceivers will not work till you execute the app. Put an activity and execute it.
Also , don't forget to add the following into the broadcastReceiver:
<data android:scheme="package" />
EDIT: On Android 8 and above, if your app targets API 27 or more, it will work partially, so you have to register to those events in code and not in manifest. Here's a list of intents that are still safe to use in manifest: https://developer.android.com/guide/components/broadcast-exceptions.html .
The rest should be used in code. More info here
Since android.intent.action.PACKAGE_ADDED is a System Intent (note that your own app will not receive it at its installation), your BroadcastReceiver will receive messages from sources outside your app. Thus, check you did NOT put: android:exported="false"
You also may need to add:
<data android:scheme="package" />
So, your BroadcastReceiver in your AndroidManifest.xml should look like this:
<application ...>
<receiver android:name=".NewAppReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
</appcication>
If it still doesn't work, you may try to put an higher priority, such as: android:priority="1000"
Take a look at: http://developer.android.com/guide/topics/manifest/receiver-element.html
Registering receiver from manifest would not work from API 26(android 8). Because it had performance impact on older versions.
But we can register receiver from java code and receive updates of removed and added applications.
val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
intentFilter.addDataScheme("package")
registerReceiver(YourBroadcastReceiver(), intentFilter)
Are you trying to receive the intent in the application you are installing? The documentation for ACTION_PACKAGE_ADDED says:
Note that the newly installed package does not receive this broadcast.
Another possibility is that this intent might not be delivered to components registered via the manifest but only manually (as described in an answer by Mark Murphy to Stack Overflow question Can't receive broadcasts for PACKAGE intents).
If you try to receive some other package it must be worked.
(As #Savvas noted) If you try to receive your own package's addition you can't receive it. Even if your broadcast receiver has action.PACKAGE_ADDED, receiver's onReceive method isn't triggered.
In this case your best bet is saving this data. By using sharedPreferences, add a key something like "appIsWorkedBefore", and on your launcher Activity's onCreate method set this variable as "true". And you can make your works with respect to this Boolean.
This intent action is no longer available for applications.
This is a protected intent that can only be sent by the system.
https://developer.android.com/reference/android/content/Intent#ACTION_PACKAGE_ADDED

BroadcastReceiver with intent-filter for them?

Her is what I'm trying to accomplish:
When user tries to share some text from any app (Like sharing a tweet or a link), my app will appear in the sharing list.
If he select my app, some simple code will be run (like showing a Toast) then that's it. No interface or UI is needed.
Here is how I did it:
AndroidManifest.xml
<receiver
android:name=".MyBroadcastReceiver" >
<intent-filter
android:label="select my app">
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</receiver>
MyBroadcastReceiver.java
public void onReceive(Context arg0, Intent arg1) {
// TODO Auto-generated method stub
//Some simple code
Toast.makeText(arg0, "My Receiver is cool", Toast.LENGTH_LONG).show();
}
This didn't work, my app doesn't show in the sharing list.
Why I work with BroadcatReceivers and not with Activities? Because I don't want any UI and I think that is why we have receivers (correct my plz)
Am I doing it right?
This didn't work, my app doesn't show in the sharing list.
ACTION_SEND is used with activities. You are attempting to use a BroadcastReceiver. Since a BroadcastReceiver is not an activity, this will not work.
Am I doing it right?
No.
If he select my app, some simple code will be run (like showing a Toast) then that's it. No interface or UI is needed.
You still need an activity. However, if you give the activity Theme.NoDisplay, and you do not call setContentView(), there will be no UI for the activity. Usually, you just call finish() from onCreate() after doing whatever it is you wanted to do (in this case, display a Toast).
For example, this sample application shows an activity (FauxSender) set up to do precisely what you want: respond to ACTION_SEND with a Toast. It has another activity that issues an ACTION_SEND so you can see the results.

Categories

Resources