Is there any changes required for Android 11 storage policy? - java

As you all know 5th May is the deadline for using Scoped Storage for Android 11. And here's the case for:
I have an app in which user uploads an image during the Sign Up process and I'm using this method to select an image from Gallery
Intent chooseImageIntent = new Intent();
chooseImageIntent.setType("image/*");
chooseImageIntent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(chooseImageIntent, "Select image"), requestCode);
then
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case PICK_IMAGE_ID:
// If image is selected successfully, set the image URI and bitmap.
Uri imageUri = data.getData();
mBitmap1 = ImageHelper.loadSizeLimitedBitmapFromUri(
imageUri, getContentResolver());
if (mBitmap1 != null) {
ivItem1.setImageBitmap(mBitmap1);
uploadFile(mBitmap1, PICK_IMAGE_ID);
} else {
Toast.makeText(this, "image not loaded", Toast.LENGTH_SHORT).show();
}
break;
default:
super.onActivityResult(requestCode, resultCode, data);
break;
}
}
What changes should I make, in order to comply with the Android 11 update or storage policy update?

It's mentioned in the Google's support website and I quote
Google Play restricts the use of high risk or sensitive permissions,
including a special app access called All files access. This is only
applicable to apps that target Android 11 (API level 30) and declare
the MANAGE_EXTERNAL_STORAGE permission, which is added in Android 11.
Also, this policy does not impact the usage of the
READ_EXTERNAL_STORAGE permission.
So if you are requesting MANAGE_EXTERNAL_STORAGE permission on Android 11 then you need to remove it if it not required by your app. If you need that permission then you need to explain why you are using it.
Since you are asking only READ_EXTERNAL_STORAGE permission. You don't have to do anything. and the policy will not affect your app unless you are requesting MANAGE_EXTERNAL_STORAGE permission
More details can be found here :
Preview: Use of All files access (MANAGE_EXTERNAL_STORAGE) permission

Related

Google Play - In App Update is installed but it shows update available again and again

Recently I've added In App Update feature in my App with IMMEDIATE update flow. Here is I'm checking and requesting for the update in onCreate() of MainActivity
initialized the variable in onCreate() like this
appUpdateManager = AppUpdateManagerFactory.create(this);
appUpdateInfoTask = appUpdateManager.getAppUpdateInfo();
and in onCreate(), I've added this piece of code
appUpdateInfoTask.addOnSuccessListener(appUpdateInfo -> {
if (appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE && appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE)) {
Toast.makeText(app, "update available", Toast.LENGTH_SHORT).show();
//update is available
try {
appUpdateManager.startUpdateFlowForResult(appUpdateInfo, AppUpdateType.IMMEDIATE, this, Constant.APP_UPDATE_RQ_CODE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
Log.e(TAG, "Update app error: " + e.getMessage());
Toast.makeText(app, e.getMessage(), Toast.LENGTH_SHORT).show();
}
}
});
And this code in onActivityResult()
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == Constant.APP_UPDATE_RQ_CODE) {
if (requestCode == RESULT_OK){
//update is failed, request update again
Toast.makeText(app, "this is called again and again!", Toast.LENGTH_SHORT).show();
requestUpdateApp();
}
}
}
The problem is, after updating the app, always appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE gets true and that's why in app update dialog shows again and again. Please help me to resolve this issue.
for anyone cant install update apk from playstore.
the wrong is not your code, but way your test this library.
you test your function with upload news release (after add in app update libs) to playstore with increment version code and version name.
then you decrement or -1 your version and version code, then build news release apk and try install in your device.
and update is show, but install is failed. cause after succes install you find your version code apk keep with old version. and pop up update keep show and again and again.
the right way for test is like this :
you test your function with upload news release (after add in app update libs) to playstore with increment version code and version name.
install your news version from playstore
then you increment or +1 your version and version code, then build news release apk or bundle and upload again to playstore with news release.
then wait for apk or bundle live in playstore (until you see “Update” in your playstore), if app already live in playstore, but you not found “update” in your app. you can clear all data in playstore and open search again your app in playstore and you will found “Update”
open your apk and you will find show pop up update, and update must be succes.

Google Sign In on Android only work with one of my accounts

I am currently making an Android game and I am using google sign in (for access to firebase, google leaderboard and achievement). I already integrated all of that and this is working fine. However I was always using my main google account but when I tried to change it to another account to have other people test it, it doesn't connect anymore.
I added the other account as a tester on the google play game service for my app. I believe I must have missed to add it somewhere but I cannot find where and I have been searching for hours.
Here's the code that should connect but doesn't:
private void startSignInIntent() {
Intent intent = GoogleSignIn.getClient(this,
GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).getSignInIntent();
startActivityForResult(intent, RC_SIGN_IN);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case RC_SIGN_IN:
GoogleSignInResult result = Auth.GoogleSignInApi.getSignInResultFromIntent(data);
if (result.isSuccess()) {
GoogleSignInAccount x = result.getSignInAccount();
//x.getIdToken() is always null with the other account
if (x.getIdToken() != null)
firebaseConnect(x);
else
//I tried repeating the operation but won't work
(...)
I also tried with different accounts but only my original one works. So do you have any idea of what I could have done that made this original account work and not any other? I did most of that Google Sign in parametrization long time ago so I don't remember in every details. And I am very desperate to debug that, after spending so much time trying to solve it in vain.
Thank you for any hint or help about that!
Found the solution, I used "GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN" but we need to use "GoogleSignInOptions.DEFAULT_SIGN_IN" to use google connection. For more details about the difference between these 2, refer to the GoogleSignInOptions API documentation.

Android System Overlay window not working

I am building and Android app and trying to learn all I can in the process. As a test I wanted to add a "chat heads" style overlay to the system. So, I looked around and found some good tutorials, and some really good answers on here, but it is still not working. In my android manifest I have the uses-permission declaration..
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Then in my Preference page, when the user clicks on a SwitchPreference to activate the popup chat window I am checking for version and permissions like so...
private Preference.OnPreferenceChangeListener chatHeadsChangeListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object o) {
if((boolean) o) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
!Settings.canDrawOverlays(getApplicationContext())) {
Intent intent = new Intent(
Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getPackageName())
);
startActivityForResult(intent, CODE_DRAW_OVER_OTHER_APP_PERMISSION);
} else {
initializeChatHeadsView();
}
}
return true;
}
};
Then in my onActivityResult I am checking again to make sure, like one answer I found on here...
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == CODE_DRAW_OVER_OTHER_APP_PERMISSION) {
if(Settings.canDrawOverlays(this)) {
initializeChatHeadsView();
} else {
Toast.makeText(
this,
"Draw over other app permission was not available. Cannot activate Popup Chat",
Toast.LENGTH_LONG
).show();
}
}
}
The first time I load the app up on the emulator, which is running Android 8.0, I go into my settings page and click the SwitchPreference turning it on. The settings page opens up asking me if I want to enable the permission, I activate the permission, but it doesn't go back to my app after activating, so I hit the back button which goes back into my app, then I get the "[Application] has stopped responding." If I check the log in AndroidStudio I get the error...
Process: test.notreal.justatext, PID: 21429
java.lang.RuntimeException: Unable to create service test.notreal.justatext.service.FloatingViewService: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W#bc855eb -- permission denied for window type 2002
So it is still saying the permission is denied, even though I am enabling the permission, and in my onActivityResult I am checking if(Settings.canDrawOverlays())
Can anyone see why this is failing? I can't figure it out. Thank you for any help, I really appreciate it.
for apps targeting Android 8.0
apps must use a new window type called TYPE_APPLICATION_OVERLAY.
so for Android 8.0 you must ask this permission, for lower verison
SYSTEM_ALERT_WINDOW permission
will work
For more Refer this link
https://developer.android.com/about/versions/oreo/android-8.0-changes.html#cwt

SecurityException: No persistable permission grants found for uri from ACTION_IMAGE_CAPTURE

My app use camera to take a photo and use it for long term.
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
Uri resultUri = null;
resultUri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new ContentValues());
imageCaptureIntent.putExtra(MediaStore.EXTRA_OUTPUT, resultUri);
startActivityForResult(imageCaptureIntent, IMAGE_CAPTURE_REQUEST_CODE);
But when I call takePersistableUriPermission(), I will get SecurityException: No persistable permission grants found
I've read this
Getting Permission Denial Exception.
It works perfect to ACTION_OPEN_DOCUMENT.
How do I get a persistent permission from Camera?
Access to MediaStore URIs are only controlled by the storage permissions (i.e., READ_EXTERNAL_STORAGE) so as long as you continue to hold the storage permission, you can access the Uris so in this case you don't need to persist permissions at all.
URI based permissions, used in ACTION_GET_CONTENT, ACTION_OPEN_DOCUMENT, etc. give special one time access to a URI via the FLAG_GRANT_READ_URI_PERMISSION being included with the returned Intent.
It is only document URIs (ones where DocumentsContract.isDocumentUri() returns true) that allow you to persist permissions to give more permanent access to a Uri.

Android java.lang.SecurityException occured

I am new in Android. And I am Working On Dialer Through Launch Application. And I hide my Application Icon From the Menu. I successfully open the Application from Dialer In jellybean And Kitkat Device but when i open Application in Lollipop and Marshmallow System getting me Exception like,
E/GooglePlusContactsSync: Failed to clear out contacts
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord{ff7ceee 26321:com.google.android.apps.plus/u0a89} (pid=26321, uid=10089) requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at android.app.ActivityManagerProxy.getContentProvider(ActivityManagerNative.java:3594)
at android.app.ActivityThread.acquireProvider(ActivityThread.java:4799)
at android.app.ContextImpl$ApplicationContentResolver.acquireUnstableProvider(ContextImpl.java:2018)
at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1466)
at android.content.ContentResolver.query(ContentResolver.java:475)
at android.content.ContentResolver.query(ContentResolver.java:434)
at dit.a(PG:440)
at dit.b(PG:1388)
at diu.run(PG:325)
at java.lang.Thread.run(Thread.java:818)
E/DatabaseUtils: Writing exception to parcel
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaProvider uri content://media/external/fs_id from pid=2208, uid=10089 requires android.permission.READ_EXTERNAL_STORAGE, or grantUriPermission()
at android.content.ContentProvider.enforceReadPermissionInner(ContentProvider.java:605)
at android.content.ContentProvider$Transport.enforceReadPermission(ContentProvider.java:480)
at android.content.ContentProvider$Transport.query(ContentProvider.java:211)
at android.content.ContentProviderNative.onTransact(ContentProviderNative.java:112)
at android.os.Binder.execTransact(Binder.java:453)
And then Application automatic close.
The Android 6.0 (Marshmallow) introduced a new way to deal with permissions on Android. Read more about it here
Beginning in Android 6.0 (API level 23), users grant permissions to
apps while the app is running, not when they install the app. This
approach streamlines the app install process, since the user does not
need to grant permissions when they install or update the app. It also
gives the user more control over the app's functionality; for example,
a user could choose to give a camera app access to the camera but not
to the device location. The user can revoke the permissions at any
time, by going to the app's Settings screen.
You need to declare your permissions at the manifest.
Check for the current state:
// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.WRITE_CALENDAR);
And request them if you need:
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an expanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed, we can request the permission.
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
}
To deal with runtime permission in Android I usually use this library. It really helps and reduce the code boilerplate.
From Android 6.0 we need to check if the permission is already granted or not, so in order to read contacts you need to first check if read_contacts permission is already granted or not.
Try :
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, 101);
return;
} else {
// permission already granted
}
and Listener after granting the permission
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 101:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission granted
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}

Categories

Resources