Screen pinning 3rd party apps programmatically - android

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
}

Related

Device admin confirm before DEACTIVATE

I want to ask a confirmation before disabling/deactivating device admin for my application. I searched a lot about it but not fing any proper solution for this.
In short, I want to detect a callback when user click DEACTIVATE button from device admin and I want to ask a confirmation to use that whether are you sure you want to deactivate device admin ? If use press cancel then device admin should not be deactivated.
If you observer AppLock application by DoMobile Lab from google play store, you can find that this app is doing the same thing. So there must be some secret behind it.
You can do it by overriding onDisableRequested() method of DeviceAdminReceiver
public class AdminReceiver extends DeviceAdminReceiver {
#Override
public CharSequence onDisableRequested(Context context, Intent intent) {
return "Are you sure you want to disable the Device admin?";//OR whatever message you would like to display
}
}
As per documentation
Called when the user has asked to disable the administrator, as a result of receiving ACTION_DEVICE_ADMIN_DISABLE_REQUESTED, giving you a chance to present a warning message to them. The message is returned as the result; if null is returned (the default implementation), no message will be displayed.
This will show a popup with OK and cancel button, along with the text returned.

How can I intercept the Intent when the user open another application?

Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
For instance, in SOTI MobiControl app you can manage (from a web dashboard) the permissions of the user with the app installed (and enrolled to your server). If you don't allow one user to open Settings app, when he tries to open it, a toast appears saying "Unauthorized". How do they that?
Doing so is against Google Play Developer Program Policy, as it states in its System Interference section:
An app downloaded from Google Play (or its components or derivative
elements) must not make changes to the user’s device outside of the
app without the user’s knowledge and consent.
This includes behavior such as replacing or reordering the default
presentation of apps, widgets, or the settings on the device. If an
app makes such changes with the user’s knowledge and consent, it must
be clear to the user which app has made the change and the user must
be able to reverse the change easily, or by uninstalling the app
altogether.
Apps and their ads must not modify or add browser settings or
bookmarks, add homescreen shortcuts, or icons on the user’s device as
a service to third parties or for advertising purposes.
Apps and their ads must not display advertisements through system
level notifications on the user’s device, unless the notifications
derive from an integral feature provided by the installed app (e.g.,
an airline app that notifies users of special deals, or a game that
notifies users of in-game promotions).
Apps must not encourage, incentivize, or mislead users into removing
or disabling third-party apps except as part of a security service
provided by the app.
https://play.google.com/intl/ALL_us/about/developer-content-policy.html
Is there a way to "intercept" this intent, from my app's service, in
order to detect that "Settings" app is going to be opened?
As other mentioned before it's not possible to intercept a launch intent.
For instance, in SOTI MobiControl app you can manage (from a web
dashboard) the permissions of the user with the app installed (and
enrolled to your server). If you don't allow one user to open Settings
app, when he tries to open it, a toast appears saying "Unauthorized".
How do they that?
It's however possible to determine if an app is opened and "intercept" that call. By intercept I mean draw over the starting app's screen and present a login screen or a not authorized screen.
I haven't worked out a full sample that would work an any Android version but from my research with AppLocks, I'd say it works more or less like this:
On pre-Lollipop Android you'd use this to retrieve the running processes:
ActivityManager manager = (ActivityManager)getSystemService(ACTIVITY_SERVICE);
for (ActivityManager.RunningAppProcessInfo info : manager.getRunningAppProcesses()) {
Log.e("TAG", "Running process: " + info.processName);
if ("com.mycompany.mycoolapp".equals(info.processName)) {
// do stuff...
}
}
requires:
<uses-permission android:name="android.permission.GET_TASKS"/>
or alternatively:
for (ActivityManager.RunningTaskInfo recentTaskInfo : manager.getRunningTasks(100)) {
Log.e("TAG", "Recent tasks: " + recentTaskInfo.baseActivity.getPackageName());
}
On Lollipop and higher you'd use UsageStats to determine if an app is running:
UsageStatsManager usageStatsManager = (UsageStatsManager)getSystemService(USAGE_STATS_SERVICE);
Calendar cal = Calendar.getInstance();
cal.add(Calendar.YEAR, -1);
long start = cal.getTimeInMillis();
long end = System.currentTimeMillis();
List<UsageStats> queryUsageStats = usageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_DAILY, start, end);
for (UsageStats stats : queryUsageStats) {
Log.e("TAG", "Usage stats for: " + stats.getPackageName());
}
requires:
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
I would probably run both using the AlarmManager to perform that recurring task.
I'm fairly certain these are the two ways to get the list of running apps. If the permission for usage stats is denied to AppLock it's not working any more an Android 6.0 devices. On pre-M devices it however still works which is an indicator that the app has an alternative way to get the list of running apps (the first option described above).
Once it's determined an app has been started (it's running and hasn't been running the last time we checked), we can "take over" the screen. And that's how I'd do it: http://www.piwai.info/chatheads-basics/
Of course that's just the basic idea and I'm sure there are a couple of pitfalls when implementing a reliable solution but this should give you something to start with.
Let's say the user open "Settings" application, is there a way to "intercept" this intent, from my app's service, in order to detect that "Settings" app is going to be openned?
No, unless you are the one that is calling startActivity() to launch the application in the first place.

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.

NotificationListenerService: detect if application is allowed to listen for notification

i saw some applications with a little dialog asking for permit the app to listen for notification. That dialog got 2 button: cancel, and go (that opens the security settings to allow apps for listen for notification). That dialog is persisten so i guess it have a sort of method to detect if the app is allowed or not. Anyone can point me to that API? Thanks
I know this is an old question, but here what I use now in my application:
String notificationListenerString = Settings.Secure.getString(this.getContentResolver(),"enabled_notification_listeners");
//Check notifications access permission
if (notificationListenerString == null || !notificationListenerString.contains(getPackageName()))
{
//The notification access has not acquired yet!
}else{
//Your application has access to the notifications
}
You can move the user to Notification Access Permission settings by open the activity:
startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
This is tested very well from Jelly Bean 4.3 to Marshmallow 6.0 and I use it in my applications.
Hi I don't think that there is a method to call to know if you have permission to Listen Notifications, but you can try the following:
Try to acquire the reference of your NotificationListenerService instance.
Now if you got a null pointer when you expected it to be not null then you should prompt a Dialog asking user to enable the Security setting.
add onClickListener in "Ok" button and now just startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));
All applications on Android can send notifications, there is not even a Permission for it. Any dialog you see in UIs is something implemented by each developer (to be extra considerate).
Bottom line, there is no API for accessing if an app can send notifications (all can).
Otherwise, there are Application Permissions for a variety of other things, which would also be worth learning about.

How to unlock android phone through code remotely

I have written an application that locks android phone remotely. That is when a special code is sent from server then application locks the phone based on the special code. This is the code I am using.
if (!mDPM.isAdminActive(mDeviceAdminSample)) {
// try to become active – must happen here in this activity, to get result
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,mDeviceAdminSample);
intent.putExtra(DevicePolicyManager.EXTRA_ADD_EXPLANATION,"Admin is added to do security operation.");
startActivityForResult(intent, 0);
} else {
// Already is a device administrator, can do security operations now.
mDPM.lockNow();
}
The above code is working and it's locking the phone.
I am able to unlock the phone by entering password from soft keypad. Is there any way to unlock it through code?
My question is how to unlock the phone through code.(This unlocking should be done remotely in the manner I explained for locking)
I believe you cannot override the built-in screen-lock unless you make your own device like Samsung and HTC do. However, by having your customers use your own screen-lock-like app you probably can achieve what you are trying to do.
I do not think your remote unlock goal is achievable.
The way Android is set up, is that many apps may have Device Administrator privilege, and any Device Administrator can issue a lock command, but the unlock has to come from the user.
I can suggest one thing you to simplify this: Your app could try to remove the key lock password, and then the user can use the device without a code simply by sliding a finger on the screen.
Now there is a snag in what I suggested, if your app is not the only device administrator. In that case, some other administrator app could set a minimum password length (or some other password restriction) which would prevent your app from clearing the screen lock password.
If your goal is to help a user that forgot his/her screen lock password, then your server could invent a new password, inform the user what the new password is, and also send the new password to your app and your app could apply the password. The user can then unlock the phone. Do not worry, it is not as complicated as it sounds.
Sorry to write that - There is no way to unlock phone from code. If you find any way to do that - no warranty to work. So there is no way to remote unlock, writing custom lock screens, etc.
You need to use mDPM.resetPassword("", 0)
http://developer.android.com/reference/android/app/admin/DevicePolicyManager.html#resetPassword(java.lang.String, int)
When set password string as "", current password is replaced with empty values & screen lock disappears.
try this
KeyguardManager manager = (KeyguardManager)context.getSystemService(KEYGUARD_SERVICE);
kl = manager.newKeyguardLock("my-remote-app");
kl.disableKeyguard();
//for reenabling keyguard on exit (if you need)
onDestroy() {
kl.reenableKeyguard();
}
this works <=ICS.
This is a deprecated api, they suggested you to use the flags from WindowManager for similar effect. Although I failed to generate the similar effect using the WindowManger.
Hope this helps,
Please note that I'm not an Android developer, but:
If you look at this, it looks like you can ask the WindowManager to dismiss the key guard if you have the right permission, even if you're in "secure lock" mode.
As per my knowledge, we cant unlock password protected phone programatically.
One solution would be to write a "custom lockscreen".
Sure, it's not the easiest way, but it would work as you can do everything you want with your own lockscreen.
If you are considering that solution, feel free to contact me, I'll give you some useful links.
Cheers!

Categories

Resources