有人告诉我,这可能是因为如果 targetSdkVersion >= Android 6.0(API 级别 23),开发人员需要在运行时添加一些代码来请求用户的相关权限。
“如果你还想实现‘打开相机/拍照’功能,你应该在运行时请求CAMERA的拍照权限和存储相关的图片保存权限。也许可以使用FileProvider来存储图片。”
如何在我的项目中实施这个建议?
这是我的 SelectImageActivity,其中 TAKEPICTURE 的代码涉及
package com.microsoft.projectoxford.face.samples.ui;
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);
}
}
这是我的构建 gradle (:app)
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.5'
implementation 'com.android.support.constraint:constraint-layout:2.0.4'
compile project(':voicetwo')
implementation project(':voicetwo')
}
我的错误日志:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.microsoft.projectoxford.faceapisample, PID: 16272
java.lang.IllegalStateException: Could not execute method for android:onClick
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:390)
at android.view.View.performClick(View.java:7167)
at android.view.View.performClickInternal(View.java:7140)
at android.view.View.access$3500(View.java:813)
at android.view.View$PerformClick.run(View.java:27597)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7519)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:7167)
at android.view.View.performClickInternal(View.java:7140)
at android.view.View.access$3500(View.java:813)
at android.view.View$PerformClick.run(View.java:27597)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7519)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)
Caused by: android.os.FileUriExposedException: file:///storage/emulated/0/Android/data/com.microsoft.projectoxford.faceapisample/files/Pictures/IMG_2029674407291738623.jpg exposed beyond app through ClipData.Item.getUri()
at android.os.StrictMode.onFileUriExposed(StrictMode.java:2089)
at android.net.Uri.checkFileUriExposed(Uri.java:2388)
at android.content.ClipData.prepareToLeaveProcess(ClipData.java:977)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10780)
at android.content.Intent.prepareToLeaveProcess(Intent.java:10765)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1710)
at android.app.Activity.startActivityForResult(Activity.java:5258)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:767)
at android.app.Activity.startActivityForResult(Activity.java:5216)
at android.support.v4.app.FragmentActivity.startActivityForResult(FragmentActivity.java:754)
at com.microsoft.projectoxford.face.samples.ui.SelectImageActivity.takePhoto(SelectImageActivity.java:103)
at java.lang.reflect.Method.invoke(Native Method)
at android.support.v7.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:7167)
at android.view.View.performClickInternal(View.java:7140)
at android.view.View.access$3500(View.java:813)
at android.view.View$PerformClick.run(View.java:27597)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:224)
at android.app.ActivityThread.main(ActivityThread.java:7519)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:539)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:995)
E/MQSEventManagerDelegate: failed to get MQSService.
D/OOMEventManagerFK: checkEventAndDumpForJE: 0
E/MQSEventManagerDelegate: failed to get MQSService.
com.microsoft.projectoxford.face.samples.ui.SelectImageActivity.takePhoto(SelectImageActivity.java:103) 错误日志中的行是
startActivityForResult(intent, REQUEST_TAKE_PHOTO);