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.
Related
I'm developing an Android app to collect data from an Android Wear. A WearableListenerService is used in the handheld device to receive data from the watch via Data API.
But I noticed that if the app in handheld device is forcibly stopped, either from Settings -> Apps or by adb during development, while the app in wearable is still running, it won't be able to receive data again even it's manually restarted.
This won't happen if the wearable is not running the app.
To restart capturing the data in handheld, I have to stop Google Play Services and re-launch my app.
My WearableListenerService:
public class WearableSensorListener extends WearableListenerService {
public static final String SENSOR_RESULT = "minimal_intent_service.result";
public static final String SENSOR_MESSAGE = "minimal_intent_service.message";
private static final String DATA_API_PATH = "/wearable-sensor";
// private GoogleApiClient googleApiClient;
private LocalBroadcastManager localBroadcastManager = LocalBroadcastManager.getInstance(this);
#Override
public void onDataChanged(DataEventBuffer dataEvents) {
Log.i(this.getClass().toString(), "Got data at " + System.currentTimeMillis());
for (DataEvent dataEvent : dataEvents) {
Log.i(this.getClass().toString(), "Got event: " + dataEvent.toString());
if (dataEvent.getType() == DataEvent.TYPE_CHANGED) {
String path = dataEvent.getDataItem().getUri().getPath();
if (path.equals(DATA_API_PATH)) {
DataMap dataMap = DataMapItem.fromDataItem(dataEvent.getDataItem()).getDataMap();
int type = dataMap.getInt("TYPE");
long time = dataMap.getLong("TIME");
float[] data = dataMap.getFloatArray("DATA");
String message = String.format(Locale.UK, "TYPE: %d, TIME: %d, DATA: %s",
type,
time,
Arrays.toString(data));
showSensorResult(message);
}
}
}
}
private void showSensorResult(String message) {
Intent intent = new Intent(SENSOR_RESULT);
if (message != null)
intent.putExtra(SENSOR_MESSAGE, message);
localBroadcastManager.sendBroadcast(intent);
}
}
AndroidManifest.xml in handheld:
<service
android:name=".WearableSensorListener"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.android.gms.wearable.DATA_CHANGED"/>
<data android:host="*"
android:scheme="wear"
android:pathPrefix="/wearable-sensor"/>
</intent-filter>
</service>
It seems the listener won't be cleared after the app crash/stop. Is there any workaround to handle this?
It seems the listener won't be cleared after the app crash/stop.
Why should it? You've registered to that action through manifest and haven't unregistered from anywhere.
You can disable the component from onDataChanged() with PackageManager. setComponentEnabledSetting() API.
Set the enabled setting for a package component (activity, receiver, service, provider). This setting will override any enabled state which may have been set by the component in its manifest.
I have created demo app for One Signal Push notification. It's work fine on emulator but when testing on real device. There is one problem when application closed did not receive push notification.
implementation code is like as following:
TestDemo.java file
public class TestDemo extends Application {
#Override
public void onCreate() {
super.onCreate();
OneSignal.setLogLevel(OneSignal.LOG_LEVEL.DEBUG, OneSignal.LOG_LEVEL.WARN);
OneSignal.startInit(this)
.setNotificationOpenedHandler(new ExampleNotificationOpenedHandler())
.autoPromptLocation(true)
.init();
}
private class ExampleNotificationOpenedHandler implements OneSignal.NotificationOpenedHandler {
#Override
public void notificationOpened(OSNotificationOpenResult result) {
OSNotificationAction.ActionType actionType = result.action.type;
JSONObject data = result.notification.payload.additionalData;
String customKey;
if (data != null) {
customKey = data.optString("customkey", null);
if (customKey != null)
Log.i("OneSignalExample", "customkey set with value: " + customKey);
}
if (actionType == OSNotificationAction.ActionType.ActionTaken)
Log.i("OneSignalExample", "Button pressed with id: " + result.action.actionID);
}
}
}
MainActivity.java file
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
OneSignal.idsAvailable(new OneSignal.IdsAvailableHandler() {
#Override
public void idsAvailable(String userId, String registrationId) {
Log.d("UserId : ", userId);
Log.d("Reg Id : ", registrationId);
}
});
}
and also given permission as suggestion on documentation
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Please help if any solution for that...
Thanks...
The following are reasons why notifications may show as delivered on the OneSignal dashboard or API, but are not visible on your device or website:
The app is currently In Focus
By default, notifications will not be displayed on the device if your app is currently "in focus" (open and visible). However, you can call inFocusDisplaying with InAppAlert to show notifications as alert boxes in your app, or Notification to display the notification.
The app is Force Stopped
When an app is in a "Force Stopped" state most events including GCM/FCM messages for push notifications will not be received. An app can be placed in this state in the following ways.
From Settings > Apps, "Force Stop" is pressed.
Long pressing the back button on some devices.
Using a 3rd party task killer like Greenify.
App is closed on some Huawei, Xiaomi, or Sony devices due their custom Android tweaks. The following device settings can be changed to prevent this.
* Huawei - Go to Settings > "Protected apps", check your app.
* Xiaomi - Make sure "Auto-start" property enabled for your app in the settings.
* Sony - Tap on the battery icon. Go to Power Management > STAMINA mode > Apps active in standby > Add your app.
To confirm your app state is the issue send a few notifications and check for the following GCM logcat entry.
W/GCM-DMM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=com.onesignal.example (has extras) }
Some device manufactures will white list apps from going into the force closed state. Example such as Gmail and Whatsapp.
You have network issues
The network / WiFi you're connected to may have closed your connection to Google servers'. Try disabling and re-enabling your internet connection. See this post for more details.
I'm writing an Android application in which I'd like to programmatically bond to a custom BLE device. I have the manual bonding working in which the user enters the PIN using the standard Android Bluetooth pairing dialog, but I have not been able to find any information on how to automatically bond a BLE device programatically, without user intervention. Is that possible? If so, what's the process?
I was able to make this work MOST OF THE TIME by registering a BroadcastReceiver to receive the BluetoothDevice.ACTION_BOND_STATE_CHANGED intent and then calling BluetoothDevice.setPin after receiving the BluetoothDevice.BOND_BONDING message. As is the case with most BLE things in Android, this seems to act slightly differently depending on the device and Android version. Unfortunately, I can't seem to stop Android from also receiving the bluetooth intent, so the PIN entry screen still pops up for a second before the bonding is completed.
private final BroadcastReceiver mReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
final String action = intent.getAction();
Logger("Broadcast Receiver:" + action);
if (action.equals(BluetoothDevice.ACTION_BOND_STATE_CHANGED))
{
final int state = intent.getIntExtra(BluetoothDevice.EXTRA_BOND_STATE, BluetoothDevice.ERROR);
if(state == BluetoothDevice.BOND_BONDING)
{
Logger("Bonding...");
if (mDevice != null) {
mDevice.setPin(BONDING_CODE.getBytes());
Logger("Setting bonding code = " + BONDING_CODE);
}
}
else if(state == BluetoothDevice.BOND_BONDED)
{
Logger("Bonded!!!");
mOwner.unregisterReceiver(mReceiver);
}
else if(state == BluetoothDevice.BOND_NONE)
{
Logger("Not Bonded");
}
}
}
};
I managed to do this - see my answer here.
The TL;DR is: forget about ACTION_BOND_STATE_CHANGED; you don't need it. Instead listen to ACTION_PAIRING_REQUEST, and set the priority high. In the broadcast receiver when you get ACTION_PAIRING_REQUEST, call setPin() with your PIN and then abortBroadcast() to prevent the system showing the notification.
All you can do to avoid user interaction is to force Just Works pairing. To do that, program the peripheral to accept pairing with NoInputNoOutput IO Capability.
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.
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