I have a navigation drawer. In navigation drawer I am doing inflate the fragment. At the first fragment I ask to user for the runtime permission. but in the second fragment I want to do that it ask user for the same permission again. but in my case first fragment ask the permission. but in the second fragment it does not ask for the permission. so can anyone tell me what is the issue? because I am using the same code in the both situation.
This is my first fragment code :-
if (checkPermission(Manifest.permission.ACCESS_FINE_LOCATION, getActivity().getApplicationContext(), getActivity())) {
IsConsumed = 1;
fetchLocationData();
} else {
requestPermission(Manifest.permission.ACCESS_FINE_LOCATION, PERMISSION_REQUEST_CODE_LOCATION, getActivity().getApplicationContext(), getActivity());
}
public void requestPermission(String strPermission, int perCode, Context _c, Activity _a) {
if (ActivityCompat.shouldShowRequestPermissionRationale(_a, strPermission)) {
Toast.makeText(getActivity(), "GPS permission allows us to access location data. Please allow in App Settings for additional functionality.", Toast.LENGTH_LONG).show();
} else {
ActivityCompat.requestPermissions(_a, new String[]{strPermission}, perCode);
}
}
public static boolean checkPermission(String strPermission, Context _c, Activity _a) {
int result = ContextCompat.checkSelfPermission(_c, strPermission);
if (result == PackageManager.PERMISSION_GRANTED) {
return true;
} else {
return false;
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE_LOCATION:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
fetchLocationData();
} else {
Toast.makeText(getActivity(), "Permission Denied, You cannot access location data.", Toast.LENGTH_LONG).show();
}
break;
}
}
I am using the same code in the second fragment. but it does not ask for the permission.I tried to print the log it goes into the if() condition.and print the log. but it does not ask for the permission.
Related
I struct at first page, I am not able to open Dialog soon after permission granted(Write). First time I asked Permission and I granted Permission,in onRequestPermissionsResult() I opened Dialog, here App is closed with Unfortunately APP has crashed issue. When reopen App the issue not here, It is running normally.I got issue in Monitor
Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState .I Searched lot but different answers I've seen.Please help me ,I am not getting why app is crashed first time.
Here is my code:
llAddPhoto.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!tvAddPhotoOrNext.getText().toString().equals("Next")) { // When Image not gone selected
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//First checking if the app is already having the permission
if (isReadStorageAllowed()) {
//If permission is already having then showing the toast
Toast.makeText(AddUserProfilePic.this, "You already have the permission", Toast.LENGTH_LONG).show();
//Existing the method with return
showFourButtonsBSDialog();
}else {
//If the app has not the permission then ask for the permission
checkPermissions();
}
} else
showFourButtonsBSDialog();
} else { // When image gone selected.
mSetProfilePicByAPI();
}
}
});
#SuppressLint("InlinedApi")
private void checkPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_PICKIMAGE);
} else {
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_PICKIMAGE:
//If permission is granted
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//Displaying a toast
Toast.makeText(this, "Permission granted now you can read the storage", Toast.LENGTH_LONG).show();
showFourButtonsBSDialog();
} else {
//Displaying another toast if permission is not granted
Toast.makeText(this, "Oops you just denied the permission", Toast.LENGTH_LONG).show();
}
}
}
/* BottomSheetDialog */
private void showFourButtonsBSDialog() {
MoreOptionsDialogFragment mTBFragment = new MoreOptionsDialogFragment(); // ThreeButtonsFragment
Bundle mTextNamesArgs = new Bundle(); //Send buttons names
mTextNamesArgs.putStringArray("buttons_names",new String[]{"Take Photo","Choose from library",
"Photo from Facebook","Photo from Instagram"});
mTBFragment.setArguments(mTextNamesArgs);
mTBFragment.show(getSupportFragmentManager(),mTBFragment.getTag());
}
private boolean isReadStorageAllowed() {
//Getting the permission status
int result = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
//If permission is granted returning true
if (result == PackageManager.PERMISSION_GRANTED)
return true;
//If permission is not granted returning false
return false;
}
What are your compile SDK and target SDK versions? Make sure them to be 23 or higher.
https://developer.android.com/guide/topics/permissions/requesting.html
the below code is work only in M version of android, i get issue when i request for permission, after permission request system dialog will be open but its background to be black and after when i try to accept/deny i found app was closed.
#TargetApi(Build.VERSION_CODES.M)
public boolean checkPermissionPhoneState(final String manifestPermissionRequestState, final int PERMISSION_REQUEST_PHONE_STATE) {
int result = ContextCompat.checkSelfPermission(context,manifestPermissionRequestState);
if (result != PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale(manifestPermissionRequestState)) {
requestPermissions(new String[]{manifestPermissionRequestState}, PERMISSION_REQUEST_PHONE_STATE);
contactPermission = false;
}else{
requestPermissions(new String[]{manifestPermissionRequestState}, PERMISSION_REQUEST_PHONE_STATE);
contactPermission = false;
}
} else {
contactPermission = true;
}
return contactPermission;
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
contactPermission = true;
Snackbar.make(view, "Permission Granted", Snackbar.LENGTH_SHORT).show();
} else {
Snackbar.make(view, "Permission Denied", Snackbar.LENGTH_SHORT).show();
}
break;
}
}
I got answer, this app did not crash from background it will close automatically when dialog appear. the main issue was i include "android:noHistory='true'" in Android-manifest,when dialog appear app remove from stack. So after remove this tag from Manifest file my app work properly.
So when i call requestContactPermission method, the dialog appears normally but when i click on allow button , the fragment close and the activity forced to recreate ? what seems to be the problem ? the log dose not show anything
private void requestContactPermission() {
if (shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS)) {
getLoaderManager().initLoader(0, null, this);
} else {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},
101);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 101:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
getLoaderManager().initLoader(0, null, this);
}
break;
}
}
my main problem is when i test it in emulator its works fine but when i test it in real device, like Galaxy S7 edge i'm having this problem
Give this a try.
if (ContextCompat.checkSelfPermission(getActivity(),
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Requesting Runtime Permission Read contact");
ActivityCompat.requestPermissions(getActivity(),
new String[]{Manifest.permission.READ_CONTACTS},
101);
} else {
Log.d(TAG, "Previously User have provided Read contact access");
}
#Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case 101: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Write External Storage Access granted");
downloadCurrentImage();
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
}
// other 'case' lines to check for other
// permissions this app might request
}
}
Marshmallow has redesigned getting permissions. So Handled permissions before calling the method which needs permissions and it works fine, but It crashes in the following scenario:
Step 1: Opened app and gave all the necessary permissions
Step 2: Clicked Home button(So the app is in background)
Step 3: Manually changed the permissions in the Settings
Step 4: Launched the app from multitasks, now it crashes because of app context becomes invalid
Observed that app gets created again, don't understand why this happens. Any suggestions to rectify this issue would be welcome!
It's because of additional features added from Marshmallow. You need to request from user at runtime. For this use this class which I have made. Then use it whereever required
public class AppPermission {
public static boolean isMarshmallowPlusDevice() {
return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;
}
#TargetApi(Build.VERSION_CODES.M)
public static boolean isPermissionRequestRequired(Activity activity, #NonNull String[] permissions, int requestCode) {
if (isMarshmallowPlusDevice() && permissions.length > 0) {
List<String> newPermissionList = new ArrayList<>();
for (String permission : permissions) {
if (PackageManager.PERMISSION_GRANTED != activity.checkSelfPermission(permission)) {
newPermissionList.add(permission);
}
}
if (newPermissionList.size() > 0) {
activity.requestPermissions(newPermissionList.toArray(new String[newPermissionList.size()]), requestCode);
return true;
}
}
return false;
}
}
Then put this code where you require permission from user.
if (!AppPermission.isPermissionRequestRequired(SignInActivity.this, new String[]{"android.permission.GET_ACCOUNTS"},
REQUEST_APP_PERMISSION)) {
// Your code if permission available
}
After this, in your Fragment or Activity put this code -
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_APP_PERMISSION:
for (int i = 0; i < permissions.length; i++) {
String permission = permissions[i];
int grantResult = grantResults[i];
switch (permission) {
case "android.permission.GET_ACCOUNTS":
if (PackageManager.PERMISSION_GRANTED == grantResult) {
// Your code
}
break;
}
}
break;
}
}
The above code is for request permission for GET_ACCOUNTS you can change it to whatever required.
Observed that app gets created again, don't understand why this
happens. Any suggestions to rectify this issue would be welcome!
Because when permissions change, application "state" should be invalidated. The proper way to do that is destroy the root context, which is the application itself.
You have to check the permissions granted status each time you query the API methods that require these permissions. You can't rely on some SharedPreferences flag indicating that "user granted the permissions in onboarding, ok, lets have fun". Make your app stateless in this regards.
For example, you can create some BaseActivity/BaseFragment or Utility and move all the checking logic in there.
Define a boolean value at first
private boolean isPermissionGranted = false;
And then check if permission granted:
if (!isPermissionGranted) {
checkPermission();
}
Actual code for run time permission check is as follow:
private void checkPermission() {
int hasPermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.CAMERA);
int hasWritePermission = ContextCompat.checkSelfPermission(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if (hasPermission != PackageManager.PERMISSION_GRANTED && hasWritePermission != PackageManager.PERMISSION_GRANTED) {
if (!ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.CAMERA) && !ActivityCompat.shouldShowRequestPermissionRationale(UserProfile.this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
showMessage(getString(R.string.allow_access_to_camera_external_storage),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_ASK_PERMISSIONS);
}
});
return;
}
ActivityCompat.requestPermissions(UserProfile.this, new String[]{Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE},
REQUEST_CODE_ASK_PERMISSIONS);
return;
} else {
isPermissionGranted = true;
}
}
private void showMessage(String message, DialogInterface.OnClickListener listener) {
new AlertDialog.Builder(UserProfile.this)
.setMessage(message)
.setPositiveButton(R.string.ok, listener)
.setNegativeButton(R.string.cancel, null)
.create()
.show();
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
switch (requestCode) {
case REQUEST_CODE_ASK_PERMISSIONS:
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
isPermissionGranted = true;
} else {
isPermissionGranted = false;
Toast.makeText(UserProfile.this, R.string.permission_denied, Toast.LENGTH_SHORT)
.show();
}
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
You can take reference from above code and implement it in your application.
I play around with the Preview M and test my app on it, especially the "saving a file to external storage" part.
Before the download/save process starts, i request for
Manifest.permission.WRITE_EXTERNAL_STORAGE
permission as described on the developer page: https://developer.android.com/preview/features/runtime-permissions.html
The dialog occurs as expected:
"Allow <AppName> to access photos, media, and files on your device?" Deny / Allow
If i hit the "deny"-button, the onRequestPermissionsResult-method of the activity is called.
If i press the "allow"-button, the activity is first recreated and afterwards the onRequestPermissionsResult-method is called. I think it's a result of the granted permission.
But the second situation is tricky because i want to trigger a callback that starts the download, but this object is null at this point:
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
getLogger().error("onRequestPermissionsResult ( " + requestCode + ", " + permissions + ", " + grantResults + " )");
switch (requestCode) {
//permission for saving files?
case PermissionCode.WRITE_EXTERNAL_STORAGE: {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//HERE IS THE NULL-OBJECT
if (controller != null) {
controller.triggerCallback();
}
}
break;
}
default: {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
}
So my questions are:
Can I avoid this recreation?
If no, how can i redesign my code to solve the problem - i'm totally idealess at the moment
EDIT 1:
I tried to solve the problem with a handler and postDelayed - but i skipped it.
EDIT 2:
I preliminary solved it and show a Toast to user with the request to push the download button again (in case of granted permission). But Google: ARE YOU SERIOUS?
EDIT 3:
No recreation happens with the latest SDK 6.0 (Version 23) - maybe somebody heard my weeping in Mountain View :-)
You can always check the download condition immediately after the activity recreates itself in onCreate():
static final int MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 0;
boolean initiateDownload = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
initiateDownload = savedInstanceState.getBoolean("toDownload");
}
}
#Override
public void onResume() {
super.onResume();
final boolean hasPermission = checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
== PackageManager.PERMISSION_GRANTED;
if(initiateDownload && hasPermission) {
// start download here...
} else {
requestPermissions(new String[]{WRITE_EXTERNAL_STORAGE},
MainActivity.MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE);
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(requestCode == MY_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
initiateDownload = true;
} else {
// denied permission...
}
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("toDownload", initiateDownload);
}
Android may destroy and recreate your activity for a number of reasons. The use case of requesting permissions is no exception. You can use your preferred way of saving and restoring UI state. If your state is parcelable you can do it like the example below. Why this is not mentioned in Request App Permissions or Android RuntimePermissions Sample I don't know.
See more in
Saving and restoring transient UI state
and
Saving UI States
public class ExampleActivity extends AppCompatActivity {
private static final String CURRENT_DOWNLOAD_ITEM = "CURRENT_DOWNLOAD_ITEM";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null)
currentDownloadItem = savedInstanceState.getParcelable(CURRENT_DOWNLOAD_ITEM);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putParcelable(CURRENT_DOWNLOAD_ITEM, currentDownloadItem);
super.onSaveInstanceState(outState);
}
public void downloadItem(Parcelable item) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
currentDownloadItem = item;
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else
perfornDownload(item);
}
private Parcelable currentDownloadItem;
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case 1:
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (currentDownloadItem != null) {
perfornDownload(currentDownloadItem);
currentDownloadItem = null;
} else
Toast.makeText(this, "Please select download again now that we have permission to save it", Toast.LENGTH_LONG).show();
} else
Toast.makeText(this, "Download cancelled, as we don\'t have permission to save the downloaded files", Toast.LENGTH_LONG).show();
break;
}
}
private void perfornDownload(Parcelable item) {
// Here we are sure we have the permission
}
}