I have IntentService task in foreground mode, but in Android M+ the task stops in Doze mode. I read Google banned if the app uses intent to set themselves in whitelist. But if I use permission and check GRANT or DENIED, I get the granted result, but nothing happen. I don't see my app in whitelist. How can I add the app in whitelist without banned? (I added permission in AndroidManifest.xml)
if(Build.VERSION.SDK_INT>=23){
int permissionCheck= ContextCompat
.checkSelfPermission(this, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
if(permissionCheck == PackageManager.PERMISSION_DENIED){
//Should we show an explanation
if(ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)){
//Show an explanation
final String message = "";
Snackbar.make(coordinatorLayoutView,message,Snackbar.LENGTH_LONG)
.setAction("GRANT", new View.OnClickListener() {
#Override
public void onClick(View v) {
ActivityCompat.requestPermissions(MainActivity.this, new String[]{ Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS }, PERMISSION_REQUEST_CODE);
}
})
.show();
}else{
//No explanation need,we can request the permission
ActivityCompat.requestPermissions(this, new String[]{ Manifest.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS }, PERMISSION_REQUEST_CODE);
}
}
}
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS is not a dangerous permission. You do not need, or want, any of that code. Quoting the documentation for REQUEST_IGNORE_BATTERY_OPTIMIZATIONS:
Permission an application must hold in order to use ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. This is a normal permission: an app requesting it will always be granted the permission, without the user needing to approve or see it.
So, delete all that code.
I don't see my app in whitelist.
That is because the user did not add you to the whitelist, apparently.
Requesting REQUEST_IGNORE_BATTERY_OPTIMIZATIONS grants you the authority, from a security standpoint, to start an activity with an ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS Intent. Be sure to include your app's package as the Uri:
startActivity(new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS, Uri.parse("package:"+getPackageName())));
The user will be taken to a screen where they can indicate that they are willing to suspend portions of Doze mode effects on your app.
How can I add the app in whitelist without banned?
If you do not want to be banned, do not do any of this. Have something in your app that starts an activity with an ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS Intent. This leads the user to the overall list of apps, where the user can toggle which ones are and are not on the whitelist. This does not require any permission.
The act of requesting REQUEST_IGNORE_BATTERY_OPTIMIZATIONS in the manifest is what may get you banned.
Be aware of using Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS intent for the activity, this does not work on all phones and you will get a android.content.ActivityNotFoundException. In particular it does not work on Samsung phones running Android 6. The only combination that I have found works on these phones is to declare the REQUEST_IGNORE_BATTERY_OPTIMIZATIONS in the manifest, then launch an activity with intent Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. I.e. the combination that is not liked by Google.
Related
We are currently developing an app where we'd like to change some system settings, with user permission of course. The android documentation says that to do this, you have to add the following permission:
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
Also, one has to explicitly ask the user to enable this permission. An excerpt from https://developer.android.com/reference/android/Manifest.permission#WRITE_SETTINGS says:
Note: If the app targets API level 23 or higher, the app user must
explicitly grant this permission to the app through a permission
management screen. The app requests the user's approval by sending an
intent with action Settings.ACTION_MANAGE_WRITE_SETTINGS. The app can
check whether it has this authorization by calling
Settings.System.canWrite().
Up until this point, it is quite clear. However, when the permission is added to the AndroidManifest.xml file, Android Studio complains that "Permission is only granted to system apps". Now, this is confusing since I haven't found any documentation stating that it is indeed only granted to system apps.
So, I'd like to ask if someone has encountered this issue, and if there is some kind of documentation that explains this in detail? Or am I simply missing something?
You need to get the user permission specifically from the user by that I mean you have to take the user to a screen where user can grant the permission to your app to have WRITE_SETTINGS permission.
So when ever you want to change system settings you have to check if the user has granted the permission or not like this:
private boolean checkSystemWritePermission() {
boolean retVal = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
retVal = Settings.System.canWrite(this);
Log.d("TAG", "Can Write Settings: " + retVal);
if(retVal){
///Permission granted by the user
}else{
//permission not granted navigate to permission screen
openAndroidPermissionsMenu();
}
}
return retVal;
}
private void openAndroidPermissionsMenu() {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
intent.setData(Uri.parse("package:" + this.getPackageName()));
startActivity(intent);
}
As stated by user passsy in the stackoverflow question provided by Brian, android.permission.WRITE_SETTINGS has a android:protectionLevel of "signature", which makes the permission unavailable for use in user applications since API level 23.
See https://developer.android.com/guide/topics/manifest/permission-element#plevel for the description of protection levels for permissions.
I'm trying to get a list of apps (on Android 8.0+) that have REQUEST_INSTALL_PACKAGES permissions marked as granted.
context.packageManager.getInstalledPackages(PackageManager.GET_PERMISSIONS or PackageManager.GET_META_DATA).forEach { pi ->
if (pi.requestedPermissions != null) {
for (i in pi.requestedPermissions.indices) {
if (pi.requestedPermissions[i] == android.Manifest.permission.REQUEST_INSTALL_PACKAGES) {
if ((pi.requestedPermissionsFlags[i] and PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0) {
// permission is granted, do stuff here
}
}
}
}
}
The problem is, that corresponding requestedPermissionsFlags entry is always 1, which means REQUESTED_PERMISSION_REQUIRED and that is obviously wrong.
I tried different api: context.packageManager.checkPermission(android.Manifest.permission.REQUEST_INSTALL_PACKAGES, pi.packageName) == PackageManager.PERMISSION_GRANTED with the same result.
In tried this on Android 8, 9 and 10 on different devices and the only success I had was on Pixel 3a that came positive for com.android.nfc. Others were always false even when I can see in system settings that chrome and other apps have this permission granted.
Am I missing something for this API? Is it private? There is not much to find about it.
Because this permmission has a signature protection level. According to documentation:
A permission that the system grants only if the requesting application is signed with the same certificate as the application that declared the permission
So requestedPermissionsFlags is correct - only com.android.nfc is granted.
Actually REQUEST_INSTALL_PACKAGES has a signature|appop protection level, that's why not only system apps can use it although this perrmission is not granted for them. For a little bit more details - Acquiring Android Permission with Signature Protection Level.
I'd like to grant android.permission.READ_PRIVILEGED_PHONE_STATE permission to my app, but even though it's a system app (in system-priv folder on a rooted device for tests) it's not granted.
ADB shows request for this permission, but it's not granted.
In the Manifest I have
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" tools:ignore="ProtectedPermissions" />
When I try to check it in the runtime
if (ActivityCompat.checkSelfPermission(context.getApplicationContext(), Manifest.permission.READ_PRIVILEGED_PHONE_STATE) == PackageManager.PERMISSION_GRANTED)
the AS gives "Cannot resolve symbol 'READ_PRIVILEGED_PHONE_STATE'" and the app won't compile.
Why READ_PRIVILEGED_PHONE_STATE is visible in the Manifest, but not visible in the java code (also missing in Manifest.class) ?
How can I grant this permission?
I tested it on rooted Android Oreo.
Edit: This answers a part of my question: Permission is not a changeable permission type
The permission was granted on Lollipop, but not on Oreo.
But the question remains: Why READ_PRIVILEGED_PHONE_STATE is visible in the Manifest, but not visible in the java code (also missing in Manifest.class) ?
What I think might be happening is that Drobinsky did not call:
String[] permissions = {"android.permission.READ_PHONE_STATE"};
int requestCode = 5;
ActivityCompat.requestPermissions(this,permissions, requestCode);
prior to calling "ActivityCompat.checkSelfPermission(…"
In the activity you can also add a permissions notififcation handler which looks like this:
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 5: //REQUEST_READ_PHONE_STATE:
if ((grantResults.length > 0) && (grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
// Do what you want to do with the granted permission
Even though you've got the permission added in the manifest, the user must also grant this permission at runtime. What happens is that a popup will occur asking the user to grant this permission, and if the user grants it, the "checkSelfPermission" method will then work correctly. The popup block is automatic; i.e. no code needs to be added to the app. I think you can add a text message that displays the reason the permission is required. Certain permission requests need to be handled in this manner, whereas some permission requests are granted without user intervention required. I think the Android model is that if a request is deemed "dangerous" it requires the user give their permission to grant the app access to these so called dangerous privileges.
Is there any way to programmaticaly ask the Android to reload/regrant my app permissions without reinstalling the app or rebooting the device on a non-rooted device?
Why do I need it?
My app (ClientApp) is binding to a service declared in AIDL by another app (ServiceApp). ServiceApp is a third-party app which I can't modify and it declares a permission that ClientApp needs to bind to its service, so I added that permission to my ClientApp's manifest:
<uses-permission android:name="com.example.service.API" />
When I install ServiceApp before installing ClientApp everything works fine. However, when I first install ClientApp and then install ServiceApp I get an exception when calling bindService on ServiceApp's service in ClientApp:
java.lang.SecurityException: Not allowed to bind to service Intent { act=com.example.service.API pkg=com.example.service }
My understanding is that my app is not granted the requested permission on installation because it's not declared in the system before ServiceApp is installed. I can fix it on Android < 5.0 by declaring ServiceApp's permission in ClientApp's manifest but it's not possible in Android 5.0+ because of security reasons.
If I could somehow reload the permissions (which apparently happens on device reboot) from my code I could solve the problem.
You should check the permission is granted. If it is granted, you can use it, otherwise you can show permission request as popup
Camera permission example:
if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED)
{
// permission granted
}
else
{
// ask permission to user
ActivityCompat.requestPermissions(context, new String[]{Manifest.permission.CAMERA}, Constants.PermissionRequestCodes.CAMERA_REQUEST);
}
Will the Android permissions WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE trigger the new grant permission dialog of Android M?
I agree with Guillaume Perrot 's answer. I have met the similar question when I write the permission of READ_WRITE_EXTERNAL_STORAGE in AndroidManifest.xml
with no permissions showing up in the app by default , people need to switch the toggle button of storage in the app permissions.Then I modify my targetSdkVersion in build.gradle to less than 23(MNC) and other number related with sdkVersion, the app installed with the permissions on.
The other way is to write requestpermission function in the place that you need the permisson. The code is as follow:
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)==
PackageManager.PERMISSION_GRANTED) {
//do the things} else {
requestPermissions(new String[] { Manifest.permission.WRITE_EXTERNAL_STORAGE },
AnyNumber);
Because I have less than 15 reputation so I can't vote for the Guillaume Perrot 's answer.Just use this way to show my idea.
I solved add this if check version for Android M
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
requestPermissions(new String[]{android.Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
My answer is based on my tests on M Preview SDK version 2, using an emulator.
If you target MNC preview API level, WRITE_EXTERNAL_STORAGE is not granted by default and will be part of the new dynamic permission API.
You will see the storage permission as a toggle button in the new app permissions menu in device settings, and you can use Activity.requestPermissions to show the popup for that permission.
However if you target api level < MNC, it won't be classified as a dangerous permission, and thus will be granted without a way for the user to disable it (not showing up in permission settings), and you will not be able to compile code using Activity.requestPermissions anyway as the preview SDK enforces minSdkVersion="MNC" to use the new APIs.
This is a different behavior than location permissions: whatever the API level you target, the user will be able to turn location off in permission menu.
For the permission menu itself, the permission toggle state is ON by default if:
Target API level < MNC.
Target API level = MNC but you upgrade app on device from a previous install where target API level was less than MNC.
Otherwise you will see the toggle as OFF by default.
Hope it helps.
According to the docs:
Limited Permissions Granted at Install Time: When the user installs or updates the app, the system grants the app all permissions that the app requests that fall under PROTECTION_NORMAL.
So because READ_EXTERNAL_STORAGE is falling under PROTECTION_NORMAL , it won't trigger the dialog.
But because the level of WRITE_EXTERNAL_STORAGE is PROTECTION_DANGEROUS, it will fall under this behavior as described in docs:
User Grants Permissions at Run-Time: When the app requests a permission, the system shows a dialog to the user, then calls the app's callback function to notify it whether the permission was granted. If a user grants a permission, the app is given all permissions in that permission's functional area that were declared in the app manifest
Here is the sources for the protection level:
detailed list
According to Android docs you don't need to request permission about read and write external storage.
Edit: in the latest Android M release you need to ask for both read and write permissions
Storage permission falls under dangerous protection level, So all the dangerous protection level permissions will not be granted at install time in Android M, if App target SDK is set to 23. They will be given at run time.
And yes these permissions can be revoked at run time also.
No permission dialog will not be triggered automatically, you need to do a request by using API such as requestPermissions() method to show that native dialog.
Please check the dangerous level permission list here