我希望实现以下功能:
1. 从 MyApp 中通过一个
在我的 MainActivity 中,我使用布尔变量
- 将照片文件保存到
相机应用程序可以成功将照片文件保存到 ExternalFilesDir,但无法将文件保存到其公共目录中。由于这是在相机应用程序内发生的,因此我无法进行调试。
我的问题如下:
- 是否可能让相机应用程序保存到公共目录 DCIM? - 如果是,怎样做? - 如何使我的照片在图库应用程序中可见?
(我的函数
我正在使用:
- AndroidStudio 4.0.1 - SDK平台 Android 10.0+(R), API 30 - 我的测试设备具有
1. 从 MyApp 中通过一个
intent
启动手机的相机应用程序
2. 手机的相机应用程序将照片保存在公共目录中 (DCIM 或 DCIM/Camera)
3. 保存的照片使用我选择的文件名。
4. 保存的照片在图库应用程序中可用
5. 相机应用程序返回焦点到 MyApp 后,我的应用程序编辑 Exif。在我的 MainActivity 中,我使用布尔变量
USE_ANDROID_EXTERNAL_STORAGE_PUBLIC_DIRECTORY
在以下两个选项之间进行切换:- 将照片文件保存到
ExternalFilesDir
(在我的情况下:/storage/emulated/0/Android/data/pub.openbook.labellor/files/Pictures)
- 将照片文件保存到Public Directory
(在我的情况下为 /storage/emulated/0/DCIM)。相机应用程序可以成功将照片文件保存到 ExternalFilesDir,但无法将文件保存到其公共目录中。由于这是在相机应用程序内发生的,因此我无法进行调试。
我的问题如下:
- 是否可能让相机应用程序保存到公共目录 DCIM? - 如果是,怎样做? - 如何使我的照片在图库应用程序中可见?
(我的函数
galleryAddPic()
可以正常完成但未达到目的。照片仍然在图库应用程序中不可见。)我正在使用:
- AndroidStudio 4.0.1 - SDK平台 Android 10.0+(R), API 30 - 我的测试设备具有
android.os.Build.VERSION.SDK_INT
23package pub.openbook.labellor;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.util.Log;
import android.widget.LinearLayout;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import static android.os.Environment.getExternalStoragePublicDirectory;
public class MainActivity extends AppCompatActivity {
static final int REQUEST_IMAGE_CAPTURE = 1;
static final int REQUEST_TAKE_PHOTO = 1;
static final boolean USE_ANDROID_EXTERNAL_STORAGE_PUBLIC_DIRECTORY = true;
private static final String IMAGES_FOLDER_NAME = "Camera";
String stPathToJpgFile;
View mainCoordinatorLayout;
private static final String logTag = MainActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// initialize layout:
setContentView(R.layout.activity_main);
// initialize variables:
mainCoordinatorLayout = (View) findViewById(R.id.main_coordinator_layout);
Toolbar toolbar = findViewById(R.id.toolbar);
FloatingActionButton fab = findViewById(R.id.fab);
// initialize layout & and components:
setSupportActionBar(toolbar);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dispatchTakePictureIntent(view);
}
});
LinearLayout checkboxContainer = (LinearLayout) findViewById(R.id.checkbox_container);
CheckBox cb = new CheckBox(this);
cb.setText("Tutlane");
cb.setChecked(true);
checkboxContainer.addView(cb);
cb = new CheckBox(this);
cb.setText("Another");
cb.setChecked(false);
checkboxContainer.addView(cb);
cb = new CheckBox(this);
cb.setText("Label threee");
cb.setChecked(false);
checkboxContainer.addView(cb);
Log.d(logTag, "============ android.os.Build.VERSION.SDK_INT " + android.os.Build.VERSION.SDK_INT + "=====================");
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(logTag, "onActivityResult() back from take picture intent;");
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK) {
Log.d(logTag, "onActivityResult() photo resides at"+stPathToJpgFile);
galleryAddPic(stPathToJpgFile);
ImageView imageView = (ImageView) findViewById(R.id.thumbnail_view);
Context mContext;
mContext = (Context)this;
Bitmap d = new BitmapDrawable(mContext.getResources() , stPathToJpgFile).getBitmap();
if (null != d) {
int nh = (int) ( d.getHeight() * (512.0 / d.getWidth()) );
Bitmap scaled = Bitmap.createScaledBitmap(d, 512, nh, true);
imageView.setImageBitmap(scaled);
}
}
}
/*
Use resident Camera App to take picture and save (filename has labels)
*/
private void dispatchTakePictureIntent(View view) {
// take picture with resident camera app:
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
// Ensure that there's a camera activity to handle the intent
if (takePictureIntent.resolveActivity(getPackageManager()) != null) {
// Create the File where the photo should go
File photoFile = null;
try {
photoFile = jpgFile();
} catch (IOException ex) {
// Error occurred while creating the File
Log.e(logTag, "jpgFile() throws IOException");
}
Log.d(logTag, "dispatchTakePictureIntent() photoFile = "+photoFile );
// Continue only if the File was successfully created
if (photoFile != null) {
Uri photoURI = FileProvider.getUriForFile(this,
BuildConfig.APPLICATION_ID + ".provider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoURI);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
/*
*/
private File jpgFile() throws IOException {
// File object to be returned:
File jpgFile;
// Create an image file name with datestamp and labels:
String timeStamp = new SimpleDateFormat("yyMMdd").format(new Date());
String imageFileName = timeStamp + ".label1";
Log.d(logTag, "jpgFile() imageFileName = "+imageFileName );
File externalFilesDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
Log.d(logTag, "jpgFile() externalFilesDir = "+externalFilesDir );
// create the File object:
if (USE_ANDROID_EXTERNAL_STORAGE_PUBLIC_DIRECTORY) {
// Since getExternalStoragePublicDirectory() has been deprecated in Build.VERSION_CODES.Q and higher:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
Log.d(logTag, "jpgFile() Build.VERSION_CODES.Q or higher");
// get the Activity Context:
Context mContext;
mContext = (Context)this;
ContentResolver resolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, imageFileName);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
contentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/" + IMAGES_FOLDER_NAME);
Uri imageUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
jpgFile = new File(imageUri.getPath());
} else {
Log.d(logTag, "jpgFile() lower than Build.VERSION_CODES.Q");
String stStorageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_DCIM).toString() + File.separator + IMAGES_FOLDER_NAME;
// make sure the directory string points to a directory that exists:
if (!new File(stStorageDir).exists()) { new File(stStorageDir).mkdir(); }
jpgFile = new File(stStorageDir, imageFileName + ".jpg");
}
} else {
//write photos to directory private to this app:
File storageDir = getExternalFilesDir(Environment.DIRECTORY_PICTURES);
jpgFile = new File(storageDir, imageFileName + ".jpg");
}
// Save a file: path for use with ACTION_VIEW intents
stPathToJpgFile = jpgFile.getAbsolutePath();
return jpgFile;
}
/*
Invoke the system's media scanner to add your photo to the Media Provider's database,
making it available in the Android Gallery application and to other apps.
*/
private void galleryAddPic (String stPathToPicFile) {
Log.d(logTag, "galleryAddPic() stPathToPicFile "+stPathToPicFile);
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(stPathToPicFile);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
}
public Uri addImageToGallery(ContentResolver cr, String imgType, File filepath) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.TITLE, "player");
values.put(MediaStore.Images.Media.DISPLAY_NAME, "player");
values.put(MediaStore.Images.Media.DESCRIPTION, "");
values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imgType);
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
values.put(MediaStore.Images.Media.DATA, filepath.toString());
return cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
}
}