B
Braesident
Ambitioniertes Mitglied
- 1
Hallo,
Ich habe 2 Apps die den selben Speichplatz nutzten. Unter storage/emulated/0 wurde ein Verzeichnis erstellt. In diesem für jeden Arbeitsvorgang ein Unterverzeichnis. App 1 hat Bilder in dieses Unterverzeichnis abgelegt und App 2 json Dateien. Mit den neueren Richtlinien von Google funktioniert das ja nicht mehr.
Jetzt würde ich gern App 2 den Speichervorgang beider Daten übernehmen lassen. Das Json File ist kein Problem... ab in den eigenen Speicher. Doch die Bilder bekomme ich dort einfach nicht hin. Ich benutze in App 1 CameraX um die Bilder aufzunehmen. Sowie ein File Provider in App 2. Doch beim speichern des Bildes bekomme ich immer die Meldung Failed to write temp file... was für mich auf fehlende Permission deutet. An der Stelle komm ich einfach nicht weiter. Vielleicht hat jemand von euch eine Idee warum das nicht funktioniert bzw. wie es funktionieren könnte. Habe ich das mit dem File Provider falsch verstanden ?
Beide Apps haben als minsdk 26 und target sowie compilesdkversion 33
getestet mit Emulator Android 11 und auf Gerät mit Android 10
Ich habe 2 Apps die den selben Speichplatz nutzten. Unter storage/emulated/0 wurde ein Verzeichnis erstellt. In diesem für jeden Arbeitsvorgang ein Unterverzeichnis. App 1 hat Bilder in dieses Unterverzeichnis abgelegt und App 2 json Dateien. Mit den neueren Richtlinien von Google funktioniert das ja nicht mehr.
Jetzt würde ich gern App 2 den Speichervorgang beider Daten übernehmen lassen. Das Json File ist kein Problem... ab in den eigenen Speicher. Doch die Bilder bekomme ich dort einfach nicht hin. Ich benutze in App 1 CameraX um die Bilder aufzunehmen. Sowie ein File Provider in App 2. Doch beim speichern des Bildes bekomme ich immer die Meldung Failed to write temp file... was für mich auf fehlende Permission deutet. An der Stelle komm ich einfach nicht weiter. Vielleicht hat jemand von euch eine Idee warum das nicht funktioniert bzw. wie es funktionieren könnte. Habe ich das mit dem File Provider falsch verstanden ?
Beide Apps haben als minsdk 26 und target sowie compilesdkversion 33
getestet mit Emulator Android 11 und auf Gerät mit Android 10
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.package.b">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
android:theme="@style/AppTheme">
<activity android:name=".App2"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<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>
XML:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path name="external_files" path="."/>
<external-files-path
name="external_files"
path="." />
<files-path
name="files"
path="." />
</paths>
Java:
public class App2 extends AppCompatActivity {
ActivityResultLauncher<Intent> cameraLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {}
}
);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = findViewById(R.id.button);
btn.setOnClickListener(view -> handleImagesDialog());
}
private void handleImagesDialog() {
File imgDir = new File(getFilesDir().getPath().concat("/JOB_ID/pictures"));
imgDir.mkdirs();
File[] imgs = imgDir.listFiles();
ImageButton btn = dialog.getWindow().findViewById(R.id.trigger);
btn.setOnClickListener(view -> {
Uri uri = FileProvider.getUriForFile(this, getApplicationContext().getPackageName() + ".provider", imgDir);
Intent cameraIntent = new Intent("my.package.a.intent.CAMERA");
cameraIntent.putExtra("path", imgDir.getPath());
cameraIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
cameraIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
cameraIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
cameraLauncher.launch(cameraIntent);
});
}
}
XML:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<application
android:name=".App1Application"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:requestLegacyExternalStorage="true"
tools:ignore="LockedOrientationActivity">
<activity
android:name=".ActivityCamera"
android:exported="true"
android:label="@string/title_activity_camera">
<intent-filter>
<action android:name="my.package.a.intent.CAMERA" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
</application>
</manifest>
Java:
public class ActivityCamera extends AppCompatActivity {
private ImageButton trigger;
private PreviewView previewView;
private String imageDefaultPath = "";
private String imageDestinationPath = "";
private Uri imageUri;
int facing = CameraSelector.LENS_FACING_BACK;
private SimpleDateFormat dateFormatTimestamp = new SimpleDateFormat("yyyyMMddHHmmss", Locale.getDefault());
private final ActivityResultLauncher<String> cameraPermissionResultLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(), new ActivityResultCallback<Boolean>() {
@Override
public void onActivityResult(Boolean result) {
startCamera(facing);
}
});
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
imageDefaultPath = getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath();
// imageDefaultPath = Environment.getExternalStorageDirectory().getPath().concat("/MyApp");
if (getIntent().hasExtra("path")) {
Bundle bundle = this.getIntent().getExtras();
imageDestinationPath = bundle.getString("path", getExternalFilesDir(Environment.DIRECTORY_PICTURES).getPath());
}
if (getIntent().hasExtra(MediaStore.EXTRA_OUTPUT)) {
Bundle bundle = this.getIntent().getExtras();
imageUri = (Uri) bundle.get(MediaStore.EXTRA_OUTPUT);
}
previewView = findViewById(R.id.preview);
trigger = findViewById(R.id.trigger);
if (ContextCompat.checkSelfPermission(ActivityCamera.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
cameraPermissionResultLauncher.launch(Manifest.permission.CAMERA);
} else {
startCamera(facing);
}
}
private void startCamera(int facing) {
int aspectRatio = aspectRatio(previewView.getWidth(), previewView.getHeight());
ListenableFuture listenableFuture = ProcessCameraProvider.getInstance(this);
listenableFuture.addListener(() -> {
try {
ProcessCameraProvider processCameraProvider = (ProcessCameraProvider) listenableFuture.get();
Preview preview = new Preview.Builder().setTargetAspectRatio(aspectRatio).build();
ImageCapture imageCapture = new ImageCapture.Builder()
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.setTargetRotation(getWindowManager().getDefaultDisplay().getRotation()).build();
CameraSelector cameraSelector = new CameraSelector.Builder().requireLensFacing(facing).build();
processCameraProvider.unbindAll();
Camera camera = processCameraProvider.bindToLifecycle(this, cameraSelector, preview, imageCapture);
trigger.setOnClickListener(view -> {
if (ContextCompat.checkSelfPermission(ActivityCamera.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
cameraPermissionResultLauncher.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE);
} else {
triggerPicture(imageCapture);
}
});
preview.setSurfaceProvider(previewView.getSurfaceProvider());
} catch (ExecutionException | InterruptedException e) {
throw new RuntimeException(e);
}
}, ContextCompat.getMainExecutor(this));
}
private void triggerPicture(ImageCapture imageCapture) {
String filename = dateFormatTimestamp.format(new Date()) + ".jpg";
Uri extendedUri = Uri.withAppendedPath(imageUri, filename);
final File file = new File("" + extendedUri);
Log.d("AC", "Take PICTURE TO: " + file.getPath());
// content:/my.package.b.provider/external_files/Documents/MyApp/202309062236/pictures/20230907224154.jpg
ImageCapture.OutputFileOptions options = new ImageCapture.OutputFileOptions.Builder(file).build();
imageCapture.takePicture(options, Executors.newCachedThreadPool(), new ImageCapture.OnImageSavedCallback() {
@Override
public void onImageSaved(@NonNull ImageCapture.OutputFileResults outputFileResults) {
Log.d("AC", getString(R.string.image_saved) + ": " + file.getPath());
startCamera(facing);
}
@Override
public void onError(@NonNull ImageCaptureException exception) {
Log.d("AC", getString(R.string.failed) + ": " + exception.getMessage());
exception.printStackTrace();
startCamera(facing);
}
});
}
private int aspectRatio(int width, int height) {
double previewRatio = (double) Math.max(width, height) / Math.min(width, height);
if (Math.abs(previewRatio - 4.0 / 3.0) <= Math.abs(previewRatio - 16.0 / 9.0)) {
return AspectRatio.RATIO_4_3;
}
return AspectRatio.RATIO_16_9;
}
}
Zuletzt bearbeitet:
Bearbeitet von:
Braesident
- Grund: Code angepasst