java.lang.SecurityExeception :Clearing DeviceOwner data is forbidden - java

I am trying to clear a data from within the app and my app is device owner, hence I am getting and error
java.lang.SecurityExeception :Clearing DeviceOwner data is forbidden.
Code I am using is
public void onClearData(View view) {
try {
boolean isCleared = ((ActivityManager) getSystemService(ACTIVITY_SERVICE)).clearApplicationUserData();
if (!isCleared) {
Toast.makeText(this, "Not able to clear the data", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Now, my question is that how it will be possible to clear a data of device owner app from within the app? Would appreciate a help.

The way you're doing it is how it's done, according to the docs.
But since you're getting that security exception, your app is probably set as a device owner app, and you're not allowed to deactivate it, remove its data nor uninstall it while it is on this state.
If that's really the case I'd suggest you to unset it as a Device Owner App. Try to use dpm remove-active-admin for that.
Take a look at those questions for more info:
How to make my app a device owner?
How to remove set-device-owner in Android DPM?
Disable a device owner app from android terminal

Related

MSAL ANDROID : MultiAccountMode issue with Logout

I have an android native application using MSAL library to authenticate. We are facing issues to logout from application after login. While logout, it displays a screen where the already logged in email displays, tapping on that allows the user to login to the application with out a password. The application is configured as MultiAccount mode. Below is the code for logout.
removeAccountButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if (mMultipleAccountApp == null) {
return;
}
/**
* Removes the selected account and cached tokens from this app (or device, if the device is in shared mode).
*/
mMultipleAccountApp.removeAccount(accountList.get(accountListSpinner.getSelectedItemPosition()),
new IMultipleAccountPublicClientApplication.RemoveAccountCallback() {
#Override
public void onRemoved() {
Toast.makeText(getContext(), "Account removed.", Toast.LENGTH_SHORT)
.show();
/* Reload account asynchronously to get the up-to-date list. */
loadAccounts();
}
#Override
public void onError(#NonNull MsalException exception) {
displayError(exception);
}
});
}
});
It always display the toast "Account removed", but it is actually not. Any help is appreciated!
Edit 1 - 12/12/2022
#Tinjzz This Answer is almost your exact scenario.
Question Description
"accounts are removed successfully, but when signing in again and the microsoft sign in intent is opened, the accounts can just be clicked to sign in without password"
#Rutha answer "This is happening because MSAL automatically refreshes your token after expiration. When user opens your app it checks if that token is already present and valid."
"you need to remove the cache as well to remove the account from the cache, find the account that need to be removed and then call PublicClientApplication.removeAccount()"
In a later answer, #Rutha notes "On Android we basically don't have any control on the cookies" "If you want the user to enter the password again then you should do this: AcquireTokenInteractive(scopes).WithPrompt(Prompt.ForceLogin);
Old Response
From the code posted, it looks like you are using an approach similar to this site with a separate loadAccounts() method. "Step 5.2: Load accounts"
However, in the MS MSAL Single and Multi-Account page, it notes:
"If your app is configured to use a broker, and a broker is installed on the device, the account won't be removed from the broker when you call removeAccount. Only tokens associated with your client are removed."
MS specifically recommends using "Call getAccounts to get a list of accounts currently known to the app."
So, the current setup may be using loadAccounts() per the first link, yet MS actually recommends getAccounts that specifically addresses only the internal MSAL token system.

Play Core in app update giving UPDATE_NOT_AVAILABLE on production release

I have integrated the play core in-app update it's working fine in the testing track but when a release is published in the production track it's always giving the UPDATE_NOT_AVAILABLE flag. I think the problem might be because Timed Publishing/Publishing Overview is enabled. Is there any fix or any setting which I have to change from the play console itself? or do I have to implement something in my android end?
here is the Implemented code-
AppUpdateManager appUpdateManager = AppUpdateManagerFactory.create(context);
Task<AppUpdateInfo> appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
appUpdateInfoTask.addOnCompleteListener(listener -> {
if (listener.isSuccessful()) {
Log.d(TAG, "Update Available " + (listener.getResult().updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE)); // returns false
Log.d(TAG, "Update Allowed" + listener.getResult().isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)); // returns false
Log.d(TAG, "Update Availibility" + listener.getResult().updateAvailability()); // returns 1 that is UPDATE_NOT_AVAILABLE
if (listener.getResult().updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& listener.getResult().isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
try {
appUpdateManager.startUpdateFlowForResult(
listener.getResult(),
AppUpdateType.IMMEDIATE,
activity,
1001);
} catch (IntentSender.SendIntentException e) {
Log.e(TAG, "showPopup: ", e);
dialog.show();
}
} else {
Log.d(TAG, "no update: " + listener.getResult());
dialog.show();
}
} else {
Log.e(TAG, "no update: ", listener.getException());
}
});
I had a similar problem yesterday, and in my desperation put what should of been a comment about having a similar problem as an answer... #Natty showed me the error of my ways, and I felt bad, so made sure I'd come back with a better actual answer:
I discovered that the likely culprit is google play app signing. It looks like they changed things in August 2021 so as the default is to allow google to manage the app signing, which means your app is signed by a different key with each release, and thus your releases have different signatures, and it won't find the updates. The exceptions is internal app sharing.
Sadly, there appears to be no way to opt-out
You can't disable App Signing after being activated as you can read in the image below:
see this post
It get worse... because ya know google... your can't delete you app either, the only thing you can do is to
unpublish the app.
Then create a new version on the google play store. Change the applicationId to some slight variant so it counts as a different app.
When adding you first release for the new app in any track, make sure to select the appropriate option for app signing above where you drop in the app bundle
click use different key
Either use a keystore generated from android studio or make a new one. From then on google will use that same keystore for signing all future releases of the app.
I even went back and double checked this was the case for me, by checking the older version of the app and the new version on internal testing tracks. Indeed, the new version using the same app signing keystore works for in-app updates, but the older version with google app signing did not.
Just bear in mind a whole new app has to go through the review process, which can take 1-3 days for new apps (seemed to be much quicker once the initial review is done)

How to delete/clear hidden data of app in android programmatically?

Basically my App displays the WebView of a website. and it logins (Google SignIn) correctly but after logout and pressing on LogIn Again doesn't take my account, instead it saves that Gmail once, and clicking log-in again uses previous login credentials. and it gets solved if I clear my app data using device settings. I am trying to reach and Clear my App Data Programmatically.
So far I have been able to delete app data using ( https://www.hrupin.com/2011/11/how-to-clear-user-data-in-your-android-application-programmatically )
But this link was useful if app data exist normally on DeviceFileExplorer data -> data -> package-name, and my problem is that app data is generated hidden inside internal storage (OS security).
Using these below commands I have been able to display them up on DeviceFileExplorer.
adb shell
run-as com.your.packagename
cp /data/data/com.your.packagename/
I have read that this command copies(not move) my hidden package data to this /data/data/com.your.packagename/
So deleting this /data/data/com.your.packagename/ won't help.
try this this might help but some oem have issues with this
private void clearData() {
try {
if (Build.VERSION_CODES.KITKAT <= Build.VERSION.SDK_INT) {
((ActivityManager)getSystemService(ACTIVITY_SERVICE)).clearApplicationUserData();
} else {
Runtime.getRuntime().exec("pm clear " + getApplicationContext().getPackageName());
}
} catch (Exception e) {
e.printStackTrace();
}
}

Always-on VPN switch on programmatically android

Can Always-on VPN switch be on programmatically?
I have added the device admin permission. After that i have set always on in with device admin
mDPM = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);
mDeviceAdminSample = new ComponentName(this, DeviceAdminReceiver.class);
isAdminApp = mDPM.isAdminActive(mDeviceAdminSample);
if (isAdminApp) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
mDPM.setAlwaysOnVpnPackage(mDeviceAdminSample,"", true);
}
} catch (PackageManager.NameNotFoundException namenotfoundexception) {
namenotfoundexception.printStackTrace();
} catch (Exception ex) {
}
}
but it's not enabling the always on.
i have added package name insted of
mDPM.setAlwaysOnVpnPackage(mDeviceAdminSample,"my.app.package.name", true);
but still not enabling the switch.
Then what this code is doing?
How can i enable it programatically?
I want this to be like below image
According to docs, setAlwaysOnVpnPackage can only be used by the profile owner (usually the MDM client on work profile) or device owner (for fully managed devices):
Called by a device or profile owner to configure an always-on VPN connection through a specific application for the current user. This connection is automatically granted and persisted after a reboot.
As a personal profile user - I don't want my VPN to decide for itself when to connect (set always on programmatically will immediately connect the VPN, if implemented correctly).
As a work profile user (wearing the hat of an employee), it's not my decision, but my organization's (via the profile owner app).
So, all in all, this behavior makes sense.
Update:
Instead implementing MDM, which could take a lot of work, you can clone, build and debug Google's Test DPC app, which have everything you need to test toggling always-on VPN programmatically.
It also have million other things, which you don't need so be sure to ignore the rest :)
I haven't looked at their code, but I suggest searching for usages of setAlwaysOnVpnPackage function.
Google's Test DPC app:
Link to Play Store
Link to GitHub repo (to build & debug it yourself)

Android 8.0 Oreo - Accounts

In my app, I need to known if there is any Google account or any Samsung account.
Up to Android 7 it was easy to get this information with something like:
Account[] accounts = AccountManager.get(getContext())
.getAccountsByType("com.google")
But with the event of Oreo this does not work anymore.
EDIT: see official information on this subject:
In Android 8.0 (API level 26), apps can no longer get access to user accounts unless the authenticator owns the accounts or the user grants that access. The GET_ACCOUNTS permission is no longer sufficient. To be granted access to an account, apps should either use AccountManager.newChooseAccountIntent() or an authenticator-specific method. After getting access to accounts, an app can can call AccountManager.getAccounts() to access them.
Android 8.0 deprecates LOGIN_ACCOUNTS_CHANGED_ACTION. Apps should instead use addOnAccountsUpdatedListener() to get updates about accounts during runtime.
For information about new APIs and methods added for account access and discoverability, see Account Access and Discoverability in the New APIs section of this document
I spent half a day to find a solution to my need, without success.
I've found information claiming that now the only way to access to accounts is to use AccountPicker like this:
AccountPicker.newChooseAccountIntent(null, null, new String[]{"com.google"},true, null, null, null, null);
But this does respond to my problem. To be clear I only need to know if an account exists for a certain type (Google, Samsung...) I do not need to know how much if so and do not need accounts information.
Using "android.permission.READ_CONTACTS" permission, and
Account[] accounts = AccountManager.get(getContext())
.getAccountsByType("com.google")
working again in android Oreo
As you already said, there's no way to read other accounts if the user didn't give you the permission to do so. The permission now is provided not only with the run-time permission but even with the account picker, i.e. an account is visible to your app only if the user selected the account after you called the account picker. This new restriction is exactly to avoid what you are trying to do: read all user accounts. There's no solution to your problem, the only thing you can do is to present the picker to the user and let him select all the accounts, not the best user experience however.
Edit: starting from Google Play Services 11.6 there's now a new method requestGoogleAccountsAccess() to get all Google accounts.
To get the installed google accounts on a device running Oreo+ (8+) with this code
Account[] accounts = AccountManager.get(getContext()).getAccountsByType("com.google")
You need to first call
https://developers.google.com/android/reference/com/google/android/gms/auth/GoogleAuthUtil.html#requestGoogleAccountsAccess(android.content.Context)
Please add the following dependency first
com.google.android.gms:play-services-auth:16.0.0
The call requestGoogleAccountsAccess() throws an exception which you can cast (after checking) to UserRecoverableAuthException and get an intent from it to start with startActivityForResult
Here is some example code, working on Android Oreo
// call this on a background thread!
private void requestGoogleAccountAccess() throws Exception
{
googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this);
Log.i(TAG, "googleAccountAccessGranted: " + googleAccountAccessGranted);
}
// exception handler after calling method above
private void handleAuthResult(Throwable e)
{
if (e instanceof UserRecoverableAuthException)
{
UserRecoverableAuthException authException = (UserRecoverableAuthException) e;
startActivityForResult(authException.getIntent(), AUTH_PERMISSION_REQUEST);
}
else
{
Log.e(TAG, "Cannot request Google Account Access", e);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == AUTH_PERMISSION_REQUEST)
{
Log.i(TAG, "Google Auth Permission Result");
if (resultCode == Activity.RESULT_CANCELED)
{
Log.w(TAG, "User Cancelled Play Services Auth Request.")
}
else if (resultCode == Activity.RESULT_OK)
{
Log.d(TAG, "User accepted Play Services Auth Request.");
// call the following line again on a background thread. the call now returns a boolean instead of throwing an exception
// googleAccountAccessGranted = GoogleAuthUtil.requestGoogleAccountsAccess(this);
}
}
}
It's a bit strange why Google decided themselves for this "architecture". Why not return a Task, etc.
But this is how you get it working.
Of course this code needs proper exception handling which I left out for readability.

Categories