I am re-writing an app for most versions of Android. The app is set to call android.hardware.Camera.Open() on launch. When the app launches it gives the error Camera Error: Could not connect to camera
The permissions in AndroidManifest.xml are
<uses-permission android:name="android.permission.FLASHLIGHT"/>
<uses-permission android:name="android.permission.camera"/>
<uses-feature android:name="android.hardware.camera" android:required="false"/>`.
Why can't it connect to the camera?
Problem solved!
The issue was simply a matter of capitalization. The line <uses-permission android:name="android.permission.camera"/> should actually read <uses-permission android:name="android.permission.CAMERA"/>. This happened because camera is a hardware feature, while CAMERA is a permission.
In previous versions of android in order to use camera hardware there was enough to state proper permissions and uses in android manifest, but since the Marshmallow version has appeared it's not enough to run the app anymore. As there is also need to enable runtime permissions. Consider using similar code, and suit it to your project, as it gives You opportunity to check and enable permission.
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (requestCode == PERMISSION_REQUEST_CODE) {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
cameraPreview.initializeCamera();
} else {
}
return;
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PERMISSION_REQUEST_CODE) {
cameraPreview.initializeCamera();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
public void requestCameraPermission() {
ActivityCompat.requestPermissions(this,
new String[]{
Manifest.permission.CAMERA
},
PERMISSION_REQUEST_CODE);
}
public void requestPermissionWithRationale() {
if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.CAMERA)) {
Snackbar.make(findViewById(android.R.id.content), R.string.no_cam_permission, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.snackbar_action_grant, new View.OnClickListener() {
#Override
public void onClick(View v) {
requestCameraPermission();
}
})
.show();
} else {
requestCameraPermission();
}
}
Use Camera for Deprecated
Below is the code
UPDATE --->
#Module
public class CameraModule {
#Provides
CameraSupport provideCameraSupport() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return new CameraNew(context);
} else {
return new CameraOld();
}
}
}
and then for Old target :
#SuppressWarnings("deprecation")
public class CameraOld implements CameraSupport {
private Camera camera;
#Override
public CameraSupport open(final int cameraId) {
this.camera = Camera.open(cameraId);
return this;
}
#Override
public int getOrientation(final int cameraId) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(cameraId, info);
return info.orientation;
}
}
for New Target :
public class CameraNew implements CameraSupport {
private CameraDevice camera;
private CameraManager manager;
public CameraNew(final Context context) {
this.manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public CameraSupport open(final int cameraId) {
try {
String[] cameraIds = manager.getCameraIdList();
if (ActivityCompat.checkSelfPermission(CameraPreview.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return null;
}
manager.openCamera(cameraIds[cameraId], new CameraDevice.StateCallback() {
#Override
public void onOpened(CameraDevice camera) {
CameraNew.this.camera = camera;
}
#Override
public void onDisconnected(CameraDevice camera) {
CameraNew.this.camera = camera;
// TODO handle
}
#Override
public void onError(CameraDevice camera, int error) {
CameraNew.this.camera = camera;
// TODO handle
}
}, null);
} catch (Exception e) {
// TODO handle
}
return this;
}
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public int getOrientation(final int cameraId) {
try {
String[] cameraIds = manager.getCameraIdList();
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraIds[cameraId]);
return characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
} catch (CameraAccessException e) {
// TODO handle
return 0;
}
}
}
Related
if you have Problem with file permissions, following solution worked for me on API 27, 29 and 30. I haven't tried for API version 28 but I assume it would also work for 28 because the file access rights are changed from API version 29.
AndroidManifest.xml,
<manifest
...
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29"/>
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
...
<application
...
android:requestLegacyExternalStorage="true"
>
...
</application>
</manifest>
main.java,
private static final int PERMISSIONS_REQUEST_CODE = 1240;
private ArrayList<String> appPermissions;
private ActivityResultLauncher<Intent> permissionLauncher;
private void checkPermissionsGranted() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
if ( !Environment.isExternalStorageManager() ) {
requestPermission();
} else {
// app has permissions, init app
initApp();
}
} else {
// older API-Versions
checkAndRequestPermissions();
}
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
permissionLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// app has permissions, init app
initApp();
} else {
//permission is denied
finish();
}
});
try {
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
// startActivityForResult(intent, AppConstants.STORAGE_PERMISSION_CODE);
permissionLauncher.launch(intent);
} catch (Exception e) {
Log.e(TAG, "Exp... " + e.toString());
Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
permissionLauncher.launch(intent);
}
}
}
public void checkAndRequestPermissions(){
// check which permissions are granted
List<String> listPermissionsNeeded = new ArrayList<>();
for (String perm:appPermissions){
if (ContextCompat.checkSelfPermission(this, perm) != PackageManager.PERMISSION_GRANTED){
listPermissionsNeeded.add(perm);
}
}
// ask for non-granted
if (!listPermissionsNeeded.isEmpty()){
ActivityCompat.requestPermissions(this, listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]), PERMISSIONS_REQUEST_CODE);
} else {
// app has all permissions, init app
initApp();
}
}
private void initApp() {
/**
* TODO
* */
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == PERMISSIONS_REQUEST_CODE) {
HashMap<String, Integer> permissionResults = new HashMap<>();
int deniedCount = 0;
for (int i = 0; i < grantResults.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
permissionResults.put(permissions[i], grantResults[i]);
deniedCount++;
}
}
if (deniedCount == 0) {
// app has all permissions, init app
initApp();
} else {
// denied
for (Map.Entry<String, Integer> entry : permissionResults.entrySet()) {
String permName = entry.getKey();
int permResult = entry.getValue();
// permission is denied (this is first time, when "newer ask again" is not checked)
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permName)) {
// show dialog
new MaterialAlertDialogBuilder(MainActivity.this)
.setTitle("Title")
.setMessage(getString(R.string.confirmation_permissions))
.setPositiveButton(getString(R.string.confirm_permissions_ok), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
checkAndRequestPermissions();
}
})
.setNegativeButton(getString(R.string.confirm_permissions_cancel), new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
// finish App
finish();
}
})
.show();
} else {
//permission is denied ("newer ask again" is checked)
finish();
}
}
}
}
}
I'm trying to download file via Download Manager in Instant app:
Uri uri = Uri.parse("https://images.pexels.com/photos/67636/rose-blue-flower-rose-blooms-67636.jpeg?auto=compress&cs=tinysrgb&dpr=2&h=750&w=1260");
DownloadManager downloadManager = (DownloadManager) context.getSystemService(DOWNLOAD_SERVICE);
downloadManager.enqueue(new DownloadManager.Request(uri)
.setTitle("Demo")
.setDescription("Something useful. No, really.")
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS,
"test.mp4"));
But getting an exception:
java.lang.IllegalStateException: Unable to create directory: /storage/emulated/0/Download
at android.app.DownloadManager$Request.setDestinationInExternalPublicDir(DownloadManager.java:539)
Is there other way to download files in Instant apps?
Issue seems it be related with Android Runtime Permission introduced in Android 6.0
When your app targeting API Level 23, by default all the permission is false you have to request permission dialog and approve the permission before using that into your app.
Ask the permission
public class RequestPermissionHandler {
private Activity mActivity;
private RequestPermissionListener mRequestPermissionListener;
private int mRequestCode;
public void requestPermission(Activity activity, #NonNull String[] permissions, int requestCode,
RequestPermissionListener listener) {
mActivity = activity;
mRequestCode = requestCode;
mRequestPermissionListener = listener;
if (!needRequestRuntimePermissions()) {
mRequestPermissionListener.onSuccess();
return;
}
requestUnGrantedPermissions(permissions, requestCode);
}
private boolean needRequestRuntimePermissions() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
private void requestUnGrantedPermissions(String[] permissions, int requestCode) {
String[] unGrantedPermissions = findUnGrantedPermissions(permissions);
if (unGrantedPermissions.length == 0) {
mRequestPermissionListener.onSuccess();
return;
}
ActivityCompat.requestPermissions(mActivity, unGrantedPermissions, requestCode);
}
private boolean isPermissionGranted(String permission) {
return ActivityCompat.checkSelfPermission(mActivity, permission)
== PackageManager.PERMISSION_GRANTED;
}
private String[] findUnGrantedPermissions(String[] permissions) {
List<String> unGrantedPermissionList = new ArrayList<>();
for (String permission : permissions) {
if (!isPermissionGranted(permission)) {
unGrantedPermissionList.add(permission);
}
}
return unGrantedPermissionList.toArray(new String[0]);
}
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
if (requestCode == mRequestCode) {
if (grantResults.length > 0) {
for (int grantResult : grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
mRequestPermissionListener.onFailed();
return;
}
}
mRequestPermissionListener.onSuccess();
} else {
mRequestPermissionListener.onFailed();
}
}
}
public interface RequestPermissionListener {
void onSuccess();
void onFailed();
}
Use in Activity like this:
public class MainActivity extends AppCompatActivity {
private RequestPermissionHandler mRequestPermissionHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mRequestPermissionHandler = new RequestPermissionHandler();
findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
handleButtonClicked();
}
});
}
private void handleButtonClicked(){
mRequestPermissionHandler.requestPermission(this, new String[] {
Manifest.permission.RECEIVE_SMS, Manifest.permission.READ_EXTERNAL_STORAGE
}, 123, new RequestPermissionHandler.RequestPermissionListener() {
#Override
public void onSuccess() {
Toast.makeText(MainActivity.this, "request permission success", Toast.LENGTH_SHORT).show();
}
#Override
public void onFailed() {
Toast.makeText(MainActivity.this, "request permission failed", Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mRequestPermissionHandler.onRequestPermissionsResult(requestCode, permissions,
grantResults);
}
}
and don't forget to add this in your manifest
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
I want to open camera when clicking an item on my dialog box, but I get an error like below. I've been adding a camera permission to manifest.xml.
java.lang.SecurityException: Permission Denial: starting Intent { act=android.media.action.IMAGE_CAPTURE cmp=com.sonyericsson.android.camera/.MultiWindowActivity } from ProcessRecord{b42fcde 29884:ukmutilizer.project.com.ukm_utilizer/u0a273} (pid=29884, uid=10273) with revoked permission android.permission.CAMERA
this is my function
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.personal_data_step, container, false);
ButterKnife.bind(this, view);
imageEktp.setClickable(true);
imageEktp.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//Log.d("test : ", "testing");
CharSequence menu[] = new CharSequence[]{"Take From Galery", "Open Camera"};
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setTitle("Pick a Picture");
builder.setItems(menu, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if(i == 0){
Toast.makeText(getActivity(), "galery", Toast.LENGTH_SHORT).show();
}else{
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivity(intent);
}
}
});
builder.show();
}
});
return view;
}
Ensure you request Runtime Camera Permission from the user.
private static final int CAMERA_REQUEST_CODE = 100;
Request permission if not granted.
if (checkSelfPermission(Manifest.permission.CAMERA)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA},
CAMERA_REQUEST_CODE);
}
Do stuff inside onRequestPermissionsResult.
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == CAMERA_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, "Camera permission granted.", Toast.LENGTH_LONG).show();
// Do stuff here for Action Image Capture.
} else {
Toast.makeText(this, "Camera permission denied.", Toast.LENGTH_LONG).show();
}
}
}
Also this should be declared inside Manifest as well.
You have to get runtime permission then only access your camera
like
in manifest
<uses-permission android:name="android.permission.CAMERA" />
in Java
private static final int MY_CAMERA_REQUEST_CODE = 100;
private void processPickImage() {
if(hasCameraPermission()) {
pickImage();
}
else
{
requestCameraPermission();
}
}
private boolean hasCameraPermission() {
return ContextCompat.checkSelfPermission(context,
Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
}
#TargetApi(Build.VERSION_CODES.M)
private void requestCameraPermission() {
requestPermissions(new String[]{Manifest.permission.CAMERA},
MY_CAMERA_REQUEST_CODE );
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions,
#NonNull int[] grantResults) {
switch (requestCode) {
case MY_CAMERA_REQUEST_CODE :
processPickImage();
break;
default:
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
The user has to confirm the permission request.
Try
public class ActivityMain extends AppCompatActivity
{
public static final int MY_PERMISSIONS_REQUEST = 0;
#Override
protected void onCreate(Bundle savedInstanceState)
{
if (ContextCompat.checkSelfPermission(ActivityMain.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED)
{ ActivityCompat.requestPermissions(ActivityMain.this, new String[]{Manifest.permission.CAMERA}, MY_PERMISSIONS_REQUEST);
}
[...]
}
#Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults)
{ switch (requestCode)
{ case MY_PERMISSIONS_REQUEST:
[...]
}
}
}
when you run your app in 6.0 above like marshmallow device then need permission other wise no need to permission.
that time your code work..
if run marshmallow device that time need permission then make below code ..
private void alertDialog(){
CharSequence menu[] = new CharSequence[]{"Take From Galery", "Open Camera"};
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("Pick a Picture");
builder.setItems(menu, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialogInterface, int i) {
if(i == 0){
Toast.makeText(getApplicationContext(), "galery", Toast.LENGTH_SHORT).show();
}else{
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
startActivity(intent);
}
}
});
builder.show();
}
then above method put in permission code like below ..
if (ContextCompat.checkSelfPermission(webView.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(webView.this, Manifest.permission.CAMERA)) {
alertDialog();
}
else{
ActivityCompat.requestPermissions(webView.this, new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);
}
}
add two permission into manifest file ..
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
your error main problem is permission if you add this below line is work.
if (ContextCompat.checkSelfPermission(webView.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(webView.this, Manifest.permission.CAMERA)) {
alertDialog();
}
else{
ActivityCompat.requestPermissions(webView.this, new String[] { Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE }, 0);
}
}
I make an AARplugins for android which accesses Camera.
But it does not activate onActivityResult.
public static void showCamera ( ) // Connect Camera
{
String Uri;
Activity CameraActivity = UnityPlayer.currentActivity;
Toast.makeText(CameraActivity , "first" ,Toast.LENGTH_LONG).show();
Log.d(" before ImageUrl###### ", "first");
CameraActivity.runOnUiThread(new Runnable()
{
public void run() {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
CameraActivity.startActivityForResult(intent,1);
}
});
}
///////////////Don't activate↓//////////////////////////////////
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Log.d(" before ImageUrl###### ", "twotwotwotwotwotwotwo"); //Don't activate
}
////////////////////////////////////////////////////////////////////////////
why don't activate this?
Try This,
Camera permission
private static final int REQUEST_CAMERA = 112;
btn_cam.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (Build.VERSION.SDK_INT >= 23) {
String[] PERMISSIONS = {android.Manifest.permission.CAMERA};
if (!hasPermissions(mContext, PERMISSIONS)) {
ActivityCompat.requestPermissions((Activity) mContext, PERMISSIONS, REQUEST_CAMERAE );
} else {
//open camera
}
} else {
//open camera
}
}
});
}
get Permissions Result
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String[] permissions, #NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode) {
case REQUEST_CAMERA: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
//open camera
}
}
}
}
check permissions for marshmallow
private static boolean hasPermissions(Context context, String... permissions) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && context != null && permissions != null) {
for (String permission : permissions) {
if (ActivityCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
}
return true;
}
AndroidManifest.xml
<uses-permission android:name="android.permission.CAMERA" />
I am trying to take an image from Gallery and set it to an imageview but in Android 6 there are some permission problems. Below is the method to ask for the permission. Should I ask for read external storage or write external storage?
Here is what I have done so far:
private static final int READ_CONTACTS_PERMISSIONS_REQUEST = 1;
public void getPermissionToReadExternalStorage() {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
if (shouldShowRequestPermissionRationale(
Manifest.permission.READ_EXTERNAL_STORAGE)) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
READ_CONTACTS_PERMISSIONS_REQUEST);
}}}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String permissions[],
#NonNull int[] grantResults){
// Make sure it's our original READ_CONTACTS request
if (requestCode == READ_CONTACTS_PERMISSIONS_REQUEST) {
if (grantResults.length == 1 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(getActivity(), "Read Contacts permission granted", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(getActivity(), "Read Contacts permission denied", Toast.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
Now my on click listener to pick data from the Gallery:
pro.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
intent.setType("image/*");
if (android.os.Build.VERSION.SDK_INT >= 23) {
getPermissionToReadExternalStorage();
if (getPermissionToReadExternalStorage () this???? <==)
startActivityForResult(Intent.createChooser(intent, "Select Picture"), 0);
} else {
startActivityForResult(Intent.createChooser(intent, "Select Picture"), 0);
}}
});
return v;
}
Now I want to get result of the method getPermissionToReadExternalStorage() so I can start the Activity for picking gallery for Android 6. How can I get the result of the void class?
And another thing is do I have to write method for every permission my app asks for?
So I have completely rewritten the code to request permissions.
Now it supports requesting for multiple permissions and running code with proper result.
Also it works with preMarshmallow devices, so you don't have to check and copy the code in that case.
First, create an Activity class with this code (You can extend any king of activity you need, e.g. AppCompatActivity):
public abstract class PermissionActivity extends AppCompatActivity {
private final ArrayList<PermissionListener> permissionListeners = new ArrayList<>();
#SuppressWarnings("unused")
public void requestPermissions(int requestCode, String[] requestPermissions, PermissionListener permissionListener) {
requestPermissions(requestCode, requestPermissions, null, permissionListener);
}
#SuppressWarnings("unused")
public void requestPermissions(final int requestCode, String[] requestPermissions, String message, final PermissionListener permissionListener) {
final int[] grantResults = new int[requestPermissions.length];
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> list_notGranted = new ArrayList<>();
for (String requestPermission : requestPermissions)
if (ContextCompat.checkSelfPermission(this, requestPermission) != PackageManager.PERMISSION_GRANTED)
list_notGranted.add(requestPermission);
if (list_notGranted.size() > 0) {
permissionListeners.add(permissionListener);
requestPermissions = list_notGranted.toArray(new String[list_notGranted.size()]);
if (message != null) {
boolean shouldShowRequestPermissionRationale = false;
for (String permission : requestPermissions)
if (ActivityCompat.shouldShowRequestPermissionRationale(this, permission)) {
shouldShowRequestPermissionRationale = true;
break;
}
if (shouldShowRequestPermissionRationale) {
final String[] f_requestPermissions = requestPermissions;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(message);
DialogInterface.OnClickListener onClickListener = new DialogInterface.OnClickListener() {
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
PermissionActivity.super.requestPermissions(f_requestPermissions, requestCode);
break;
default:
for (int i = 0; i < grantResults.length; i++)
grantResults[i] = PackageManager.PERMISSION_DENIED;
if (permissionListener != null)
permissionListener.onResult(requestCode, f_requestPermissions, grantResults);
break;
}
}
};
builder.setPositiveButton("OK", onClickListener);
builder.setNegativeButton("Cancel", onClickListener);
builder.show();
} else {
super.requestPermissions(requestPermissions, requestCode);
}
} else {
super.requestPermissions(requestPermissions, requestCode);
}
} else {
for (int i = 0; i < grantResults.length; i++)
grantResults[i] = PackageManager.PERMISSION_GRANTED;
if (permissionListener != null)
permissionListener.onResult(requestCode, requestPermissions, grantResults);
}
} else {
if (permissionListener != null) {
for (int i = 0; i < grantResults.length; i++)
grantResults[i] = PackageManager.PERMISSION_GRANTED;
permissionListener.onResult(requestCode, requestPermissions, grantResults);
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, #NonNull String permissions[], #NonNull int[] grantResults) {
for (Iterator<PermissionListener> it = permissionListeners.iterator(); it.hasNext(); ) {
PermissionListener permissionListener = it.next();
if (permissionListener.onResult(requestCode, permissions, grantResults)) {
it.remove();
}
}
}
public interface PermissionListener {
boolean onResult(int requestCode, String[] requestPermissions, int[] grantResults);
}
}
If you want to request permissions from Fragments, add this class:
public class PermissionFragment extends Fragment {
#SuppressWarnings("unused")
public void requestPermissions(int requestCode, String[] requestPermissions, PermissionActivity.PermissionListener permissionListener) {
requestPermissions(requestCode, requestPermissions, null, permissionListener);
}
#SuppressWarnings("unused")
public void requestPermissions(final int requestCode, String[] requestPermissions, String message, PermissionActivity.PermissionListener permissionListener) {
((PermissionActivity) getActivity()).requestPermissions(requestCode, requestPermissions, message, permissionListener);
}
}
Your Activities and Fragments should extend these classes instead of the standart ones.
Now you are ready to request the permissions by calling a method:
requestPermissions(int requestCode, String[] requestPermissions, PermissionListener permissionListener)
If the permission is required for the app to work, you should call this method and specify the message saying why the permission is required.
requestPermissions(int requestCode, String[] requestPermissions, String message, PermissionListener permissionListener)
DONT MISSCALL THE DEFAULT METHOD, WHICH IS
// DON'T USE THIS ONE!
requestPermissions(String[] requestPermissions, int requestCode)
// DON'T USE THIS ONE!
Here is the example of requesting contacts:
private void requestAndLoadContacts() {
String[] permissions = new String[]{Manifest.permission.READ_CONTACTS};
requestPermissions(REQUEST_PERMISSIONS_CONTACTS, permissions, "Read contacts permission is required for the app to work!", new PermissionListener() {
#Override
public boolean onResult(int requestCode, String[] requestPermissions, int[] grantResults) {
// Check if the requestCode is ours
if (requestCode == REQUEST_PERMISSIONS_CONTACTS) {
// Check if the permission is correct and is granted
if (requestPermissions[0].equals(Manifest.permission.READ_CONTACTS) && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission granted
// Calling a method to actually load the contacts
loadContacts();
} else {
// Permission not granted
Toast.makeText(MainActivity.this, "Access denied!", Toast.LENGTH_SHORT).show();
}
return true;
}
return false;
}
});
}
NOTE:
When you implement the PermissionListener, don't forget to return true when the requestCode is the correct one, otherwise the PermissionListener won't be removed from the ArrayList and you'll most likely get a small memory leak.
EDIT
I have rewritted the code and posted in another answer.
Old answer:
Yes, you have to check and ask for permission every time.
Usually I write the code like this:
private int requestPermissionCode;
private Runnable requestPermissionRunnable;
private void runPermissionCode(String requestPermission, int requestCode, Runnable codeToRun) {
if (android.os.Build.VERSION.SDK_INT >= 23) {
if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.READ_EXTERNAL_STORAGE)
!= PackageManager.PERMISSION_GRANTED) {
requestPermissionCode = requestCode;
requestPermissionRunnable = codeToRun;
requestPermissions(new String[]{requestPermission},
requestCode);
}
} else {
codeToRun.run();
}
}
#Override
public void onRequestPermissionsResult(int requestCode,
#NonNull String permissions[],
#NonNull int[] grantResults) {
if (requestCode == requestPermissionCode) {
if (grantResults.length == 1 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (requestPermissionRunnable != null)
requestPermissionRunnable.run();
} else {
Toast.makeText(getActivity(), "Permission denied", Toast.LENGTH_SHORT).show();
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
}
and run it like this:
runPermissionCode(Manifest.permission.READ_EXTERNAL_STORAGE, READ_CONTACTS_PERMISSIONS_REQUEST, new Runnable() {
#Override
public void run() {
// your code here
}
});
I am sure it is not a best way, but at least it gives a possibility to request permission and make actions easier.
Initialize Your Permission
private static final int INITIAL_REQUEST = 1337;
private static final int GET_ACCOUNTS = INITIAL_REQUEST+2;
private static final int LOCATION_REQUEST =INITIAL_REQUEST+3;
private static final String[] INITIAL_PERMS = {
Manifest.permission.GET_ACCOUNTS,
Manifest.permission.INTERNET,
Manifest.permission.ACCESS_FINE_LOCATION
};
Check for device and Request for permissions
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!canAccessAccounts()|| !canAccessLocation() ||!canAccessInternet()) {
requestPermissions(INITIAL_PERMS, INITIAL_REQUEST);
}
}
Check Permission is granted Or not
private boolean canAccessAccounts() {
return (hasPermission(Manifest.permission.GET_ACCOUNTS));
}
private boolean canAccessLocation() {
return (hasPermission(Manifest.permission.ACCESS_FINE_LOCATION));
}
private boolean canAccessInternet() {
return (hasPermission(Manifest.permission.INTERNET));
}
private boolean hasPermission(String perm) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return (PackageManager.PERMISSION_GRANTED == checkSelfPermission(perm));
}
return (true);
}
Update Permissions and Check method for permissions onRequestPermissionsResult
void UpdatePermissions(){
canAccessInternet();
canAccessLocation();
canAccessInternet();
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
UpdatePermissions();
switch(requestCode) {
case GET_ACCOUNTS:
if (canAccessAccounts()) {
}
else {
}
break;
case LOCATION_REQUEST:
if (canAccessLocation()) {
}
else {
}
break;
case INITIAL_REQUEST:
if(canAccessInternet()){
}else {
}
break;
}
}