I am creating a Intent chooser to choose between a the phone camera app and the gallery/file manager.
Intent chooserIntent = Intent.createChooser(clickPhoto(),"Set Image Using");
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS,openGallery());
startActivityForResult.launch(chooserIntent);
Click Photo method:
private Intent clickPhoto() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
ComponentName componentName = takePictureIntent.resolveActivity(requireActivity().getPackageManager());
if (componentName != null) {
try {
createImageFile();
mimeType = "image/*";
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DISPLAY_NAME, getNewFileName());
values.put(MediaStore.Images.Media.MIME_TYPE, mimeType);
values.put(MediaStore.Images.Media.RELATIVE_PATH, getImageDirectoryPath());
Uri imageUri = requireActivity().getContentResolver().insert(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), values);
if (imageUri != null) {
currentPhotoPath = imageUri.toString();
shareUri = imageUri;
}
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
// initRequestCode(takePictureIntent, requestCode);
} catch (IOException ioException) {
Toast.makeText(requireContext(), ioException.getMessage().toString(), Toast.LENGTH_LONG).show();
}
}
return takePictureIntent;
}
Open gallery method:
private Intent openGallery(){
mimeType = "image/*";
Intent intent = new Intent();
Uri collection = MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL);
try {
intent =
new Intent(Intent.ACTION_PICK, collection).setType(mimeType);
intent.resolveActivity(requireActivity().getPackageManager());
// initRequestCode(intent, requestCode);
} catch (ActivityNotFoundException e) {
Toast.makeText(requireContext(), e.getLocalizedMessage(), Toast.LENGTH_LONG).show();
}
return intent;
}
The ActivityResultLauncher:
ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
//how to tell which intent the user selected ?
}
});
how do I know if the user took a piture using the camera or picked an image with the file picker ?
You can put an extra integer to each intent before returning them which you can access in result, say:
Global variables
final String SOURCE = "source";
final int SOURCE_CAMERA = 0;
final int SOURCE_GALLERY = 1;
final int SOURCE_UNKNOWN = 2;
For camera
...
takePictureIntent.putExtra(SOURCE, SOURCE_CAMERA);
return takePictureIntent;
For gallery
..
intent.putExtra(SOURCE, SOURCE_GALLERY);
return intent;
ActivityResultLauncher
if (result.getResultCode() == Activity.RESULT_OK) {
//Identify source
int mySource = result.getData().getIntExtra(SOURCE, SOURCE_UNKNOWN )
}
You can differentiate like this,
If one method is for camera intent,
private fun openCamera() {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (takePictureIntent.resolveActivity(packageManager) != null) {
cameraImageFile = getTempFile()
cameraImageFile?.let {
val imageUri = FileProvider.getUriForFile(
this,
"${BuildConfig.APPLICATION_ID}.fileprovider",
it
)
cameraLauncher.launch(imageUri)
}
}
}
and another method is for gallery intent
private fun openGallery() {
galleryLauncher.launch("image/*")
}
Then you can define them like below in activity,
//Todo for gallery
private val galleryLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) {
//code here for gallery
}
//Todo for camera
private val cameraLauncher = registerForActivityResult(ActivityResultContracts.TakePicture()) {
//code here for camera
}
That's it!
Declare some variables
companion object{
private const val CAMERA_ACTION =1
private const val GALLERY_ACTION =2
private const val CHOOSER_INTENT_ACTION =3
}
private var mActionTriggered =0
then follow
private fun openCamera() {
mActionTriggered = CAMERA_ACTION
}
private fun openGallery() {
mActionTriggered =GALLERY_ACTION
}
private fun openChooser() {
mActionTriggered =CHOOSER_INTENT_ACTION
}
onResult
private val startActivityForResult = registerForActivityResult(
StartActivityForResult()
) { result: ActivityResult ->
if (result.resultCode == RESULT_OK) {
when (mActionTriggered) {
CAMERA_ACTION -> {
mActionTriggered = 0
//TODO your logics
}
GALLERY_ACTION -> {
mActionTriggered = 0
//TODO your logics
}
else -> {
mActionTriggered = 0
//TODO your logics
}
}
}else{
mActionTriggered = 0
}
}
It feels a little overkill, but you can use the refinement mechanism of the chooser activity.
You need to implement the refinement activity yourself, but you can use the EXTRA_RESULT_RECEIVER that the chooser passes along to send back the result.
Intent refinementIntent = new Intent(this, RefinementActivity.class);
PendingIntent refinementPendingIntent = PendingIntent.getActivity(this, 0, refinementIntent, 0);
Intent clickPhotoIntent = clickPhoto();
Intent chooserIntent = Intent.createChooser(clickPhoto(),"Set Image Using");
chooserIntent.putExtra(
Intent.EXTRA_CHOOSER_REFINEMENT_INTENT_SENDER, refinementPendingIntent.getIntentSender());
chooserIntent.putExtra(Intent.EXTRA_RESULT_RECEIVER, new ResultReceiver() {
#Override
public void onReceive(int resultCode, Bundle resultData) {
Intent startedIntent = resultData.getParcelable("extra_selected_intent");
// Check which intent was selected.
// Note that this is called when the selection happened, before the
// started activity returned. Probably what you want to do here is
// cache the value in a field and then check it when you get
// the activity result.
}
});
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, openGallery());
startActivityForResult.launch(chooserIntent);
And then in RefinementActivity.java, you will need to send the selected intent back to the sender
#Override
public void onCreate(Bundle savedInstanceState) {
Intent selectedIntent = getIntent().getParcelableExtra(Intent.EXTRA_INTENT);
ResultReceiver receiver = getIntent().getParcelableExtra(Intent.EXTRA_RESULT_RECEIVER);
Bundle resultData = new Bundle();
resultData.putParcelable("extra_selected_intent", selectedIntent);
receiver.send(RESULT_OK, resultData);
startActivity(selectedIntent.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT));
finish();
}
You can initialize Global Boolean value name isGallery and set it true in openGallery() and false in clickPhoto()
Like the code below:
private boolean isGallery ;
private Intent clickPhoto() {
isGallery = false;
}
private Intent openGallery() {
isGallery = true;
}
Now your ActivityResultLauncher will be like this:
ActivityResultLauncher<Intent> startActivityForResult =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
if (isGallery) {
// user picked an image with the file picker
} else {
// user took a picture using the camera
}
}
});
Related
i'm trying to capture image in android 11 device but request is keep cancelled. i have added also. still unable to capture image. pick image from gallery is working. image is not storing in Android/data folder.
i have added val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION) also still unable to create temp file in storage. please provide any solutions
private fun selectImage() {
imageUtils.createImageFile(applicationContext).let {
viewModel.setFileTempPath(it.absolutePath, "doc_name")
startActivityForResult(imageUtils.captureImage(applicationContext, it), 300)
}
override fun onActivityResult(
requestCode: Int,
resultCode: Int,
data: Intent?
) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
300 -> when (resultCode) {
RESULT_OK -> {
Log.d("tmppath", data?.data.toString())
if (data != null && data.data != null) {
val selectedImage: Bitmap =
imageUtils.getBitmap(data.data, this#TaggingActivity)!!
viewModel.dataModel.selectedImagesArrayList.value.let {
if (it == null) {
viewModel.dataModel.selectedImagesArrayList.value = ArrayList()
}
val a = it
a?.add(
ImageDetailsToUpload(
"",
selectedImage,
Constant.CUSTOMER_GEO_TAG,
viewModel.dataModel.documentName.value,
viewModel.commonModel.currentLocation.value!!
)
)
viewModel.dataModel.selectedImagesArrayList.postValue(a)
}
} else {
if (viewModel.dataModel.tmpPath.value != null) {
imageUtils.getBitmapFromPath(viewModel.dataModel.tmpPath.value)
?.let { selectedImage ->
val a = viewModel.dataModel.selectedImagesArrayList.value
a?.add(
ImageDetailsToUpload(
"",
selectedImage,
Constant.CUSTOMER_GEO_TAG,
viewModel.dataModel.documentName.value,
viewModel.commonModel.currentLocation.value!!
)
)
viewModel.dataModel.selectedImagesArrayList.postValue(a)
} ?: run {
viewModel.commonModel.showToastTextView("Sorry Try Again..!")
}
} else {
viewModel.commonModel.showToastTextView("Sorry Try Again..!")
return
}
}
viewModel.dataModel.tmpPath.value = null
}
RESULT_CANCELED -> {
viewModel.setFileTempPath("", "")
Toast.makeText(this,"cancelled",Toast.LENGTH_LONG).show()
}
}
}
//Intent class
fun getCameraIntent(file: File): Intent {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(file))
if (Build.VERSION.SDK_INT >= 24) {
try {
val m =
StrictMode::class.java.getMethod("disableDeathOnFileUriExposure")
m.invoke(null)
} catch (e: java.lang.Exception) {
e.printStackTrace()
}
} else {
takePictureIntent.putExtra("return-data", true)
takePictureIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}
val pickPhoto = Intent(
Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
)
val intents: ArrayList<Intent> = arrayListOf()
intents.add(takePictureIntent)
intents.add(pickPhoto)
val chooserIntent = Intent.createChooser(
intents.removeAt(intents.size - 1),
" Document Upload"
)
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(arrayOf<Parcelable>()))
return chooserIntent
}
I'm developing an notepad app, and i need to reload the notes on the view when the Note Editor is closed (i'm using Finish() to close the Editor), but I am not sure how to wait until the Activity closes and does something.
I'm starting the Editor Activity with this:
public async void noteClicked(object sender, EventArgs e)
{
var obj = (RelativeLayout)sender;
var id = obj.Id;
var note = Util.db.Query<Note>(string.Format("SELECT * FROM Notes WHERE ID={0}", id));
var intent = new Intent(this, typeof(EditorAcitivity));
intent.PutExtra("Note", JsonConvert.SerializeObject(note));
intent.PutExtra("Mode", "Edit");
StartActivity(intent);
}
On the EditorActivity.cs:
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.editor_activity);
Util.context = this;
mode = Intent.GetStringExtra("Mode");
txtTitle = FindViewById<EditText>(Resource.Id.editorTitle);
txtText = FindViewById<EditText>(Resource.Id.editorText);
if (mode == "Edit")
{
note = JsonConvert.DeserializeObject<Note>(Intent.GetStringExtra("Note"));
txtTitle.Text = note.title;
txtText.Text = note.text;
}
FindViewById<ImageButton>(Resource.Id.editorDelete).Click += editorDelete_Clicked;
FindViewById<ImageButton>(Resource.Id.editorSave).Click += editorSave_Clicked;
}
private void editorSave_Clicked(object sender, EventArgs e)
{
if (txtText.Text.Length == 0 || string.IsNullOrWhiteSpace(txtText.Text))
{
Util.makeShortText("Null text");
}
else
{
var note = new Note();
note.date = Util.now();
note.text = txtText.Text;
if (string.IsNullOrWhiteSpace(txtTitle.Text))
{
note.title = " ";
}
else {
note.title = txtTitle.Text;
}
Util.db.Insert(note);
this.Finish();
}
}
I want to do something like loadNotes() when the Activity is finished (this.Finish())
Edit: I don't wanna return some data, just wait the activity.
I would suggest you to use StartActivityForResult
var intent = new Intent(this, typeof(EditorAcitivity));
intent.PutExtra("Note", JsonConvert.SerializeObject(note));
intent.PutExtra("Mode", "Edit");
StartActivityForResult(intent,REQUEST_CODE_EDITOR_ACITIVTY);
In that case REQUEST_CODE_EDITOR_ACITIVTY is a integer constant.
And then when your about to finish your activity call to the SetResult method as below
Util.db.Insert(note);
SetResult(Result.Ok);
this.Finish();
And finally override the OnActivityResult method in the same activity you're starting the EditorAcitivity as below
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_EDITOR_ACITIVTY) {
if(resultCode == Result.Ok) {
//Here your activity received the callback and you can call the load notes method
loadNotes();
}
}
}
Take a look at this tutorial if you want to learn more about Activity for result
https://subscription.packtpub.com/book/application_development/9781784398576/8/ch08lvl1sec84/obtaining-data-from-activities
I need help with Kotlin. I need to capture and save an image in my media store.
My code:
class MainActivity : AppCompatActivity() {
var ListadeProductos = ArrayList<Notas>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
camera.setOnClickListener {
val intentCamera = Intent("android.media.action.IMAGE_CAPTURE")
startActivity(intentCamera)
}
}
}
I think maybe the next code can help you half way. Just capture the image from camera and display it in an ImageView.
I used it (found in Creating camera intent app using Kotlin on android - Displaying thumbnail).
val CAMERA_REQUEST_CODE = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {
val callCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if (callCameraIntent.resolveActivity(packageManager) != null) {
startActivityForResult(callCameraIntent, CAMERA_REQUEST_CODE)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(requestCode) {
CAMERA_REQUEST_CODE -> {
if (resultCode == Activity.RESULT_OK && data != null) {
imageView.setImageBitmap(data.extras.get("data") as Bitmap)
}
}
else -> {
Toast.makeText(this, "Unrecognized request code", Toast.LENGTH_SHORT)
}
}
}
The simplest code is to, open the native camera app to take a picture and handle result in the OnActivityResult method, as shown in the article Capture Picture with Camera in Kotlin – Android.
val REQUEST_CODE = 200
fun capturePhoto() {
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE && data != null){
imageView.setImageBitmap(data.extras.get("data") as Bitmap)
}
}
That's it.
This blog explains how take picture from camera and show in an imagview in android/kotlin -- very simple
Complete code for pick image and crop it
Step 1: Add this gradle
implementation 'com.theartofdev.edmodo:android-image-cropper:1.2.1'
Step 2: Add two activities in your package and in manifest
<activity android:name=".ui.activities.CropImageActivity"
android:label="Crop Image"></activity>
<activity android:name=".ui.activities.ImagePickerActivity"
android:label="Pick Image"></activity>
CropImageActivity class
public class CropImageActivity extends AppCompatActivity implements CropImageView.OnSetImageUriCompleteListener, CropImageView.OnGetCroppedImageCompleteListener {
private static final int DEFAULT_ASPECT_RATIO_VALUES = 100;
public static final String CROPPED_IMAGE_PATH = "cropped_image_path";
public static final String EXTRA_IMAGE_URI = "cropped_image_path";
public static final String FIXED_ASPECT_RATIO = "extra_fixed_aspect_ratio";
public static final String EXTRA_ASPECT_RATIO_X = "extra_aspect_ratio_x";
public static final String EXTRA_ASPECT_RATIO_Y = "extra_aspect_ratio_y";
private static final String ASPECT_RATIO_X = "ASPECT_RATIO_X";
private static final String ASPECT_RATIO_Y = "ASPECT_RATIO_Y";
private CropImageView mCropImageView;
private int mAspectRatioX = DEFAULT_ASPECT_RATIO_VALUES;
private int mAspectRatioY = DEFAULT_ASPECT_RATIO_VALUES;
private boolean isFixedAspectRatio = false;
Bitmap croppedImage;
//endregion
private TextView tv_cancel, tv_crop;
// Saves the state upon rotating the screen/restarting the activity
#Override
protected void onSaveInstanceState(#SuppressWarnings("NullableProblems") Bundle bundle) {
super.onSaveInstanceState(bundle);
bundle.putInt(ASPECT_RATIO_X, mAspectRatioX);
bundle.putInt(ASPECT_RATIO_Y, mAspectRatioY);
}
// Restores the state upon rotating the screen/restarting the activity
#Override
protected void onRestoreInstanceState(#SuppressWarnings("NullableProblems") Bundle bundle) {
super.onRestoreInstanceState(bundle);
mAspectRatioX = bundle.getInt(ASPECT_RATIO_X);
mAspectRatioY = bundle.getInt(ASPECT_RATIO_Y);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_crop_image);
tv_cancel = (TextView)findViewById(R.id.tv_cancel);
tv_crop = (TextView)findViewById(R.id.tv_crop);
if (!getIntent().hasExtra(EXTRA_IMAGE_URI)) {
cropFailed();
return;
}
isFixedAspectRatio = getIntent().getBooleanExtra(FIXED_ASPECT_RATIO, false);
mAspectRatioX = getIntent().getIntExtra(EXTRA_ASPECT_RATIO_X, DEFAULT_ASPECT_RATIO_VALUES);
mAspectRatioY = getIntent().getIntExtra(EXTRA_ASPECT_RATIO_Y, DEFAULT_ASPECT_RATIO_VALUES);
Uri imageUri = Uri.parse(getIntent().getStringExtra(EXTRA_IMAGE_URI));
// Initialize components of the app
mCropImageView = (CropImageView) findViewById(R.id.CropImageView);
// If you want to fix the aspect ratio, set it to 'true'
mCropImageView.setFixedAspectRatio(isFixedAspectRatio);
if (savedInstanceState == null) {
mCropImageView.setImageUriAsync(imageUri);
}
tv_cancel.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cropFailed();
}
});
tv_crop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCropImageView.getCroppedImageAsync(mCropImageView.getCropShape(), 0, 0);
}
});
}
private void cropFailed() {
Toast.makeText(mCropImageView.getContext(), "Image crop failed", Toast.LENGTH_LONG).show();
setResult(RESULT_CANCELED);
finish();
}
#Override
protected void onStart() {
super.onStart();
mCropImageView.setOnSetImageUriCompleteListener(this);
mCropImageView.setOnGetCroppedImageCompleteListener(this);
}
#Override
protected void onStop() {
super.onStop();
mCropImageView.setOnSetImageUriCompleteListener(null);
mCropImageView.setOnGetCroppedImageCompleteListener(null);
}
#Override
public void onSetImageUriComplete(CropImageView view, Uri uri, Exception error) {
if (error == null) {
//Toast.makeText(mCropImageView.getContext(), "Image load successful", Toast.LENGTH_SHORT).show();
}
else {
//Toast.makeText(mCropImageView.getContext(), "Image load failed: " + error.getMessage(), Toast.LENGTH_LONG).show();
Toast.makeText(mCropImageView.getContext(), "Unable to load image", Toast.LENGTH_LONG).show();
}
}
#Override
public void onGetCroppedImageComplete(CropImageView view, Bitmap bitmap, Exception error) {
if (error == null) {
croppedImage = bitmap;
try {
String path = saveToInternalStorage(this, bitmap);
Intent resultIntent = new Intent();
resultIntent.putExtra(CROPPED_IMAGE_PATH, path);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
catch (IOException e) {
e.printStackTrace();
cropFailed();
}
}
else {
cropFailed();
}
}
private String saveToInternalStorage(Context context, Bitmap bitmapImage) throws IOException {
ContextWrapper cw = new ContextWrapper(context);
// Path to /data/data/yourapp/app_data/imageDir
File directory = cw.getDir("imageDir", Context.MODE_PRIVATE);
// Create imageDir
File mypath = new File(directory, "image.jpg");
FileOutputStream fos = null;
try {
fos = new FileOutputStream(mypath);
// Use the compress method on the BitMap object to write image to the OutputStream
//Bitmap scaledBitmap = getCompressedBitmap(bitmapImage);
bitmapImage.compress(Bitmap.CompressFormat.PNG, 70, fos);
}
catch (Exception e) {
e.printStackTrace();
}
finally {
fos.close();
}
return directory.getAbsolutePath();
}
}
ImagePickerActivity class
public class ImagePickerActivity extends AppCompatActivity {
private static final int REQUEST_PICK_IMAGE = 2365;
private static final int REQUEST_CROP_IMAGE = 2342;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startActivityForResult(getPickImageChooserIntent(), REQUEST_PICK_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
if(requestCode == REQUEST_PICK_IMAGE) {
Intent intent = new Intent(this, CropImageActivity.class);
Uri imageUri = getPickImageResultUri(data);
intent.putExtra(CropImageActivity.EXTRA_IMAGE_URI, imageUri.toString());
startActivityForResult(intent, REQUEST_CROP_IMAGE);
}
else
if(requestCode == REQUEST_CROP_IMAGE) {
System.out.println("Image crop success:" + data.getStringExtra(CropImageActivity.CROPPED_IMAGE_PATH));
String imagePath = new File(data.getStringExtra(CropImageActivity.CROPPED_IMAGE_PATH), "image.jpg").getAbsolutePath();
Intent result = new Intent();
result.putExtra("image_path", imagePath);
setResult(Activity.RESULT_OK, result);
finish();
}
}
else {
System.out.println("Image crop failed");
setResult(Activity.RESULT_CANCELED);
finish();
}
}
/**
* Create a chooser intent to select the source to get image from.<br/>
* The source can be camera's (ACTION_IMAGE_CAPTURE) or gallery's (ACTION_GET_CONTENT).<br/>
* All possible sources are added to the intent chooser.
*/
public Intent getPickImageChooserIntent() {
// Determine URI of camera image to save.
Uri outputFileUri = getCaptureImageOutputUri();
List<Intent> allIntents = new ArrayList<>();
PackageManager packageManager = getPackageManager();
// Collect all camera intents
Intent captureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);
for (ResolveInfo res : listCam) {
Intent intent = new Intent(captureIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
if (outputFileUri != null) {
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
}
allIntents.add(intent);
}
// Collect all gallery intents
Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);
galleryIntent.setType("image/*");
List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);
for (ResolveInfo res : listGallery) {
Intent intent = new Intent(galleryIntent);
intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));
intent.setPackage(res.activityInfo.packageName);
allIntents.add(intent);
}
// The main intent is the last in the list, so pickup the useless one
Intent mainIntent = allIntents.get(allIntents.size() - 1);
for (Intent intent : allIntents) {
if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) {
mainIntent = intent;
break;
}
}
allIntents.remove(mainIntent);
// Create a chooser from the main intent
Intent chooserIntent = Intent.createChooser(mainIntent, "Select source");
// Add all other intents
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));
return chooserIntent;
}
/**
* Get URI to image received from capture by camera.
*/
private Uri getCaptureImageOutputUri() {
Uri outputFileUri = null;
File getImage = getExternalCacheDir();
if (getImage != null) {
outputFileUri = Uri.fromFile(new File(getImage.getPath(), "pickImageResult.jpeg"));
}
return outputFileUri;
}
/**
* Get the URI of the selected image from {#link #getPickImageChooserIntent()}.<br/>
* Will return the correct URI for camera and gallery image.
*
* #param data the returned data of the activity result
*/
public Uri getPickImageResultUri(Intent data) {
boolean isCamera = true;
if (data != null) {
String action = data.getAction();
isCamera = action != null && action.equals(MediaStore.ACTION_IMAGE_CAPTURE);
}
return isCamera ? getCaptureImageOutputUri() : data.getData();
}
}
activity_crop_image.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:id="#+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:background="#color/colorblue"
android:padding="15dp">
<TextView
android:id="#+id/tv_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="10dp"
android:text="Cancel"
android:textColor="#color/colorwhite"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:id="#+id/tv_crop"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="#+id/tv_title"
android:layout_centerVertical="true"
android:layout_marginRight="10dp"
android:text="Crop"
android:textColor="#color/colorwhite"
android:textSize="18sp"
android:textStyle="bold" />
</RelativeLayout>
<com.theartofdev.edmodo.cropper.CropImageView
android:id="#+id/CropImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/header"
android:layout_gravity="center"
app:cropFixAspectRatio="true" />
</RelativeLayout>
Step 3: Usage in fragment or activity class
private val REQUEST_PICK_IMAGE = 1002
profile_pic1.setOnClickListener {
startActivityForResult(Intent(activity, ImagePickerActivity::class.java), REQUEST_PICK_IMAGE)
}
fun setImage(imagePath: String) {
profile_pic1.setImageBitmap(getImageFromStorage(imagePath));
}
fun getImageFromStorage(path: String): Bitmap {
var f = File(path);
var options = BitmapFactory.Options();
options.inJustDecodeBounds = false;
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, 512, 512);
return BitmapFactory.decodeStream(FileInputStream(f), null, options)
}
private fun calculateInSampleSize(
options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
// Raw height and width of image
val height = options.outHeight
val width = options.outWidth
var inSampleSize = 1
if (height > reqHeight || width > reqWidth) {
val halfHeight = height / 2
val halfWidth = width / 2
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while (halfHeight / inSampleSize > reqHeight && halfWidth / inSampleSize > reqWidth) {
inSampleSize *= 2
}
}
return inSampleSize
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK && requestCode == requestCode) {
var imagePath = data!!.getStringExtra("image_path");
setImage(imagePath);
}
else {
System.out.println("Failed to load image");
}
}
NOTE: declare write/read and camera permission in the manifest and
runtime permissions as well
I need to stub the camera intent by creating a image file at the path provided in the intent extra.
Espresso can only respond with activityresult. Where can i perform the operation to create the file at passed path from intent extra.
Code for launching camera
File destination = new File(Environment.getExternalStorageDirectory(), "app_name" + System.currentTimeMillis() + ".jpg");
imageUri = FileProvider.getUriForFile(getApplicationContext(), getApplicationContext().getPackageName() + ".fileprovider", destination);
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri);
startActivityForResult(intent, AppConstants.REQUEST_CODE_CAMERA);
Code for stubbing intent in test
Instrumentation.ActivityResult result = new Instrumentation.ActivityResult(Activity.RESULT_OK, null);
intending(hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(result);
Ismael answer is perfect. For those looking for solution in java, Here it is.
intending(hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(
new Instrumentation.ActivityResult(Activity.RESULT_OK, null));
IntentCallback intentCallback = new IntentCallback() {
#Override
public void onIntentSent(Intent intent) {
if (intent.getAction().equals("android.media.action.IMAGE_CAPTURE")) {
try {
Uri imageUri = intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
Context context = InstrumentationRegistry.getTargetContext();
Bitmap icon = BitmapFactory.decodeResource(
context.getResources(),
R.mipmap.ic_launcher);
OutputStream out = getTargetContext().getContentResolver().openOutputStream(imageUri);
icon.compress(Bitmap.CompressFormat.JPEG, 100, out);
out.flush();
out.close();
} catch (IOException e) {
GenericUtility.handleException(e);
}
}
}
};
IntentMonitorRegistry.getInstance().addIntentCallback(intentCallback);
//Perform action here
onView(withId(R.id.tv_take_photo)).perform(click());
You need to create a IntentCallback to intercept the Uri value and save a sample image there.
Sample in Kotlin
intentCallback = IntentCallback {
if (it.action == "android.media.action.IMAGE_CAPTURE") {
it.extras.getParcelable<Uri>("output").run {
val inStream = Resources.getResource(sampleImageFileName).openStream()
val outStream = activity.contentResolver.openOutputStream(this)
ByteStreams.copy(inStream, outStream)
}
}
}
You need to register your callback before the intent trigger event
IntentMonitorRegistry.getInstance().addIntentCallback(intentCallback)
And don't to forget to unregister at end
IntentMonitorRegistry.getInstance().removeIntentCallback(intentCallback)
Ismael and Gupta's answers are correct. For those who want a complete example, I made a complete solution based on their example in Kotlin. The code below takes photo for multiple imageView and also verifies if the correct image is loaded in the respective imageview by checking the imageView.tag property. From the development code, the image name has to be set in the imageView.setTag(imageName)
private var imageName = "No Image Name"
#Test
fun verifyPhotoTaken() {
intending(hasAction(MediaStore.ACTION_IMAGE_CAPTURE)).respondWith(
ActivityResult(Activity.RESULT_OK, null))
takePhoto(R.id.imageview1, R.drawable.ic_launcher)
takePhoto(R.id.imageview2, R.drawable.some_image)
}
private fun takePhoto(imageViewId : Int, resourceId : Int) {
val cameraIntentCallback = intentCallback(resourceId)
IntentMonitorRegistry.getInstance().addIntentCallback(cameraIntentCallback)
onView(withId(imageViewId)).perform(click())
onView(withId(imageViewId)).check(matches(hasDrawable(imageName)))
IntentMonitorRegistry.getInstance().removeIntentCallback(cameraIntentCallback)
}
private fun intentCallback(resourceId : Int = R.drawable.ic_launcher) :IntentCallback {
return IntentCallback {
if (it.action == MediaStore.ACTION_IMAGE_CAPTURE) {
it.extras?.getParcelable<Uri>(MediaStore.EXTRA_OUTPUT).run {
imageName = File(it.getParcelableExtra<Parcelable>(MediaStore.EXTRA_OUTPUT).toString()).name
val context : Context = InstrumentationRegistry.getInstrumentation().targetContext
val outStream = context.contentResolver.openOutputStream(this)
val bitmap : Bitmap = BitmapFactory.decodeResource(context.resources, resourceId)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outStream)
}
}
}
}
fun hasDrawable(drawableResource: String) : BoundedMatcher<View, ImageView> {
return object : BoundedMatcher<View, ImageView> (ImageView::class.java) {
override fun describeTo(description: Description?) {
description?.appendText("has drawable")
}
override fun matchesSafely(item: ImageView?): Boolean {
return item?.drawable != null && item.tag.toString().contains(drawableResource)
}
}
}
It even can't make a folder on the sdcard. When the camera takes the photo, it doesn't respond when I press the 'OK' Button. What's wrong with my code?
public static final String MACCHA_PATH = Environment.getExternalStorageDirectory().getPath() + "/Twigit";
public static final String PHOTO_PATH = MACCHA_PATH + "/camera.jpg";
public static boolean takePhoto(Activity activity) {
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File fileDir = new File(MACCHA_PATH);
boolean isSuccessful = true;
if (!fileDir.exists()) {
isSuccessful = fileDir.mkdir();
}
if(!isSuccessful) {
return false;
} else {
File file = new File(PHOTO_PATH);
Uri outputFileUri = Uri.fromFile(file);
intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);
activity.startActivityForResult(intent, TAKEPHOTO);
return true;
}
}
do you have this? You need to override the onActivityResult. which will be called before onResume when you use startActivityForResult. The requestCode will be the code you used to start the photo taking activity. In your case it would be TAKEPHOTO..
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == TAKEPHOTO) {
if (resultCode == RESULT_OK) {
//Pic taken
} else {
//Pic not taken
}
}
}
EDIT:
take a look at this link
http://achorniy.wordpress.com/2010/04/26/howto-launch-android-camera-using-intents/