I'm creating an anti-virus software, and I would like to know if Google Play Protect is enabled or disabled? I'm using Java in Android Studio. Are there any permissions required to access this information?
You can check if Google Play Protect (also known as Verify Apps) is enabled using the SafetyNet Verify Apps API (see that link for more details, including a Kotlin version and an option to prompt the user to enable it if it's disabled).
It's an asynchronous API, so you'll have to write a callback, something like:
SafetyNet.getClient(context)
.isVerifyAppsEnabled()
.addOnCompleteListener(new OnCompleteListener<VerifyAppsUserResponse>() {
#Override
public void onComplete(Task<VerifyAppsUserResponse> task) {
if (task.isSuccessful()) {
VerifyAppsUserResponse result = task.getResult();
if (result.isVerifyAppsEnabled()) {
// It's enabled, handle that case here
} else {
// It's not enabled, handle that case here
}
} else {
// An error occurred, we don't know whether it's enabled
}
}
});
The context parameter would just be your this if you're calling it from an Activity or Service.
Related
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.
I'm messing around with Cloud Firestore.
I would like to simply get a callback when reading from DB fails, so I can show a dialog to the user about he has no internet connection. Of course, this would need sophisticated exception handling, but first things first, I would like to just simply get a callback when the app cannot reach the server.
HOWEVER, whenever I test my application with an emulator which has no internet connection, I still get successful callbacks.
This is the log:
Logging_: onSuccess
Logging_: onComplete
Logging_: Task was successful without an internet connection, how?
How is it possible? Am I thinking right that Cloud Firestore is simply not available for this use case since it was built to provide cached data and aggressive syncing in order to provide a seamless user experience even when there is no internet connection?
I would just need a way to just KNOW whether the DB is reachable. (a.k.a - Is there an internet connection problem?)
Code is really simple, it just tries to reach for the current account's characters.
db.collection("users")
.document(accountId)
.collection("characters")
.get()
.addOnCanceledListener(new OnCanceledListener() {
#Override
public void onCanceled() {
Log.i("Logging_", "onCanceled");
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i("Logging_", "onFailure");
}
})
.addOnSuccessListener(new OnSuccessListener<QuerySnapshot>() {
#Override
public void onSuccess(QuerySnapshot queryDocumentSnapshots) {
Log.i("Logging_", "onSuccess");
}
})
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
#Override
public void onComplete(#NonNull Task<QuerySnapshot> task) {
Log.i("Logging_", "onComplete");
if (task.isSuccessful()) {
Log.i("Logging_", "Task was successful without internet connection, how?");
} else {
Log.i("Logging_", "Task wasn't successful.");
}
}
});
I would like to simply get a callback when reading from DB fails, so I can show a dialog to the user about whether he has no internet connection.
The Firestore SDK doesn't throw an error when there is no internet connection, and it makes sense since Firestore is designed to work offline. Behind the scenes, Firestore SDK tries to reconnect until the devices regain connectivity. So not having an internet connection cannot be considered a failure. If you want to check for internet connectivity, the following answer might help:
How to verify if user has network access and show a pop-up alert when there isn't
Please notice that Firestore has a built-in mechanism that can help know when an error occurs. So the failure callback occurs when Firestore servers reject the request due to a security rule issue.
There is a solution in which you can force the retrieval of data only from the cache or from the server. Here is the official documentation regarding source options:
https://firebase.google.com/docs/firestore/query-data/get-data#source_options
Firestore has built in caching that is enabled by default for reading from a database on Apple and Android devices. If you want to disable being able to read the cached data, you can do something like this:
FirebaseFirestoreSettings settings = new FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build();
db.setFirestoreSettings(settings);
I think what you may want to do instead is listen to network events in Android which would allow you to update the user if they try to perform an action while there is no network available.
This might be a bug. I have logged the tracking info here on GitHub
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
I've already created a custom signin that works well with Google Firebase, but the app will need to be used in China, so Google is a no go. I've read through the AWS Cognito documentation but there doesn't seem to be a way to have authentication similar to Firebase where I can use a custom signin UI.
It just needs to be a simple sign in with an email and password, with no sign up feature. Is this possible to do with AWS Cognitio for Android?
Thanks for the help.
You can use the AWS SDK for Android - Cognito Identity Provider to add SignIn feature to your app.
Import the following dependency to build.gradle file and perform gradle sync:
implementation 'com.amazonaws:aws-android-sdk-cognitoidentityprovider:2.6.25'
SignIn API: https://docs.aws.amazon.com/cognito/latest/developerguide/tutorial-integrating-user-pools-android.html#tutorial-integrating-user-pools-user-sign-in-android
Add the following code in your app:
// Callback handler for the sign-in process
AuthenticationHandler authenticationHandler = new AuthenticationHandler() {
#Override
public void onSuccess(CognitoUserSession cognitoUserSession) {
// Sign-in was successful, cognitoUserSession will contain tokens for the user
}
#Override
public void getAuthenticationDetails(AuthenticationContinuation authenticationContinuation, String userId) {
// The API needs user sign-in credentials to continue
AuthenticationDetails authenticationDetails = new AuthenticationDetails(userId, password, null);
// Pass the user sign-in credentials to the continuation
authenticationContinuation.setAuthenticationDetails(authenticationDetails);
// Allow the sign-in to continue
authenticationContinuation.continueTask();
}
#Override
public void getMFACode(MultiFactorAuthenticationContinuation multiFactorAuthenticationContinuation) {
// Multi-factor authentication is required; get the verification code from user
multiFactorAuthenticationContinuation.setMfaCode(mfaVerificationCode);
// Allow the sign-in process to continue
multiFactorAuthenticationContinuation.continueTask();
}
#Override
public void onFailure(Exception exception) {
// Sign-in failed, check exception for the cause
}
};
// Sign in the user
cognitoUser.getSessionInBackground(authenticationHandler);
You can take a look at the sample app: https://github.com/awslabs/aws-sdk-android-samples/tree/master/AmazonCognitoYourUserPoolsDemo
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.