Start another app while task-locking is enabled - android

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.

Related

Is there any way i can prevent my android app from killing?

i want to know that is there any way i can prevent my android app from killing from task manager. Whether it's any third party app, clears from ram manager or user clicks force stop. i just don't want kill my app from background, It should be running.
How to disable the "Force Stop" button
Short answer: Use the Device Administration API.
How do I demonstrate that it works?
Yes, back to your job. Use the API link provided above and the Api Demos included in Google's sample collection to figure out how to integrate this into your app.
Build the demo and run it on your device.
Choose API Demos->App->Device Admin->General->Enable admin.
Choose Activate once the Device Administration API prompts you with its enabling screen.
Exit the app and attempt to manage the app via your device's settings menu (specifics for this step varies by device).
When viewing the Api Demo's "app info" screen, you should see both Force Stop and Uninstall are disabled.
How do I do this in my own app?
Review DeviceAdminSample.java in the Api Demos app for inspiration. You will need the following:
The following code is what brings up the activation screen:
// Launch the activity to have the user enable our admin.
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN, mDeviceAdminSample);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,
mActivity.getString(R.string.add_admin_extra_app_text));
startActivityForResult(intent, REQUEST_CODE_ENABLE_ADMIN);
However, there are a few other pieces you will need to get this to work:
A broadcast receiver that derives from DeviceAdminReceiver.
Entries in your manifest file that refer to the above broadcast receiver.
Permissions in your manifest for using the Device Administrator API.
An xml file stating what policies your app can access.
All of this can be found in the above links. Good luck with your client!
This might be a dirty way to do this. But it worked for me.
Just override onDestroy() method in service and start that service again.
#Override
public void onDestroy() {
Intent intent = new Intent(this,YourService.class);
startService(intent);
}

Screen pinning 3rd party apps programmatically

After achieving device ownership, I am trying to implement a method to instruct the device to lock any given app into kiosk mode (or screen pinning mode). Since I have device ownership, the user is not asked for the permission to do so.
From the developer website, brief description tells me that it is possible to do what I am trying:
http://developer.android.com/about/versions/android-5.0.html#ScreenPinning
Programmatically: To activate screen pinning programmatically, call
startLockTask() from your app. If the requesting app is not a device
owner, the user is prompted for confirmation. A device owner app can
call the setLockTaskPackages() method to enable apps to be pinnable
without the user confirmation step.
This indicates that as a device owner app, I can pin other apps without user confirmation... but I have no idea how to.
I have been able to put my own app into pinned mode.
Any help would be appreciated.
The setLockTaskPackages() is used the specify which applications (through their package names) will be able to programmatically be pinned without user confirmation.
The setLockTaskPackages() is called from your device owner app (most probably in your DeviceAdminReceiver's onEnabled() method).
So, in you owner device app, you'll have something like :
mDPM.setLockTaskPackages("com.foo.myapp");
and then, in your "com.foo.myapp" application, you will be autorized to call :
startLockTask();
Your application will immediately enter the Pinning mode, without any user confirmation.
If you don't first register your application with setLockTaskPackages, the application will be pinned but the user will have to confirm first.
Also notice that when an app is registered with setLockTaskPackages(), it has some different behaviours than the manual pin:
the user cannot unpin manually the application by long-pressing Back + Recent Apps. You'll have to programmatically unpin your app with stopLockTask();
The "Home" and "Recent Apps" buttons are invisible (not displayed)
When the app is unpinned (via stopLockTask()), the user will directly go back to Home : no Screen lock is displayed, even if a Keyguard is set (Pattern, code, or whatever Keyguard screen).
I've not enough reputation for a comment, just would point out that for devices with physical buttons (like the Samsung Galaxy Tab A mentioned by #chairman) one way for manage the forced unpinning of your application is to implement in your DeviceAdminReceiver class the following:
#Override public void onLockTaskModeExiting(Context context, Intent
intent)
So if your user want to for the unpin you can always re-pinning your app ;)
Here's a code snippet that should get you going:
DevicePolicyManager myDevicePolicyManager = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mDeviceAdminSample = new ComponentName(this, DeviceAdminSample.class);
if (myDevicePolicyManager.isDeviceOwnerApp(this.getPackageName())) {
// Device owner
String[] packages = {this.getPackageName()};
myDevicePolicyManager.setLockTaskPackages(mDeviceAdminSample, packages);
} else {
// Not a device owner - prompt user or show error
}
if (myDevicePolicyManager.isLockTaskPermitted(this.getPackageName())) {
// Lock allowed
startLockTask();
} else {
// Lock not allowed - show error or something useful here
}

How to Hide Android Launcher Icon at Runtime while the App keeps being Upgradable

I have seen in other answers this code:
PackageManager pm = getApplicationContext().getPackageManager();
pm.setComponentEnabledSetting(getComponentName(), PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
This code indeed works, but if you try to reinstall or upgrade the app you can't start the activity that is disabled.
Is there any other way to hide the icon at runtime without losing the ability of reinstalling and upgrading?
Does anyone know?
Problems you encounter on install is because your only exported component (activity marked with main and launcher) is disabled by above code. You can add some other exported component to get back into the app (for example register broadcast receiver for GCM or SMS receive). Similar approach needs to be done to re-enable updating from play store (and even installing from eclipse). Unfortunately I am not certain what component needs to be added for those two.
Workaraound: You could send GCM broadcast to users and re-enable the launcher component before pushing the update but I think there are probably better ways.

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

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
}

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).

Categories

Resources