I have confirmed that the permissions are correct for Camera access, however on the later OS versions (perhaps API 25 and above) the camera does not open, it just gives the errror in debug console;
W/System.err: java.io.IOException: Permission denied
This is the method;
public void cameraClicked(View view) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File tempFile = new File(Environment.getExternalStorageDirectory().getPath()+ "/photoTemp.png");
try {
tempFile.createNewFile();
Uri uri = Uri.fromFile(tempFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, 2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
It does work on Android 7 and below.
EDIT - The following code is now opening the camera correctly, however once the photo is taken it progresses to the next screen but does not show the captured image... Just a black image.
public void cameraClicked(View view) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
String path=this.getExternalCacheDir()+"file.png";
File file=new File(path);
Uri uri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider",file);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, 2);
}
W/System.err: java.io.IOException: Permission denied
This happened because you create file to external storage over Android8/9/10.
If your targetSdk is 23 or higher, you should request permissions
dynamically. to know more : Requesting Permissions at Run Time
to get File path you can use
Context.getExternalFilesDir()/Context.getExternalCacheDir() for
example String path=Context.getExternalCacheDir()+"file.text"; File
file=new File(path) it doesnt need permission if the filepath is
"Android/data/app package/file name"
As in the Android Documentation, you need to write to the external storage, you must request the WRITE_EXTERNAL_STORAGE permission in your manifest file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
...
</manifest>
If you use API 23 (Marshmallow) and above, you need to Requesting Permissions at Run Time because it's a Dangerous Permission.
if (ContextCompat.checkSelfPermission(
CONTEXT, Manifest.permission.REQUESTED_PERMISSION) ==
PackageManager.PERMISSION_GRANTED) {
// You can use the API that requires the permission.
performAction(...);
} else if (shouldShowRequestPermissionRationale(...)) {
// In an educational UI, explain to the user why your app requires this
// permission for a specific feature to behave as expected. In this UI,
// include a "cancel" or "no thanks" button that allows the user to
// continue using your app without granting the permission.
showInContextUI(...);
} else {
// You can directly ask for the permission.
// The registered ActivityResultCallback gets the result of this request.
requestPermissionLauncher.launch(
Manifest.permission.REQUESTED_PERMISSION);
}
Reference source link
reference
make file to external
Edit answer
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, 0);
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode){
case 0:
if (resultCode == Activity.RESULT_OK){
Bitmap thumbnail = (Bitmap) data.getExtras().get("data");
SaveImage(thumbnail);
}
break;
}
}
private static void SaveImage(Bitmap finalBitmap) {
String root = Environment.getExternalStorageDirectory().getAbsolutePath();
File myDir = new File(root + "/saved_images");
myDir.mkdirs();
String fname = "Image-"+ Math.random() +".jpg";
File file = new File (myDir, fname);
if (file.exists ()) file.delete ();
try {
FileOutputStream out = new FileOutputStream(file);
finalBitmap.compress(Bitmap.CompressFormat.JPEG, 90, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I also faced this issue before, seems like adding this inside the Application tag under AndroidManifest.xml file solve the problem for me:
<application
...
android:requestLegacyExternalStorage="true">
</application>
Related
The goal is to update my app without using the google play store. I’m trying to download a .apk file from a server and then install it programmatically. I’m currently getting an error that the download is unsuccessful and that there was an error while parsing the package. I have the READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions requested at runtime. I had to go into the tablet's settings to give permission to “Install unknown apps”. I cannot get REQUEST_INSTALL_PACKAGES to be requested at runtime.
If I change the fileName and update URL to get a .txt that I store in the same folder on the server as the .apk AND comment out “.setMimeType()” I can download and view a .txt file.
Have the updates to Android Studio made older tutorials or examples of this outdated?
Is there a new or better way to download .apk’s from servers programmatically?
Is the lack of REQUEST_INSTALL_PACKAGES permission at runtime what is preventing my .apk from downloading?
Any advice on how to fix my code?
Here are some code snippets to help
gradle:app
android {
compileSdk 31
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "farrpro.project"
minSdk 28
targetSdk 30
}
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.ACTION_INSTALL_PACKAGE"/>
MainActivity.java
private void hasInstallPermission() { // runs in onCreate()
if (getApplicationContext().checkSelfPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.REQUEST_INSTALL_PACKAGES}, 1);
}
}
void downloadAndInstallUpdate(){ // runs when users accepts request to download update
String fileName = "update.apk";
// example of update’s string
update = “https://myserver.net/update.apk”;
//set download manager
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(update));
request.setTitle(fileName)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
.setDescription("Downloading")
//.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI | DownloadManager.Request.NETWORK_MOBILE)
.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName)
.setMimeType("application/vnd.android.package-archive");
// get download service and enqueue file
final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final long downloadId = manager.enqueue(request);
System.out.println("Max Bytes: "+DownloadManager.getMaxBytesOverMobile(this)); //returns null
//set BroadcastReceiver to install app when .apk is downloaded
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent) {
System.out.println("Is download successful: "+ manager.getUriForDownloadedFile(downloadId)); //returns null
System.out.println("Mime: "+manager.getMimeTypeForDownloadedFile(downloadId)); //returns application/vnd.android.package-archive
Intent install = new Intent(Intent.ACTION_VIEW);
File file = new File(ctxt.getExternalFilesDir(null) + fileName);
Uri downloadedApk = FileProvider.getUriForFile(ctxt, "farrpro.project.provider", file);
install.setDataAndType(downloadedApk,
manager.getMimeTypeForDownloadedFile(downloadId));
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
startActivity(install);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");// this never prints
}
unregisterReceiver(this);
finish();
}
};
//register receiver for when .apk download is complete
registerReceiver(onComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}
The problem was the server had restricted download types. My code worked more or less after that setting was changed. I ended up needing to change the intents in my broadcast receiver so that after the download was completed the new .apk would immediately install. Here are the changes I made to make the code posted work.
final long downloadId = manager.enqueue(request);
BroadcastReceiver onComplete = new BroadcastReceiver() {
public void onReceive(Context ctxt, Intent intent1) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(manager.getUriForDownloadedFile(downloadId), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
try {
getApplicationContext().startActivity(intent);
} catch (ActivityNotFoundException e) {
e.printStackTrace();
Log.e("TAG", "Error in opening the file!");
}
unregisterReceiver(this);
finish();
}
};
If your app is running on Android O or newer, you have to allow unknown app sources for your app.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!context.packageManager.canRequestPackageInstalls()) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse(String.format("package:%s", context.packageName))
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
}
I want my users to be able to share an image and select an app to share it to whether its something like their native messenger app, or twitter. Whenever I go to select the app I want to share the image to, I get a message saying "This media can't be loaded" or something like that. Here is the sharing code in BitmapUtils.java
static void shareImage(Context context, String imagePath) {
// Create the share intent and start the share activity
File imageFile = new File(imagePath);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
Uri photoURI = FileProvider.getUriForFile(context, FILE_PROVIDER_AUTHORITY, imageFile);
shareIntent.putExtra(Intent.EXTRA_STREAM, photoURI);
context.startActivity(shareIntent);
}
Here is my file provider code in my Manifest file:
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.aaronapp.hideme.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths" />
Here is the file_paths file which contains the file paths.
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-cache-path name="my_cache" path="." />
<external-path name="my_images" path="Pictures/" />
</paths>
Here is the share method that is invoked inside the MainActivity class.
/**
* OnClick method for the share button, saves and shares the new bitmap.
*/
#OnClick(R.id.share_button)
public void shareMe() {
// Delete the temporary image file
BitmapUtils.deleteImageFile(this, mTempPhotoPath);
// Share the image
BitmapUtils.shareImage(this, mTempPhotoPath);
}
If you need anymore information that I forgot to show I'll be happy to supply it. I'm trying to fix this issue and get my images to share to different apps(I know Facebook has a certain way of sharing images, but I will tackle that later)
You can also replicate this issue by downloading the Hide me, Emoji App on the google play store, taking a picture and trying to share it across your apps.https://play.google.com/store/apps/details?id=com.aaronapp.hideme
This will allow you to read files from Internal or external sdcard.
Add this in manifest.xml
<!-- this is For Access External file Storage -->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.demo.test.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/file_paths"/>
</provider>
file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="external_files"
path="." />
<root-path
name="external_files"
path="/storage/"/>
</paths>
Try with adding flag Intent.FLAG_GRANT_READ_URI_PERMISSION to Intent
The file you want to share with another app, you need to allow the client app to access the file. To allow access, grant permissions to the client app by adding the content URI to an Intent and then setting permission flags on the Intent.
// Grant temporary read permission to the content URI
shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
The permissions you grant are temporary and expire automatically when the receiving app's task stack is finished.
Please try this code, this is working in my case
File filePath = new File(FIlePath);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND_MULTIPLE);
ArrayList<Uri> uriArrayList = new ArrayList<>();
uriArrayList.add(getUriFromFilePath(filePath));
intent.setType("image/*");
intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriArrayList);
startActivity(intent);
public Uri getUriFromFilePath(Context theCtx, File theSrcPath) {
Uri requirdUri = null;
// observation
// SDKversion: 25 -- Uri.fromFile Not working, So we have to use Provider
// FileProvider.getUriForFile will not work when the file is located in external Sdcard.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
requirdUri = FileProvider.getUriForFile(theCtx,
theCtx.getApplicationContext().getPackageName() + PROVIDER_FILE_EXTENSION,
theSrcPath);
} else {
requirdUri = Uri.fromFile(theSrcPath);
}
return requirdUri;
}
I have done following changes in your code, i had tested app after
changes and able to share image now.
Please check and let me know.
in MainActivity, shareMe method you have delete the temp file before sharing that why the error was occured.
now i have delete the Temp file after sharing.
Modified code in MainActivity.java
public static final int REQUEST_CODE_SHARE_FILE = 100;
public void shareMe()
{
// BitmapUtils.deleteImageFile(this, mTempPhotoPath); delete temp file in on activity result.
BitmapUtils.shareImage(MainActivity.this, mTempPhotoPath);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
//If the image capture activity was called and was successful
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK)
{
processAndSetImage();
}
else if(requestCode == REQUEST_CODE_SHARE_FILE)
{
BitmapUtils.deleteImageFile(this, mTempPhotoPath);
}else {
BitmapUtils.deleteImageFile(this, mTempPhotoPath);
}
}
Modified code in BitmapUtils.java
static void shareImage(Activity activity, String imagePath) {
// Create the share intent and start the share activity
File imageFile = new File(imagePath);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/*");
Uri photoURI = FileProvider.getUriForFile(activity, FILE_PROVIDER_AUTHORITY, imageFile);
shareIntent.putExtra(Intent.EXTRA_STREAM, photoURI);
activity.startActivityForResult(shareIntent,MainActivity.REQUEST_CODE_SHARE_FILE);
}
I am testing your app on the device with Android version 6.0 and app gets crashed every time.
Inside detectFacesandOverlayEmoji method, on line number 32(SparseArray faces = detector.detect(frame);)
a) Sometimes app remains open without showing anything in logcat.
b) Sometimes app crashed with following error in logcat.
05-24 11:00:27.192 17880-17880/com.aaronapp.hideme E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.aaronapp.hideme, PID: 17880
java.lang.OutOfMemoryError: Failed to allocate a 51916812 byte allocation with 16765168 free bytes and 36MB until OOM
at com.google.android.gms.vision.Frame.zzTM(Unknown Source)
at com.google.android.gms.vision.Frame.getGrayscaleImageData(Unknown Source)
at com.google.android.gms.vision.face.FaceDetector.detect(Unknown Source)
at com.aaronapp.hideme.HideMe.detectFacesandOverlayEmoji(HideMe.java:32)
at com.aaronapp.hideme.MainActivity.processAndSetImage(MainActivity.java:153)
at com.aaronapp.hideme.MainActivity.onActivityResult(MainActivity.java:133)
at android.app.Activity.dispatchActivityResult(Activity.java:6428)
at android.app.ActivityThread.deliverResults(ActivityThread.java:3695)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:3742)
at android.app.ActivityThread.-wrap16(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1393)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Make use of Picasso, sharing you a working code from my project.
Put this in your App level gradle,
implementation 'com.squareup.picasso:picasso:2.71828'
Code used is given below,
static void shareImage(Context context, String imagePath) {
// Create the share intent and start the share activity
Picasso.with(getApplicationContext())
.load(imagePath)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
Intent i = new Intent(Intent.ACTION_SEND);
i.setType("image/*");
i.putExtra(Intent.EXTRA_STREAM, getLocalBitmapUri(bitmap));
if (!TextUtils.isEmpty(des)) {
i.putExtra(Intent.EXTRA_TEXT, des);
}
startActivity(Intent.createChooser(i, "Share Image"));
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
}
public Uri getLocalBitmapUri(Bitmap bmp) {
Uri bmpUri = null;
try {
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES),
"share_image_" + System.currentTimeMillis() + ".png");
FileOutputStream out = new FileOutputStream(file);
bmp.compress(Bitmap.CompressFormat.PNG, 90, out);
out.close();
bmpUri = Uri.fromFile(file);
} catch (IOException e) {
e.printStackTrace();
}
return bmpUri;
}
Hope it may help you.
I am currently working on an activity that will let the user select an image from the gallery, and then put that image's URI into an SQLite database.
I have another activity where I take that URI and display it on an ImageView. I have this working perfectly on Lollipop and older. But anything newer it crashes when I pull up the activity that displays the image.
Here is the LOGCAT line of the crash:
Caused by: java.lang.SecurityException: Permission Denial: opening provider com.google.android.apps.photos.contentprovider.MediaContentProvider from ProcessRecord{8193e94 13574:jeremy.com.wineofmine/u0a97} (pid=13574, uid=10097) that is not exported from uid 10044
This makes it seem like a permissions thing, but I am requesting the WRITE_EXTERNAL_STORAGE and READ_EXTERNAL STORAGE in the manifest, as well as requesting those permissions on run-time on the activity where it displays the image.
And here is the exact line where it's crashing (this is in the activity where it displays the image:)
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageURI);
And this is imageURI:
imageURI = Uri.parse(cursor.getString(cursor.getColumnIndexOrThrow(WineContract.WineEntry.COLUMN_WINE_IMAGE)));
//This code returns this: content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F62/ACTUAL/860591124
Here is the code to the relevant bits.
This is the intent to open up the gallery:
Intent intentGallery = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(intentGallery, SELECT_IMAGE);
And this is the onActivityResult method. The main goal of this method is to set the imageThumbail ImageView as the thumbnail, and also to set "photoURI" as the selected image's URI.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
//This is if they choose an image from the gallery
if (requestCode == SELECT_IMAGE && resultCode == RESULT_OK) {
if (requestCode == SELECT_IMAGE) {
// Get the url from data
Uri selectedImageUri = data.getData();
if (null != selectedImageUri) {
// Get the path from the Uri
String path = getPathFromURI(selectedImageUri);
Log.i("ADDACTIVITY", "Image Path : " + path);
bitmap = null;
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), selectedImageUri);
} catch (IOException e) {
e.printStackTrace();
}
bitmapThumbnail = ThumbnailUtils.extractThumbnail(bitmap,175,175);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmapThumbnail.compress(Bitmap.CompressFormat.JPEG, 100, stream);
byteArray = stream.toByteArray();
// Set the image in ImageView
imageThumbnail.setImageBitmap(bitmapThumbnail);
//Setting photoURI (which gets put into the database) as the gallery's image URI
photoURI = data.getData();
}
}
}
}
Any pointers to what I could be doing wrong, would be great.
The question is pretty common and I have googled it but it still wont work. I'm simply trying to save a text file using the below code:
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(getApplicationContext(), "Access denied", Toast.LENGTH_LONG).show();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/data";
File dir = new File(path);
dir.mkdirs();
File file = new File(path + "/savedFile.txt");
String saveText = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
FileOutputStream fos = null;
try {
fos = new FileOutputStream(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
try {
try {
fos.write(saveText.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
} finally {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Toast.makeText(getApplicationContext(), "Saved", Toast.LENGTH_LONG).show();
break;
and in my manifest I have declared:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
However everytime I try and run the code the app crashes with the error 'Unfortunately, APP_NAME has stopped." Can anyone tell me what is wrong with my code?
if ((checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)&& Build.VERSION.SDK_INT >= 23 ) {
Log.v(TAG,"Permission is granted");
return true;}
else{
ActivityCompat.requestPermissions(this, new String[]Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_CODE);
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if(grantResults[0]== PackageManager.PERMISSION_GRANTED){
Log.v(TAG,"Permission: "+permissions[0]+ "was "+grantResults[0]);
String state = Environment.getExternalStorageState();
if (!Environment.MEDIA_MOUNTED.equals(state)) {
Toast.makeText(getApplicationContext(), "Access denied", Toast.LENGTH_LONG).show();
}
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/data";
File dir = new File(path);
dir.mkdirs();
File file = new File(path + "/savedFile.txt");
String saveText = new SimpleDateFormat("yyyyMMdd_HHmmss").format(Calendar.getInstance().getTime());
try {
fos = new FileOutputStream(file);
OutputStreamWriter ow = new OutputStreamWriter(fos);
ow.write(saveText.getBytes());
ow.append(saveText.getText());
ow.close();
fos.close();
Toast.makeText(getBaseContext(),
"Done writing SD 'mysdfile.txt'",Toast.LENGTH_SHORT).show();
}} catch (Exception e) {
Toast.makeText(getBaseContext(), e.getMessage(),Toast.LENGTH_SHORT).show();
}
}
}
You need to use something like this code.Because you need to specify runtime permissions.Marshmallow needs you to check the permissions first to use respective resources.
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
I have an app that allow user to upload a photo on wall.
The code works well for the majority of users, but I have reported that the application crashes sometimes when uploading photo.
The problem is not in taking the pictures from the camera, but it is when you have to take the path of the picture.
The version of Android that is causing this problem is 4.4.2, but I do not understand how to fix it.
post some code:
activityResult:
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
if (requestCode == CAMERA_PIC_REQUEST) {
try {
//picUri is a global variable Uri
picUri = data.getData();
cropImage();
} catch (Exception e) {
e.printStackTrace();
}
}
else if(requestCode == PIC_CROP) {
try{
//thumbnail is a global variable Bitmap
thumbnail = MediaStore.Images.Media.getBitmap(context.getContentResolver(), cropImageUri);
setImage();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
}
hot to crop image:
public void cropImage() {
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
//indicate image type and Uri
cropIntent.setDataAndType(picUri, "image/*");
//set crop properties
cropIntent.putExtra("crop", "true");
//indicate aspect of desired crop
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
cropIntent.putExtra("scale", true);
//indicate output X and Y
cropIntent.putExtra("outputX", 700);
cropIntent.putExtra("outputY", 700);
//retrieve data on return
cropIntent.putExtra("return-data", false);
File f = createNewFile("CROP_");
try{
f.createNewFile();
}
catch (IOException e) {
e.printStackTrace();
}
//cropImageUri is a global variable Uri
cropImageUri = Uri.fromFile(f);
cropIntent.putExtra(MediaStore.EXTRA_OUTPUT, cropImageUri);
//start the activity - we handle returning in onActivityResult
startActivityForResult(cropIntent, PIC_CROP);
}
catch(ActivityNotFoundException anfe){
anfe.printStackTrace();
}
}
create new File:
private File createNewFile(String prefix) {
if (prefix== null) {
prefix="IMG_";
}
else if("".equalsIgnoreCase(prefix)) {
prefix="IMG_";
}
File newDirectory = new File(Environment.getExternalStorageDirectory()+"/mypics/");
if (!newDirectory.exists()) {
if (newDirectory.mkdir()) {
}
}
File file = new File(newDirectory,(prefix+System.currentTimeMillis()+".jpg"));
if (file.exists()) {
file.delete();
try {
file.createNewFile();
}catch (IOException e) {
e.printStackTrace();
}
}
return file;
}
then when a user click on "send" method preUploadImage is called:
public void preUploadImage() {
UploadImage uploadImage = new UploadImage();
Uri newUri = getImageUri(thumbnail);
try{
// System.out.println("uri = "+picUri);
uploadImage.upload(getRealPathFromURI(newUri));
}
catch (IOException e) {
e.printStackTrace();
}
}
public Uri getImageUri(Bitmap inImage) {
String path = MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
and in the last row the error appears.
return Uri.parse(path);
this row cause a NullPointerException
java.lang.NullPointerException: uriString
at android.net.Uri$StringUri.<init>(Uri.java:468)
at android.net.Uri$StringUri.<init>(Uri.java:458)
at android.net.Uri.parse(Uri.java:430)
at com.delsorboilario.verdebio.ScriviDomanda.getImageUri(ScriviDomanda.java:584)
at com.delsorboilario.verdebio.ScriviDomanda.preUploadImage(ScriviDomanda.java:608)
at com.delsorboilario.verdebio.ScriviDomanda$6$4$2.run(ScriviDomanda.java:292)
I have not attempted to use insertImage(), and in this case, it is not quite clear why you would need it.
Primarily, it seems like you are looking to upload the photo. For that, all you need is the File that you created in createNewFile(). If you are uploading it yourself (e.g., HttpUrlConnection, some third-party library), you should be able to just use the File or an InputStream on it. Even if the upload code really needs a Uri, you can try Uri.fromFile() to get a Uri from your File and see if that works.
Where MediaStore does come into play is making your file be indexed and therefore accessible to apps (ones that query the MediaStore for images) and to users (via their MTP connection through their USB cable). MediaScannerConnection and its static scanFile() method are a fairly straightforward way to get the file indexed. Just make sure your file is fully written to disk first (e.g., if you are writing the file yourself, call getFD().sync() on your FileOutputStream after flush() and before close()).
Looks like MediaStore.Images.Media.insertImage(context.getContentResolver(), inImage, "Title", null); return null.
Form the documentation of MediaStore.Images.Media
Insert an image and create a thumbnail for it.
Parameters
cr The content resolver to use
source The stream to use for the image
title The name of the image
description The description of the image
Returns The URL to the newly created image, or null if the image
failed to be stored for any reason