Delete my application programmatically (Android) - android

I want to uninstall my application on button click. For this I am using following code.
Uri packageURI = Uri.parse("package:"+packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE, packageURI);
startActivity(uninstallIntent);
It gives me result, but I want to delete directly without click on "Ok" button of dialog with message "This application will be Uninstalled".
I just want uninstalling application directly.

Uninstalling without user confirmation is not allowed to 3rd party applications.
As xDragonZ points out, a root process can crudely do this by literally removing the directory and leaving the package manager to deal with the loss, but that's not a very widely deployable solution, since AFAIK no devices ship with that capability for apps to run their own root helper process - that's a risky aftermarket modification.

Yes it is possible to uninstall a package in Android. Moreover you can also skip asking user to press OK button on uninstall screen. You can do it by using Accessibility service in Android.
public class MyAccessibilityService extends AccessibilityService {
private static final String TAG = MyAccessibilityService.class
.getSimpleName();
#Override
public void onAccessibilityEvent(AccessibilityEvent event) {
Log.i(TAG, "ACC::onAccessibilityEvent: " + event.getEventType());
//TYPE_WINDOW_STATE_CHANGED == 32
if (AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED == event
.getEventType()) {
AccessibilityNodeInfo nodeInfo = event.getSource();
Log.i(TAG, "ACC::onAccessibilityEvent: nodeInfo=" + nodeInfo);
if (nodeInfo == null) {
return;
}
List<AccessibilityNodeInfo> list = nodeInfo
.findAccessibilityNodeInfosByViewId("com.android.settings:id/left_button");
for (AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: left_button " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
list = nodeInfo
.findAccessibilityNodeInfosByViewId("android:id/button1");
for (AccessibilityNodeInfo node : list) {
Log.i(TAG, "ACC::onAccessibilityEvent: button1 " + node);
node.performAction(AccessibilityNodeInfo.ACTION_CLICK);
}
}
}
#Override
public void onServiceConnected() {
Log.i(TAG, "ACC::onServiceConnected: ");
}
#Override
public void onInterrupt() {
// TODO Auto-generated method stub
}
}

You should first look into the Android native PackageInstaller. I would recommendating you to update all the code you use.
Next step is to inspect PackageInstaller which is an normal class. You will find that uninstall function there. The bad news is that this needs Manifest.permission.DELETE_PACKAGES permission and its only granted to system apps. This means that this is not available directly to other developers. But we can access it using device owner permission.
This requires:
Android 6.0 or newer
Device owner permission to uninstall the package
Generally the DELETE_PACKAGES permission says:
Allows an application to delete packages.
Not for use by third-party applications.
Once your app gets the device owner permission, you can uninstall an package like this:
String appPackage = "com.your.app.package";
Intent intent = new Intent(getApplicationContext(),
getApplicationContext().getClass()); //getActivity() is undefined!
PendingIntent sender = PendingIntent.getActivity(getActivity(), 0, intent, 0);
PackageInstaller mPackageInstaller =
getActivity().getPackageManager().getPackageInstaller();
mPackageInstaller.uninstall(appPackage, sender.getIntentSender());
The code used available here:
PackageInstaller "Silent install and uninstall of apps by Device Owner” - Android M Preview

Related

Pushing other Android activity to foreground

From a package A, I triggered running service from privileged package B.
Package B performs an update of package A.
Target device is using Android 9 (API Level 28).
The update is successful (app version code has changed).
But my issue is that after the update, package A is in background ; on my device, it is on the background app list, I have to manually press on it to bring it to the foreground.
I would like it to come back to the foreground after install.
What I tried:
Sending a BroadcastIntent from package B to package A after install ; it looks like the intent is not received on package's A BroadcastReceiver (maybe due to the fact that it is in background or the app has been updated?)
After install this command works if I run it manually through adb: "$ adb shell am start -n "com.mma.mainapp/com.mma.mainapp.MainActivity" -a android.intent.action.MAIN -c android.intent.category.LAUNCHER". So I tried performing it from package B after install after a delay: "am start -n "$mainAppPackage/$mainAppPackage.MainActivity" -a ${Intent.ACTION_MAIN} -c ${Intent.CATEGORY_LAUNCHER}".runCommand(File(".")).
I also tried performing this from package B after install after a delay with correct permission but package A is not listed:
private fun moveToFront(mainAppPackage: String) {
val activityManager = getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
val recentTasks = activityManager.getRunningTasks(Int.MAX_VALUE)//activityManager.appTasks.map { it.taskInfo }
for (i in recentTasks.indices) {
log("PUSH Application executed : "
+ recentTasks[i].baseActivity.toShortString()
+ "\t\t ID: " + recentTasks[i].id + "")
if (recentTasks[i].baseActivity.toShortString().indexOf(mainAppPackage) > -1) {
log("PUSH TO FRONT : "
+ recentTasks[i].baseActivity.toShortString()
+ "\t\t ID: " + recentTasks[i].id + "")
activityManager.moveTaskToFront(recentTasks[i].id, ActivityManager.MOVE_TASK_WITH_HOME)
}
}
}
Overriding package A's Application::onCreate(), to bring activity to front: val i = Intent(context, MainActivity::class.java); i.setAction(Intent.ACTION_MAIN); i.addCategory(Intent.CATEGORY_LAUNCHER); context.startActivity(i) // working in isolation but onCreate is not trigerred after apk update.
Is there some way to perform this task? (this should be doable, given package B is privileged (installed under /system/priv-app on rooted device using the standard procedure) and has the same signature as package A)
You need to start an Activity after the installation is complete. It is possible you start activity before installation is complete. To get app A update completion register a broadcast receiver like this:
private static final IntentFilter appUpdateIntentFilter = new IntentFilter();
static {
appUpdateIntentFilter.addDataScheme("package");
appUpdateIntentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
}
private AppUpdateReceiver appUpdateReceiver = new AppUpdateReceiver();
then if you are starting the download from app B's service, register in onCreate and stop in onDestroy of the service:
private void registerBroadcastReceiver() {
try {
registerReceiver(appUpdateReceiver, appUpdateIntentFilter);
} catch (IllegalArgumentException e) {
// already registered
}
}
private void unregisterBroadcastReceiver() {
try {
unregisterReceiver(appUpdateReceiver);
} catch (IllegalArgumentException e) {
// already unregistered
}
}
class AppUpdateReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//if packageName is for app A then start an activity of app A
int uid = intent.getIntegerExtra(Intent.EXTRA_UID);
String appName = context.getPackageManager().getNameForUid(uid);
if(appName.equals("com.appA.PackageName")) {
//start an activity of app A
}
}
}

How to test a Knox Enabled App is actuall knox enabled

I've just gone through the motions of making a Knox Enabled App (KEA) and nothing seems to happen on the device - it just runs like another app. How do I tell if is in-fact Knox Enabled? I understand that my apps should be in their own Knox Container? - is there a way to find that out or test it?
Per the Knox API (Standard or Premium), there is no way to simply query if Knox is already activated. Specifically there is no simple boolean return "knoxlib.isKnoxActivated();"
First of all, let me review how the Knox activation process works:
Your Knox Enabled app needs to call 'activateLicense' for both the ELM & KLM (Enterprise License Management and Knox License Management classes).
The device needs to have a network path to the Knox license server, whether that's Samsung's central one online, or your organizations on-premise Knox license server.
Your Knox Enabled app must have a broadcast receiver to receive a reply from the Knox license server.
Also don't forget to register the broadcast receiver in the Manifest, like this:
<receiver>
android:name=".KnoxLicenseReceiver"
android:enabled="true"
android:exported="true"
<intent-filter>
<action android:name="edm.intent.action.license.status" />
<action android:name="edm.intent.action.knox_license.status" />
</intent-filter>
</receiver>
Your broadcast receiver class should look something like this below.
public class KnoxLicenseReceiver extends BroadcastReceiver {
private final String LOGTAG = KnoxLicenseReceiver.class.getSimpleName();
#Override
public void onReceive(Context context, Intent intent) {
SharedPreferences.Editor sharedPrefEditor = context.getSharedPreferences(Constants.SHARED_PREF_NAME, Context.MODE_PRIVATE).edit();
String action;
int errorCode;
if (intent != null) {
action = intent.getAction();
if (action != null) {
// If received an ELM response
if (EnterpriseLicenseManager.ACTION_LICENSE_STATUS.equals(action)) {
errorCode = intent.getIntExtra(EnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, Constants.DEFAULT_ERROR);
// If successfully activated
if (errorCode == EnterpriseLicenseManager.ERROR_NONE) {
Log.i(LOGTAG, "ELM activated successfully.");
sharedPrefEditor.putBoolean(Constants.ELM_ACTIVATED, true);
} else {
Log.i(LOGTAG, "ELM failed to activate with error code: " + errorCode);
sharedPrefEditor.putBoolean(Constants.ELM_ACTIVATED, false);
}
}
// If received a KLM response
if (KnoxEnterpriseLicenseManager.ACTION_LICENSE_STATUS.equals(action)) {
errorCode = intent.getIntExtra(KnoxEnterpriseLicenseManager.EXTRA_LICENSE_ERROR_CODE, Constants.DEFAULT_ERROR);
// If successfully activated
if (errorCode == KnoxEnterpriseLicenseManager.ERROR_NONE) {
Log.i(LOGTAG, "KLM activated successfully.");
sharedPrefEditor.putBoolean(Constants.KLM_ACTIVATED, true);
} else {
Log.i(LOGTAG, "KLM failed to activate with error code: " + errorCode);
sharedPrefEditor.putBoolean(Constants.KLM_ACTIVATED, false);
}
}
}
}
// Store shared pref changes
sharedPrefEditor.apply();
}
}
Just a note - The previous answers requires internet connectivity.
If you deployed solution uses the KNOX OnPremise license server (and not the Cloud Based/Internet option) you will need network connectivity to the On-Premise server.

Context.checkCallingPermission checking always fails?

I'm encountering such a scenario in Android.
App A has permission PERM to get some information. Instead of directly getting this information, it sends an intent to one BroadCastReceiver inside App B (of course B has PERM). In order to ensure all such apps like A has the permission, I use a context.checkCallingPermission (with the help of this answer).
However it always fails.
public void onReceive(Context context, Intent intent) {
String info;
String perm = Manifest.permission.READ_PHONE_STATE;
Log.i(TAG, "callPid="+ Binder.getCallingPid()+" myPid="+ Process.myPid()); /// SAME PID
if (context.checkCallingPermission(perm) != PackageManager.PERMISSION_GRANTED) {
Log.i(TAG, "not granted " + perm);
info = "denied perm " + perm;
} else {
Log.i(TAG, perm + " already granted");
info = dumpDeviceInfoImpl(context);
}
}
Specially, the comment line always return SAME pid (B's), when I send intent from A. I can confirm A and B have different PIDs.
update
Previously I was thinking it is due to BroadCastReceiver, so I tried to startActivity from A and then start an activity in B. Once again, during checkCallingPermission, it fails again. Surprisingly, still returning the SAME pid.
So what's the correct way to use checkCallingPermission?
use this methdos
checkCallingPermission(Context context, String permission, String packageName)
Checks whether the IPC you are handling has a given permission and whether the app op that corresponds to this permission is allowed.

How to check if user wants to uninstall my app?

I have been through with many Google solutions but not any solution is able to resolve my problem. What I am trying to do is firing a window for user to enter pin/password while he is trying to uninstall my application.
I saw this link, but I am facing 2 issues with this solution these are as follow:
I registered broadcast receiver in My Application, when I open "My Application" in settings, it does not seems working but working fine with other apps. My Code below:
public void onReceive(Context context, Intent intent) {
/// fetching package names from extras
String[] packageNames = intent.getStringArrayExtra("android.intent.extra.PACKAGES");
if(packageNames!=null){
for(String packageName: packageNames){
if(packageName!=null && packageName.equals("com.android.systemapplication")){
// User has selected our application under the Manage Apps settings
// now initiating background thread to watch for activity
new ListenActivities(context).start();
}
}
}
}
When I replaced package name with some different package name that settings screen can detect in broadcast receiver then in run(thread) it is not detecting uninstaller activity, Please see my ListenActivities as below:
public void run(){
Looper.prepare();
while(!exit){
// get the info from the currently running task
List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(MAX_PRIORITY);
String activityName = taskInfo.get(0).topActivity.getClassName();
Log.d("topActivity", "CURRENT Activity ::"
+ activityName);
// here "activityName" is "com.android.launcher" if I select
// package name it is "com.android.launcher2.launcher".
if (activityName.equals("com.android.packageinstaller.UninstallerActivity")) {
// User has clicked on the Uninstall button under the Manage Apps settings
//do whatever pre-uninstallation task you want to perform here
exit = true;
Toast.makeText(context, "Done with preuninstallation tasks... Exiting Now", Toast.LENGTH_SHORT).show();
} else if(activityName.equals("com.android.settings.ManageApplications")) {
// back button was pressed and the user has been taken back to Manage Applications window
// we should close the activity monitoring now
exit=true;
}
}
Looper.loop();
}
I saw many solutions but no success. if it is deprecated then please show some Android documentation because I can see antivirus can do same as what I am asking for. Code would be more helpful. ? Any help would be helpful.

How to prevent a user from disabling my device admin app, through the settings menu?

I'm working on an MDM (Mobile Device Management) app for android, but I have a huge problem and it's that the user can disable my app from within settings>security>device administrators. The only thing I can do about it, is display a warning message by overriding the onDisableRequested(...) method in my DeviceAdminReceiver sub-class, but I really want to prevent the user from disabling my admin app altogether.
I've tried to override the onReceive(...) method, so that nothing happens when the actions ACTION_DEVICE_ADMIN_DISABLE_REQUESTED and ACTION_DEVICE_ADMIN_DISABLED are broadcasted by the system, but so far it has not worked. Apparently some other component is processing those actions before they arrive to my onReceive(...) method and I dont know why. I would like to be able to show my own custom dialog indicating that the user can´t disable the administrator app from this section, and maybe even ask the user to set an admin password to do it.
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_PASSWORD_CHANGED.equals(action)) {
onPasswordChanged(context, intent);
} else if (ACTION_PASSWORD_FAILED.equals(action)) {
onPasswordFailed(context, intent);
} else if (ACTION_PASSWORD_SUCCEEDED.equals(action)) {
onPasswordSucceeded(context, intent);
} else if (ACTION_DEVICE_ADMIN_ENABLED.equals(action)) {
onEnabled(context, intent);
} else if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
} else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
} else if (ACTION_PASSWORD_EXPIRING.equals(action)) {
onPasswordExpiring(context, intent);
}
}
I need help to solve this issue.
Thanks,
You can do this from Android 5 Lollipop with the new device-owner mode. Then the Device-Administrator option in greyed-out and the user cannot disable it, thus not uninstall the device-admin App.
However note that installing a device-owner App is not easy, it has to be done at provision-time with NFC, or from a computer with adb (handy for testing but not for deployment), or with a MDM what is your case...
There is no way to prevent user from disabling, and it's his right.
But to get sure that the user himself is actually removing the admin privilege, lock the device in onDisableRequested with his password and return something like "Someone tried to disable this app administrator feature. was it you and are you sure?".
Now if someone other than the real user try to disable it, he has to enter password before proceeding.
I agree with FoamyGuy, you are not allowed to prevent disabling admin. Otherwise, your application can't be uninstalled at all.
Generally speaking a user grants to some application device admin rights and can remove these rights at any moment.
Any broadcasts are just notifications, you can't handle it and prevent some actions from happening. The system just says to listening apps that something is going on.
Also, read this:
How to wipe Android device when device admin is deactivated?
There is a workaround to prevent disabling the device administrator.
When the user initiates deactivation and we recieve ACTION_DEVICE_ADMIN_DISABLE_REQUESTED callback, we re-launch the settings activity intent.
A message is allowed by the OS to be displayed asking for confirmation from the user. According to Android OS rules, for about 5 seconds, no app is allowed to launch on top of this confirmation dialog. So basically the settings activity we tried to open will only launch after 5 seconds.
To pass these 5 seconds without allowing the user to confirm deactivation, the phone is locked by the device administrator repeatedly in a background thread. After 5 seconds when the user unlocks the device, 'Settings' activity will have been restarted.
The following code for Device Admin Broadcast Receiver Class illustrates the above method.
DevAdminReceiver.java
public class DevAdminReceiver extends DeviceAdminReceiver {
DevicePolicyManager dpm;
long current_time;
Timer myThread;
#Override
public void onEnabled(#NonNull Context context, #NonNull Intent intent) {
super.onEnabled(context, intent);
Log.d("Root", "Device Owner Enabled");
}
#Nullable
#Override
public CharSequence onDisableRequested(#NonNull Context context, #NonNull Intent intent) {
Log.d("Device Admin","Disable Requested");
Intent startMain = new Intent(android.provider.Settings.ACTION_SETTINGS);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startMain);
dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
myThread = new Timer();
current_time = System.currentTimeMillis();
myThread.schedule(lock_task,0,1000);
return "Warning";
}
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
CharSequence res = onDisableRequested(context, intent);
if (res != null) {
dpm.lockNow();
Bundle extras = getResultExtras(true);
extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
}
}else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
Log.d("Device Admin","Disabled");
}
}
// Repeatedly lock the phone every second for 5 seconds
TimerTask lock_task = new TimerTask() {
#Override
public void run() {
long diff = System.currentTimeMillis() - current_time;
if (diff<5000) {
Log.d("Timer","1 second");
dpm.lockNow();
}
else{
myThread.cancel();
}
}
};
}
Ensure force lock policy is set for the device admin in the resource file.
This is a purely a workaround and not an intended solution from the side of the developers. Apps which abuse device admin permissions are always promptly taken down from the Play Store when exposed.
Complete sample code is present in the following repo
https://github.com/abinpaul1/Android-Snippets/tree/master/PermanentDeviceAdministrator
Not a nice way to do this, but here an idea:
When you receive the callback ACTION_DEVICE_ADMIN_DISABLE_REQUESTED, kill the settings app.
(Search for task-killers to see how)
And make sure you don't kill the settings-app after the user entered the password.
If the settings app is gone, the user can't click the disable button.

Categories

Resources