I uninstalled an android mobile app and immediately got SMS that says "sorry to see you go". How did they track that I uninstalled the app?
We can implement a BroadcastReceiver in our application for listening the action "android.intent.action.QUERY_PACKAGE_RESTART" and match our package name inside onReceive() method. If the broadcast was received for selection of our desired application package, then we'll initiate a background thread that will keep monitoring the foreground running activities using the ActivityManager.
Once we find the foreground activity to be "com.android.packageinstaller.UninstallerActivity", it'll be confirm that user wants to uninstall our application. At this point we'll perform the desired tasks (either display a dialogue, or start another activity overlapping the uninstallation window, etc..) that are to be performed before uninstallation. After performing our task, we'll allow the user to continue with confirming the uninstallation process.
When the user clicks on the Uninstall button under Manage Apps settings, we'll perform our pre-uninstallation tasks and then promt the user to the Confirmation window where user can either confirm to uninstall or can Cancel the operation.
Edit you used to be able to do it this way, the permission required is now deprecated
When uninstalling an app, it fires a Broadcast for "QUERY_PACKAGE_RESTART".
So you would need to have Permissions and to build a Broadcast Receiver
<uses-permission android:name="android.permission.GET_TASKS"/>
And then the manifest.xml
<receiver android:name=".UninstallBroadcastReceiver">
<intent-filter android:priority="0">
<action android:name="android.intent.action.QUERY_PACKAGE_RESTART" />
<data android:scheme="package" />
</intent-filter>
</receiver>
UninstallBroadcastReceiver
public class UninstallBroadcastReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("YOUR_APPLICATION_PACKAGE_NAME")){
//Do Something ?
}
}
}
}
}
Still not sure how you would need to track if the user cancels the action, but fire a network call informing your app is about to be uninstalled.
Related
I am working on app which needs to executes a web-service at app install and only once.
Currently i used Shared Preferences for this, But if user clear app data then it lost Shared Preferences value and my code detracts that app is newly created and my code executes web-service further.
So i need solution which broadcast event of my own app install.
I also create broadcast for that but broadcasts only when other app install.
This code i used...
For Check Status
private void checkAppStatus() {
boolean isOpen = AppMethod.getBooleanPreference(MainActivity.this, AppConstant.PREF_IS_OPEN);
if (!isOpen) {
executeWS();
}
}
Broadcast
public class AppInfoReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.e("My App", "Install");
}
}
Manifest
<receiver android:name=".receiver.AppInfoReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_INSTALL" />
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
If you have a server, you can save status in your server and get the status before execute task
You have following options:
You can create a file in hidden directory on external memory with
needed information.
You can create and use your web service for those needs.
Your code doesn't work because your application not installed at that time when broadcast created and because in android your application can receive broadcasts only if it was launched at least one time by user.
As I understood, first option doesn't fit your needs too, cause there is some probability that external memory would be erased or replaced. Android devices doesn't provide any kind of memory that 100% would be persistent in time, and if you really need information about installation of your application you should run your server that receives android device id and sends back to your application information about rather it is first installation or re installation. However I suppose that you should assume clearing app data as application reinstall and run your web service one more time. Simplest solution: just pass to your service android device id and do your things if it is new id or not if it is already done.
I've created an appropriate BoradcastReceiver, registered it in Manifest.xml and here is my problem: if my application has already been launched and hanging in background, then dialing a number would bring it to front. If it has not been launched then dialing a number would have no effect.
How can I fix this? I test this on Xiaomi Mi4 with MIUI6 if that's important.
Here's the code (I use Scala):
manifest.xml:
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
...
<receiver android:name="DialerGate" android:enabled="true" android:exported="true">
<intent-filter android:priority="1">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
BroadcastReceiver:
class DialerGate extends BroadcastReceiver {
def onReceive(context: Context, intent: Intent) =
if (intent.getAction equals Intent.ACTION_NEW_OUTGOING_CALL) {
val phoneno = intent.getExtras getString Intent.EXTRA_PHONE_NUMBER
val prefs = context.getSharedPreferences("prefs", Context.MODE_PRIVATE)
val number = prefs.getString(AbstractKit.LAUNCH_NUMBER, null)
Log.d("WALLET-PHONE", s"Dialed number: $phoneno, saved number: $number")
Log.d("WALLET-PHONE-OK", (number == phoneno).toString)
val i = new Intent
i.setClassName("com.app.wallet", "com.app.wallet.MainActivity")
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP)
val appContext = context.getApplicationContext
appContext.startActivity(i)
//if (number == phoneno) context startActivity new Intent(context, target)
//context stopService intent
}
}
From a simple user perspective, that cannot be done (its a security feature).
Starting from HONEYCOMB Android doesn't allow any broadcast receivers to be invoked until application is run at least once.
Its basically simpler to allow the program to be run at least once (during boot its the most common one), and then have the intent close the app if its not the time to use it.
Check this for further details on how to implement additional receivers that may do what you need it to do.
create a Listener in your Broadcast Receiver and listen to ON_BOOT_COMPLETED, then start your app, in silent mood and you will be resolved to your normal workings.
side note If Activities was to be waken up that way, then Keylogging apps and hacking apps will be very very very cheap to create - hence make android vulnerable.
http://android-developers.blogspot.in/2013/05/handling-phone-call-requests-right-way.html
Listening for outgoing call requests
Apps that provide phone calling services (such as VOIP or number management) can set up Intent filters to handle outgoing call requests, such as those made from the Dialer or other installed apps. This provides a seamless integration for the user, who can transition directly to the calling service without having to redial or launch another app.
When the user initiates a call, the system notifies interested apps by sending an ordered broadcast of the NEW_OUTGOING_CALL Intent, attaching the original phone number, URI, and other information as extras. This gives apps such as Google Voice and others a chance to modify, reroute, or cancel the call before it’s passed to the system’s default phone app.
If you want your phone calling app to be able to handle outgoing call requests, implement a broadcast receiver that receives the NEW_OUTGOING_CALL Intent, processes the number, and initiates a call as needed. Make sure to declare an intent filter for NEW_OUTGOING_CALL in the receiver, to let the system know that your app is interested in the broadcast. You’ll also need to request the PROCESS_OUTGOING_CALLS permission in order to receive the Intent.
Note that the system broadcasts NEW_OUTGOING_CALL only for numbers that are not associated with core dialing capabilities such as emergency numbers. This means that NEW_OUTGOING_CALL can not interfere with access to emergency services the way your use of CALL_PRIVILEGED might.
Here’s an example broadcast receiver declared in an app’s manifest file:
<manifest>
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<application>
...
<receiver android:name=MyOutgoingCallHandler">
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
...
</application>
</manifest>
And I am sure that <category android:name="android.intent.category.DEFAULT" /> will do the trick for you. check this question too for more details about category tag.here
You could try a few things.
Try using java, if not try the following.
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
...
<receiver android:name="DialerGate">
<intent-filter android:priority="2147483648">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
</intent-filter>
</receiver>
Changed priority and removed unnecessary stuff.
Also though I am good at Broadcast Receivers I don't have experience in Scala, so I can only suggest a few ideas. Remove the if statement. It is not required as you have already have an <intent-filter>. Also change the intent as in the paste bin code.
Have a look here.
You may use a service, but just care about one thing: when the app is closed the service get closed also because they are in a one thread, so the service should be on another thread in order fot it not to be closed
You can keep it alive with AlarmManager.
In the link there are also some samples :)
Hope it helps!
The application might not have the permissions to the "phone", either ask for permissions at runtime or go to application settings and enable all the permissions asked by the application.
This worked for me..
I'm aware of the fact that the app is uninstalled and re-installed during the course of an app update from the play store.
I have a very crucial service which needs to be running ALWAYS in the background. And this service gets killed during the update process. Is there any way to restart this service without having the user to go manually to the app (without going to the activity)?
I've implemented the following code. But somehow this doesn't work either. (Probably because the app gets uninstalled anyway)
public class AppUpdateReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent)
{
if ("android.intent.action.PACKAGE_REPLACED".equals(intent.getAction()))
// Start service here
}
}
MANIFEST:
<receiver android:name="com.company.services.AppUpdateReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
Other info : minSDK = 14, Target SDK = 20
I'm aware of the fact that the app is uninstalled and re-installed during the course of an app update from the play store
No, it is not. Your process is terminated, though.
I have a very crucial service which needs to be running ALWAYS in the background
A user can stop your service whenever the user wants to, above and beyond the OS terminating your process whenever the OS feels that it is appropriate.
But somehow this doesn't work either
Try to use ACTION_MY_PACKAGE_REPLACED instead and see if that helps.
I have a very simple IntentReceiver to receive event when time changes. Here's the code:
public class IntentRec extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Log.i("IntentRec", intent.getAction());
}
}
<application android:label="#string/app_name" android:icon="#drawable/ic_launcher">
<receiver android:name=".IntentRec">
<intent-filter>
<action android:name="android.intent.action.TIME_SET"/>
</intent-filter>
</receiver>
<activity android:name="MyActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>
However, I receive the intent while the application is running. But if I shutdown (using Force Close) the app, onReceive is not called. So my question is, do I receive intents only when listener app is running? I thought that intents was designed to run target listener class when the app was not running.
Thanks
The solution is simple: stop clicking Force Close.
On Android 3.1+, Force Close will prevent anything in your app from running again, until the user runs an activity of yours manually, or something else (e.g., third-party app) starts up your app.
UPDATE
I suspect that you are being confused by multiple meanings of the word "stopped". Let's walk through the process, avoiding the word "stopped", to see if it helps.
When your app is first installed on an Android device, is in a state known to some as "snicklefritzed". While the app is in this "snicklefritzed" state, no manifest-registered BroadcastReceiver will work. To move an app out of the "snicklefritzed" state, some third-party app (like the home screen launcher) must explicitly request to run something in your app (like an activity). So, the normal course of events is that the user downloads your app, clicks on the launcher icon for it, and your app is moved into the "normal" state and away from the "snickelfritzed" state. While in the "normal" state, your BroadcastReceiver will work fine.
Let's suppose that your BroadcastReceiver is for the ACTION_BOOT_COMPLETED broadcast. The "snicklefritzed" state has nothing to do with whether your app is presently running or not -- it is dependent only upon if your app has ever run or not. Hence, if the user installs your app, but reboots their phone before doing anything with your app, your ACTION_BOOT_COMPLETED receiver will not get control at boot time. If, however, the user runs something in your app, then reboots the phone, your receiver will receive the ACTION_BOOT_COMPLETED broadcast as normal.
Normally, apps move out of the "snicklefritzed" state and never return to that state. One thing that will cause an app to be "snicklefritzed" again is if the user clicks on Force Close for this app in Settings. Here, the user is expressly telling Android that your app is misbehaving and should not run again until the user says otherwise. If, of course, the user launches your activity again, you move back to "normal" state.
You have to add android:process=":remote" in order for the BroadcastReceiver to receive independent of your Activity.
<receiver android:name=".IntentRec"
android:process=":remote"> //We declare that this is in a remote process
<intent-filter>
<action android:name="android.intent.action.TIME_SET"/>
</intent-filter>
</receiver>
Cheers,
Zed
OK, so not entirely sure this is possible...
But trying to write an application so that I can run some code before any of the following activities are performed.
1) APK is downloaded from web and market launches installer
2) Install button is pressed on android market
Is it possible to intercept and prompt on these events, or has Google locked that stuff down quite tightly?
This isn't an answer per se, but I can't find any commenting tool here. Sorry.
I'm having this issue as well. I would like to be able to detect new application installs. I know it is possible - for example, the app Apps to SD posts a notification when you install a new app that when clicked opens a dialog to move that new app to the sd card.
So far, all I've been able to figure is like this:
manifest.xml:
...
<receiver android:name=".IntentReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" />
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" />
</intent-filter>
</receiver>
...
IntentReciever.java:
public class IntentReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, YourService.class));
}
}
YourService is then created and calls onCreate() then onStartCommand(). However, I haven't been able to debug this or successfully display any notifications from the service class, so I'm not entirely sure this works. I have gotten this to work for other Receivers like android.intent.action.BOOT_COMPLETED.
Using a BroadcastReceiver you can filter the android.intent.action.PACKAGE_ADDED intent. However this will only be after the two actions you describe, not before. And it will not stop or interrupt the installation.
AFAIK there is no way to do anything before or to interrupt the Market. And then we're even talking about another app than the one that's being installed ofcourse.