I tried doing some application so I borrowed one from GitHub. When I click the "TAKE A PHOTO" button, it says that the application is not responding. I think the problem has something to do with requesting permission with camera. I upgraded targetSdkVersion from 22 to 28 and now it is not working. Can anyone help me.
Here's the selectimageactivity.java:
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.TextView;
import com.microsoft.projectoxford.face.samples.R;
import java.io.File;
import java.io.IOException;
// The activity for the user to select a image and to detect faces in the image.
public class SelectImageActivity extends AppCompatActivity {
// Flag to indicate the request of the next task to be performed
private static final int REQUEST_TAKE_PHOTO = 0;
private static final int REQUEST_SELECT_IMAGE_IN_ALBUM = 1;
// The URI of photo taken with camera
private Uri mUriPhotoTaken;
// When the activity is created, set all the member variables to initial state.
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_image);
}
// Save the activity state when it's going to stop.
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putParcelable("ImageUri", mUriPhotoTaken);
}
// Recover the saved state when the activity is recreated.
@Override
protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
mUriPhotoTaken = savedInstanceState.getParcelable("ImageUri");
}
// Deal with the result of selection of the photos and faces.
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode)
{
case REQUEST_TAKE_PHOTO:
case REQUEST_SELECT_IMAGE_IN_ALBUM:
if (resultCode == RESULT_OK) {
Uri imageUri;
if (data == null || data.getData() == null) {
imageUri = mUriPhotoTaken;
} else {
imageUri = data.getData();
}
Intent intent = new Intent();
intent.setData(imageUri);
setResult(RESULT_OK, intent);
finish();
}
break;
default:
break;
}
}
// When the button of "Take a Photo with Camera" is pressed.
public void takePhoto(View view) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if(intent.resolveActivity(getPackageManager()) != null) {
// Save the photo taken to a temporary file.
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
try {
File file = File.createTempFile("IMG_", ".jpg", storageDir);
mUriPhotoTaken = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, mUriPhotoTaken);
startActivityForResult(intent, REQUEST_TAKE_PHOTO);
} catch (IOException e) {
setInfo(e.getMessage());
}
}
}
// When the button of "Select a Photo in Album" is pressed.
public void selectImageInAlbum(View view) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
if (intent.resolveActivity(getPackageManager()) != null) {
startActivityForResult(intent, REQUEST_SELECT_IMAGE_IN_ALBUM);
}
}
// Set the information panel on screen.
private void setInfo(String info) {
TextView textView = (TextView) findViewById(R.id.info);
textView.setText(info);
}
}
And then the build.gradle(Module):
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.microsoft.projectoxford.faceapisample"
minSdkVersion 22
targetSdkVersion 28
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// Include local lib mostly for debug purpose.
// implementation project(':lib')
// Use the following line to include client library for Face API from Maven Central Repository
implementation 'com.microsoft.projectoxford:face:1.4.4'
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
implementation "com.android.support:design:28.0.0"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
This is the error I get at logcat. enter image description here
From your logcat, you are getting FileUriExposedExceptiom You need to create FileProvider and use the same.
Reason being for apps targeting Android 7.0 (API level 24) and higher, passing a file://URI across a package boundary causes a FileUriExposedException.
Here's for more info and how to take-photo and use FileProvider
https://developer.android.com/training/camera/photobasics
https://developer.android.com/reference/androidx/core/content/FileProvider
First, you must declare this FileProvider in your AndroidManifest.xml file within the tag:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
...>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.myapp.fileprovider"
android:grantUriPermissions="true"
android:exported="false">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
...
</application>
</manifest>
Next, create a resource directory called xml and create a fileprovider.xml. Assuming you wish to grant access to the application's specific external storage directory, which requires requesting no additional permissions, you can declare this line as follows:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<!-- See table below. The external-files-path DOES NOT require external storage permissions. -->
<external-files-path
name="images"
path="Pictures" />
<!--Uncomment below to share the entire application specific directory -->
<!--<external-path name="all_dirs" path="."/>-->
</paths>
Finally, you will convert the File object into a content provider using the FileProvider class:
// getExternalFilesDir() + "/Pictures" should match the declaration in fileprovider.xml paths
File file = new File(getExternalFilesDir(Environment.DIRECTORY_PICTURES), "share_image_" + System.currentTimeMillis() + ".png");
// wrap File object into a content provider. NOTE: authority here should match authority in manifest declaration
bmpUri = FileProvider.getUriForFile(MyActivity.this, "com.example.myapp.fileprovider", file);