How does Dolphin web browser get notified when it's being uninstalled? - android

Background
It might be useful for apps to allow to ask the user to answer why it was decided to uninstall them.
The problem
It seems that the Dolphin web browser app (and "everything me launcher") somehow managed to bypass it, and now it shows a webpage (on the default web browser) each time the app is being uninstalled.
This happens even if I uninstall using ADB.
As a user, I really hate it, but it's still interesting since as far as I know, apps can't get intents for the uninstallation of themselves.
Question
How could it be? How did they manage to overcome this?
Is this a hack?

Maybe the app has a background service which checks the foreground app when it's own onDestroy() callback is fired, and if the foreground app is the uninstalling activity of android Package installer, it launch a new intent for the webpage?

My guess is that they're using ACTION_PACKAGE_REMOVED.
http://developer.android.com/reference/android/content/Intent.html#ACTION_PACKAGE_REMOVED
Either that, or Robin Hood and Frei Tuck method, where each one listens to broadcasts events from the other.
Just a guess, but will look into it.
This might be an option: How can an app detect that it's going to be uninstalled?

Please try to get the top activity in the task via ActivityManager, and check if it is the uninstall activity.
Core code:
ComponentName topActivity = mActivityManager.getRunningTasks(1).get(0).topActivity;
String packageName = topActivity.getPackageName();
String className = topActivity.getClassName();
Log.v(TAG, "packageName" + packageName);
Log.v(TAG, "className" + className);
if ("com.android.packageinstaller".equals(packageName)
&& "com.android.packageinstaller.UninstallerActivity".equals(className)) {
//Do anything you want here
}

Related

Start another app while task-locking is enabled

I used this guide to activate my app as device owner. So, I can activate task locking. This is very close at how I want Android to behave.
Is it possible to start one or more specific third-party-apps out of the device owning app and without deactivating the task-lock?
If not, is it possible with a little workaround? I am thinking about deactivating the task-lock, starting the other app and then activating task-lock for the other app remotely.
Thank you in advance.
In my case, my app is an enterprise app that needs to lockdown the device, so the use of kiosk mode. But my app needs to call telephone and Google Maps apps.
Not sure if it is a bug or not, but some versions of Android startActivity() does not work even if you call setLockTaskPackages() correctly. It seems to be a problem with lollipop. To workaround I used startActivityForResult instead.
A locked task can only launch third-party activities if their launch flags allow them to be launched into the same task. If you try to launch an activity in a new task, it'll print a warning to logcat and the user will see nothing.
AFAIK, there is no general way to lock another task. The other task would have to be designed to lock itself in response to some intent.
I know I am too late for the party but here is what I did to get it working for me.
When you make your app as device owner you have to call this method:
DevicePolicyManager myDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
// get this app package name
ComponentName mDPM = new ComponentName(this, DeviceAdmin.class);
Utility.writeLogs(this, getString(R.string.info), "Trying to start lock task...");
if (myDevicePolicyManager.isDeviceOwnerApp(this.getPackageName())) {
// get this app package name
String[] packages = {this.getPackageName()};
// mDPM is the admin package, and allow the specified packages to lock task
myDevicePolicyManager.setLockTaskPackages(mDPM, packages);
startLockTask();
} else {
Toast.makeText(getApplicationContext(), R.string.not_owner, Toast.LENGTH_LONG).show();
}
Just add the package name of the application you want to allow to be opened from you application in
String[] packages = {this.getPackageName(), "Package names to be allowed"};
and it should work for you.

Android app that kills background processes to save power

I am writing an Andoid app so that when battery life gets below a certain level, a dialog with options of how to save the battery appears. One of those options is to close all background apps/services (processes) using ActivityManager.killBackgroundProcesses(). The code is shown here:
public void TaskKiller( View view){
List<ApplicationInfo> packages;
PackageManager pm;
pm = getPackageManager();
packages = pm.getInstalledApplications(0);
ActivityManager mActivityManager = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
for (ApplicationInfo packageInfo : packages) {
mActivityManager.killBackgroundProcesses(packageInfo.packageName);
}
}
However, when I click the button that calls TaskKiller() and closes the background processes, some of the apps (Email, Google Maps) instantly begin he process of restarting. How can I alter my code so these apps stay closed until they are reopened? Also, is this approach sensible in regard to saving power or am I attacking this the wrong way?
I don't think that's the right way of handeling the problem.
These apps have broadcast receivers, which mean they'll restart the service whenever something happens (i.e. AC plugged in/WiFi turned on), and I don't think there's a way to stop that without root, and actually disabling the broadcast receiver.
You could make something that kills it every 5 minutes, but that wouldn't be very battery-friendly.
I don't think it's a good idea to force close the Maps app everytime, it's a bug in Android i think..
One of the answers is as following:
"
Actually, Maps always runs when you have "Backround Data" checkmarked in your General Sync Settings under Account Settings in your phone's Gmail app. Syncing backround data is necessary, unfortunately, in order for your phone service provider to provide calling and texting (although internet access will still work without this item checkmarked). Unchecking this box will remove Maps from Running applications (& any other app that needs it), improving battery time and speeding up your phone. But, if you want to make calls, text or use apps that require Backround sync, you have to have this ckeckmarked. If all you want to do is browse the net...uncheckmark it. There are currently no other legitimate solutions to the issue. Hope this is helpful...
"
See this issue (https://code.google.com/p/android/issues/detail?id=10251)

notify installation complete from service

I have this piece of code
private void initiateInstallation() {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(new File("/sdcard/example.apk"));
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
that from within my service installs an application named example.apk
I want after the installation is finished to run an activity which notifies the user about the installation.I did that except the activity appears before the installation finishes.
The problem is that within a service I cannot use startActivityForResult. So, I need a way around this so that I can start my notification activity(or for the sake of example just print something out with Toast within the service) only AFTER the installation is complete.
I already tried some answers from other questions like "alternative to startActivityforResult in services" but still I couldn't figure this out.
I also put the code so that maybe there may be something done in there.
Thanks in advance ... any suggestions are welcome.
You could listen to the PACKAGE_ADDED broadcast intent: http://developer.android.com/reference/android/content/Intent.html#ACTION_PACKAGE_ADDED
As far as I know, these are sent after the installation is done, and you can listen to those from the service.
Just note that if the application was already installed, you will get ACTION_PACKAGE_CHANGED (as far as I know).
Also you must know the package name as well, not just the apk name, since the intent will contain the package name.
The answer given by #Pal Szasz is technically correct (as far as I know ;-) ).
However, based on the information given in your question, I assume you only wish to show a notification (no further programmatically actions are to be performed). If my assumptions are correct I would respectfully advise you NOT to show such a notification. And this is why:
The Android system already has a standard means of passing notifications to the user. The status bar will in this case already show you a message saying that the new app is successfully installed (or not installed in case of an error). If you implement yet another notification channel you will most likely confuse or irritate your users by diverging from the standard, expected behaviour.
Taking this beyond the borders of sanity one could also argue for the fact that you in some sense also would contribute to the fragmentation of Android (in a very small scale, but nevertheless).

Reboot after install

Is it possible to force a reboot of the device after my apk is installed?
I want to force this because I want to ensure that my service is started.
Most probably the answer is no, your are not allowed to do such things from your app. This is the sole privilege of the user holding the phone (and of maybe the core system services).
You can however ensure you service is started when the user starts you main activity, which would be a very normal thing to do right after the user have installed your application.
For additional information see the question How to start android service on installation, which is in fact what you should be trying to do.
It's not possible in any way to get your application to do anything as soon as it's installed, before the user first launches it from the home screen. There's no broadcast action you can listen for explicitly. However, you can listen for something generic that gets called a lot, such as:
android.intent.action.USER_PRESENT,
android.intent.action.SCREEN_OFF, or
android.intent.action.SCREEN_ON
In any case you should NOT reboot the device. Your users will hunt you down and kill you with stones. Joke aside, Google might actually pull your app from the Market for this. Just listen for one of the actions mentioned above, check if the app has just been installed (using a one-time boolean preference, for example) and start the service.
Note: if you do end up listening for one of the above actions, please disable your receiver the first time it receives an intent. You can do this like so (in your receiver):
public class FirstTimeReceiver extends BroadcastReceiver {
public void onReceive (Context context, Intent intent) {
// start your service (which does stuff asynchronously, of course, and then:
final ComponentName mySelf = new ComponentName(context, FirstTimeReceiver.class);
context.getPackageManager().setComponentEnabledSetting(mySelf, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}
}
However, you should only do this if somehow this service is absolutely critical for the user (there are few proper scenarios for this), and not for you / your app. As bjarkef mentioned, you should only start it after the user starts your app from the home screen (better yet, ask for permission from the user to run the service).

Require a password to uninstall/remove application

I would like to require that a user type a password before being allowed to uninstall/remove my application. How can I implement this functionality?
You could do this by:
The first time your app is installed, install a separate application/package ("watcher").
The only classes "watcher" contains is a BroadcastReceiver that listens for ACTION_PACKAGE_REMOVED
Add a BroadcastReceiver to your application that also listens for ACTION_PACKAGE_REMOVED
When a intent is broadcast to one of your receivers, check if the other component is still installed. If is isn't (the user just uninstalled it), prompt for the password - if it's wrong, reinstall the other component. If it's right, uninstall yourself.
You can exec logcat and get the start activity intent information.
You will find that before the uninstall activity is displayed, there is
a text msg such as:
Starting activity: Intent { act=android.intent.action.DELETE dat=package:com.comodo.pimsecure cmp=com.android.packageinstaller/.UninstallerActivity }
then you can pop a activity ask for password now.
It is possible. you can do it with DeviceAdminReceiver api. (i don't no how)
This is a hard problem. I can think of at least one non-evil use-case for it.
e.g. Stolen Phone Recovery app - you wish to deter ne'er-do-wells from uninstalling the app.
In this case, I can think of two sensible assumptions which would stop me implementing what you're looking for:
the thief is unaware of your app, so will not try to uninstall it.
the thief is aware of your app, and switch it off until he can get it to an iron box* to re-install the OS.
* For the uninitiated: an iron box will prevent the device sending or receiving electromagnetic signals.
Of course, this answer amounts to You Ain't Going To Need It, though I suspect you have already thought this through.
Protect installing/uninstalling apps by password makes Android more secure from malware/viruses. Your Android become as secure as iPhone.
How it works:
Automatic apps installing is prompted to user. You can search the app name. If not secure, Block it.
Root access is prompted to user. Too many ads is an indicator that access is dangerous.

Categories

Resources