How to convert a string to a URI without throwing exceptions - java

I had to convert a Uri to a string so that I could serialize that Uri.
Intent openFileIntent = new Intent(Intent.ACTION_GET_CONTENT);
openFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
openFileIntent.setType("audio/mpeg");
startActivityForResult(openFileIntent, PICK_MP3_FILE);
...then on activity result...
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_MP3_FILE)
{
if (resultCode == RESULT_OK)
{
try
{
if (data != null)
{
Uri mp3AudioFile;
if ((mp3AudioFile = data.getData()) != null)
{
myObject.setMp3Path(mp3AudioFile.getPath());
myObject.Save();
}
}
} catch (Exception e)
{
e.printStackTrace();
}
}
}
}
I closed the app and opened again. When I try to open that Uri with:
Uri uri = Uri.parse(myObject.getMp3Path();
I get an error:
java.lang.SecurityException: Permission Denial: reading com.android.providers.downloads.DownloadStorageProvider uri content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Faudio.mp3 from pid=601, uid=10107 requires that you obtain access using ACTION_OPEN_DOCUMENT or related APIs
My Manifest has the following permissions:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.STORAGE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />

We need to provide persistent Uri permission.
JAVA
Intent openFileIntent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
openFileIntent.addCategory(Intent.CATEGORY_OPENABLE);
openFileIntent.setType("audio/mpeg");
startActivityForResult(openFileIntent, PICK_MP3_FILE);
Also, a note worth mentioning is persistent permission is available only to Intent.ACTION_OPEN_DOCUMENT and NOT Intent.ACTION_GET_CONTENT whereas the latter one is like a one-time thing.

To do that I used getPath().
You should use toString() instead.
String scheme = uri.toString();
Uri uri = Uri.parse(scheme);

The permission denial issue needs to be dealt with the first time you receive a URI.
private val pickImage = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
// you will get result here in result.data
val uri = result.data?.data!!
requireActivity().contentResolver.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
// Do something else with the URI. E.g, save the URI as a string in the database
}
}

Related

Camera intent Android return null [duplicate]

This question already has answers here:
ACTION_IMAGE_CAPTURE returns imagefile as Extra instead of Data
(1 answer)
Why do I get null in data parmeter of onActivityResult
(1 answer)
Camera Intent Not Adding Extra
(1 answer)
Android "Taking Photos Simply" tutorial does not work for me [duplicate]
(1 answer)
Closed 2 months ago.
Start Intent Code :
Intent takePictureIntent = new Intent();
takePictureIntent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, imageUri);
takePictureIntent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE);
OnActivityResult Code :
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == UserVisitDetailActivity.RESULT_OK && data != null){
System.out.println("Masuk Camera");
Bitmap photo = (Bitmap) data.getExtras().get("data");
System.out.println(photo);
imageUri = getImageUri(getApplicationContext(), photo);
checkInHolder.setImageURI(imageUri);
}
}
Get Image URI Code :
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
The code run smoothly but after several modification, it suddenly return null data.
Thank you for your help
I have an code that working on SDK 32 successfully.
first of you need to setup manifest.xml
<manifest
....>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<queries>
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
</queries>
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera"
android:required="true" />
<application
android:requestLegacyExternalStorage="true"
....>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="#xml/provider_paths" />
</provider>
</application>
</manifest>
need to create provider_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
</paths>
setup java code.
// create global variable
private File photoFile = null;
//create methods...
private void chooseFromCamera(int requestCode) {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
try {
photoFile = createImageFile();
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, requestCode);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private File createImageFile() throws IOException {
long timeStamp = Calendar.getInstance().getTimeInMillis();
String imageFileName = "JPEG_" + timeStamp + "_";
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
File image = File.createTempFile(
imageFileName, /* prefix */
".jpg", /* suffix */
storageDir /* directory */
);
return image;
}
start intent for capture image.
chooseFromCamera(REQUEST_IMAGE_CAPTURE);
get bitmap...
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK && data != null){
if (photoFile != null) {
bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
}
}
}

Storage Permission Issue In android 10+ devices

i am trying to create a video player ,So I am trying to add the videos to the list
Storage permission is required to fetch the videos, so I took the permission with the below code.
But playstore was reject My app for this MANAGE EXTERNAL STORAGE permission.
But without this permission, I can't get storage permission on Android 10+ device.
To change the name of the video, delete the video and download the video permission is required , so please help me , please tell me how to get storage permission (/storage/Media/Videos , /storage/Download/)
My storage permission code :-
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
android:requestLegacyExternalStorage="true"
Main activity code :-
private boolean checkPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
return Environment.isExternalStorageManager();
} else {
int result = ContextCompat.checkSelfPermission(PermissionActivity.this, READ_EXTERNAL_STORAGE);
int result1 = ContextCompat.checkSelfPermission(PermissionActivity.this, WRITE_EXTERNAL_STORAGE);
return result == PackageManager.PERMISSION_GRANTED && result1 == PackageManager.PERMISSION_GRANTED;
}
}
private void requestPermission() {
if (SDK_INT >= Build.VERSION_CODES.R) {
try {
Intent intent = new Intent(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, 2296);
} catch (Exception e) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
startActivityForResult(intent, 2296);
}
} else {
//below android 11
ActivityCompat.requestPermissions(PermissionActivity.this, new String[]{WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE);
}
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2296) {
if (SDK_INT >= Build.VERSION_CODES.R) {
if (Environment.isExternalStorageManager()) {
// perform action when allow permission success
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
}
}
}
#Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
switch (requestCode) {
case PERMISSION_REQUEST_CODE:
if (grantResults.length > 0) {
boolean READ_EXTERNAL_STORAGE = grantResults[0] == PackageManager.PERMISSION_GRANTED;
boolean WRITE_EXTERNAL_STORAGE = grantResults[1] == PackageManager.PERMISSION_GRANTED;
if (READ_EXTERNAL_STORAGE && WRITE_EXTERNAL_STORAGE) {
// perform action when allow permission success
} else {
Toast.makeText(this, "Allow permission for storage access!", Toast.LENGTH_SHORT).show();
}
}
break;
}
}
So please tell me how to take storage permission in Android10+ Devices and also below Android 10 devices with out using MANAGE EXTERNAL STORAGE permission , Please Help Me
Permissions have changed in Android 10+:
External storage access scoped to app files and media
By default, apps targeting Android 10 and higher are given scoped access into external storage, or scoped storage. Such apps can see the following types of files within an external storage device without needing to request any storage-related user permissions [..]
Source: Privacy changes in Android 10
On devices that run Android 10 or higher, you don't need any storage-related permissions to access and modify media files that your app owns, including files in the MediaStore.Downloads collection
Source: Storage Permissions
If you have
android:requestLegacyExternalStorage="true"
in application tag in manifest file then you are done for an Android Q/10 device.
It will behave as it behaved on before 10.
I do not understand why you would have any problem on Android 10.
On Android 11+ you should be able to see media files in the usual public directories.

How to get the mobile number of my device programmatically?

I have tried using 2 methods for retrieving my phone number but both of them don't work. I used:
TelephonyManager
SubscriptionManager
I do get Network name, Country iso, and IMEI but whenever I try to return Number it returns nothing.
I have also added all the required permissions for these! My manifest looks like:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
Code using TelephonyManager:
TelephonyManager phoneMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
phoneMgr.getLine1Number()
Code using SubscriptionManager:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
List<SubscriptionInfo> subscription = SubscriptionManager.from(getApplicationContext()).getActiveSubscriptionInfoList();
for (int i = 0; i < subscription.size(); i++) {
SubscriptionInfo info = subscription.get(i);
Log.e("TAG", "number " + info.getNumber());
Log.e("TAG", "network name : " + info.getCarrierName());
Log.e("TAG", "country iso " + info.getCountryIso());
}
}
In both attempts I get nothing!
Is there any other way to get phone number or I'm doing something wrong?
Nowadays the TelephonyManager does not help us. Play Services API without permission is good solution for this.
This dependency is useful for this
implementation 'com.google.android.gms:play-services-auth:16.0.1'
Now inside your Activity.java:
GoogleApiClient mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(Auth.CREDENTIALS_API)
.build();
if (mGoogleApiClient != null) {
mGoogleApiClient.connect();
}
After this do request for Phone Number:
HintRequest hintRequest = new HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build();
PendingIntent intent = Auth.CredentialsApi.getHintPickerIntent(mGoogleApiClient, hintRequest);
try {
startIntentSenderForResult(intent.getIntentSender(), 1008, null, 0, 0, 0, null);
} catch (IntentSender.SendIntentException e) {
Log.e("", "Could not start hint picker Intent", e);
}
Now you need to handle response in your onActivityResult like this:
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case 1008:
if (resultCode == RESULT_OK) {
Credential cred = data.getParcelableExtra(Credential.EXTRA_KEY);
// cred.getId====: ====+919*******
Log.e("cred.getId", cred.getId());
userMob = cred.getId();
} else {
// Sim Card not found!
Log.e("cred.getId", "1008 else");
return;
}
break;
}
}
I found #bhoomika's answer useful but now using GoogleApiClient is deprecated. So you can use CredentialsClient instead.
Below is the method I used to trigger the phone number hint dialog (this method is in a helper class).
public void requestPhoneNumberHint(Activity currentActivity) {
HintRequest hintRequest = new HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build();
CredentialsClient credentialsClient = Credentials.getClient(currentActivity);
PendingIntent intent = credentialsClient.getHintPickerIntent(hintRequest);
try {
uiListener.getCurrentActivity().startIntentSenderForResult(intent.getIntentSender(),
RESOLVE_PHONE_NUMBER_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
Below is my handling for the corresponding onActivityResult (my Activity code is in Kotlin)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if(requestCode == RESOLVE_PHONE_NUMBER_HINT){
if (resultCode == RESULT_OK) {
var credential : Credential? = data?.getParcelableExtra(Credential.EXTRA_KEY)
credential?.apply {
processPhoneNumber(id)
}
}
}
As mentioned in the below documentation, the result codes can be used to identify if there were no hints that were displayed or if the user did not chose any of the options.
public static final int ACTIVITY_RESULT_NO_HINTS_AVAILABLE
Activity result code indicating that there were no hints available.
Constant Value: 1002
public static final int ACTIVITY_RESULT_OTHER_ACCOUNT
Activity result code indicating that the user wishes to use a different account from what was presented in the credential or hint picker.
Constant Value: 1001
https://developers.google.com/android/reference/com/google/android/gms/auth/api/credentials/CredentialsApi#ACTIVITY_RESULT_NO_HINTS_AVAILABLE
By using below code you current device phone number & after selecting phone number onActivity result will be called.
Gradle :
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.0.0'
Setup Google API Client :
//set google api client for hint request
mGoogleApiClient = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.enableAutoManage(this, this)
.addApi(Auth.CREDENTIALS_API)
.build();
Get an available number :
public void getHintPhoneNumber() {
HintRequest hintRequest =
new HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build();
PendingIntent mIntent = Auth.CredentialsApi.getHintPickerIntent(mGoogleApiClient, hintRequest);
try {
startIntentSenderForResult(mIntent.getIntentSender(), RESOLVE_HINT, null, 0, 0, 0);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
Get Selected Number in onActivityResult :
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//Result if we want hint number
if (requestCode == RESOLVE_HINT) {
if (resultCode == Activity.RESULT_OK) {
Credential credential = data.getParcelableExtra(Credential.EXTRA_KEY);
// credential.getId(); <-- will need to process phone number string
inputMobileNumber.setText(credential.getId());
}
}
}
Reference : https://androidwave.com/automatic-sms-verification-android/
Have you given access to READ_PHONE_STATE permission?
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
getLine1Number() should do the trick, but depending on the SIM-card this will not always be able to get the phone number
I suggest that if you do not get the number from getLine1Number(), then make the user type it in manually. (This is what iOS users have to do anyway)
EDIT:
Also, you should not use IMEI as of Android 10 you will not have permission to get that information

Unable to display result of camera activity in ImageView

Basically what I'm trying to do is create a simple app that uses the default camera app to take a picture, then I want to display that image in a new activity within an ImageView, but everything I've tried has resulted in
java.io.FileNotFoundException: /storage/emulated/0/imageToProcess.jpg: open failed: ENOENT (No such file or directory)
I've included the correct permissions (maybe even too many) in the manifest:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
and I'm also manually requesting permissions if need be in the main activity:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if(checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
}
if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
}
if(checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 1);
}
}
so I don't think the issue is with read/write permissions.
In my main activity's xml file, I've created a button with an onClick listener that calls the following method:
public void openCamera(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File f = new File(Environment.getExternalStorageDirectory() + File.separator + "imageToProcess.jpg");
imgUri = Uri.fromFile(f);
intent.putExtra("imgUri", imgUri.toString());
startActivityForResult(intent, TAKE_PICTURE);
}
Here's the onActivityResult() method I defined to create a new intent and pass the uri to the new activity:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(requestCode == TAKE_PICTURE && resultCode == Activity.RESULT_OK) {
Intent camResult = new Intent(this, ShowCameraResult.class);
camResult.putExtra("imgUri", imgUri.toString());
startActivity(camResult);
}
}
NOTE: imgUri and TAKE_PICTURE are defined at the top of the class as protected static final int TAKE_PICTURE = 1; and private Uri imgUri;
Lastly, here is my ShowCameraResult activity
public class ShowCameraResult extends AppCompatActivity {
private Bitmap mImageBitmap;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_show_camera_result);
ImageView imageView = (ImageView)findViewById(R.id.imageView);
String filePath = getIntent().getStringExtra("imgUri");
Log.d("ShowCameraResult", "directory: " + filePath);
try {
mImageBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), Uri.parse(filePath));
imageView.setImageBitmap(mImageBitmap);
} catch (IOException e) {
e.printStackTrace();
}
}
}
The Log.d method call above returns
ShowCameraResult: directory: file:///storage/emulated/0/imageToProcess.jpg
This leads me to believe that the image result from the camera isn't actually being saved into my imageToProcess.jpg file, but I could be very wrong as this is the first real android project I've worked on.
So my question is: Where did I go wrong?
Any help is greatly appreciated, thank you!
ITs returning a file, not a content resolver uri. Just decode the file with BitmapFactory.

FileNotFoundException: open failed: EACCES (Permission denied)

In emulator (i use genymotion) it works fine, but when I run it on a real device (my phone is ASUS ZenFone Laser 5.0) throws a filenotfoundexception
java.io.FileNotFoundException: /storage/emulated/0/cam20160926_075819.jpg: open failed: EACCES (Permission denied)
imgBitmap = MediaStore.Images.Media.getBitmap(cr, selectedImage);
here's the method onActivityResult()
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode){
case CAMERA_REQUEST:
if (resultCode == Activity.RESULT_OK){
Uri selectedImage = imageUri;
getActivity().getContentResolver().notifyChange(selectedImage, null);
ContentResolver cr = getActivity().getContentResolver();
Bitmap imgBitmap;
try {
imgBitmap = MediaStore.Images.Media.getBitmap(cr, selectedImage);
accountPhoto.setImageBitmap(imgBitmap);
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(getActivity().getApplicationContext(), "Something went wrong while taking a photo", Toast.LENGTH_LONG).show();
Log.e("Camera", e.toString());
}
}
}
}
i read some related questions and solutions about this EACCES, and it seems the problem is on my permission:
<uses-feature android:name="android.hardware.camera2" android:required="true"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="18"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
am I missing something? thanks for responding
you have to request permission before you start your instructions because this permission is considered dangerous in Marshmallow:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)
{
requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, RESULT);
}
else
{
//your code
}
I suspect WRITE_EXTERNAL_STORAGE overrides the READ_EXTERNAL_STORAGE read permission. If you look into the documentation you'll see that the former also permits reading from storage.
Try and remove the android:maxSdkVersion attribute and see if that works. I suspect that your device runs an SDK version > 18.
Check out this answer for more info: https://stackoverflow.com/a/15270626/425238

Categories

Resources