I am working on a Chatting application.I has successfully send text as a message to receiver, now i want to send image as a message either by capturing or selecting from the gallery.
I had gone through some of approaches like ACTION_SEND of Intent class. But find hard to implement it. I Had made separate class for those things which has to be send or receive.
public class ChatMessage {
private String messagetext;
private String messageuser;
private long messagetime;
ImageView iv;
public ChatMessage(String messagetext, String messageuser) {
this.messagetext = messagetext;
this.messageuser = messageuser;
messagetime= new Date().getTime();
}
public ChatMessage() {
}
public String getMessagetext() {
return messagetext;
}
public void setMessagetext(String messagetext) {
this.messagetext = messagetext;
}
public String getMessageuser() {
return messageuser;
}
public void setMessageuser(String messageuser) {
this.messageuser = messageuser;
}
public long getMessagetime() {
return messagetime;
}
public void setMessagetime(long messagetime) {
this.messagetime = messagetime;
}
}
and i populate these via following method:
private void displayChatMessage(){
final ListView listofmessage= (ListView)findViewById(R.id.list_of_message);
adapter=new FirebaseListAdapter<ChatMessage>(this,ChatMessage.class,R.layout.list_item,FirebaseDatabase.getInstance().getReference()) {
#Override
protected void populateView(View v, ChatMessage model, int position) {
TextView messagetext,messaggeuser,messagetime;
messagetext=(TextView)v.findViewById(R.id.message_text);
messaggeuser=(TextView)v.findViewById(R.id.message_user);
messagetime=(TextView)v.findViewById(R.id.message_time);
messagetext.setText(model.getMessagetext());
messaggeuser.setText(model.getMessageuser());
messagetime.setText(DateFormat.format("dd-mm-yyyy (HH:mm:ss)",model.getMessagetime()));
}
};
listofmessage.setAdapter(adapter);
}
so, please suggest some approaches. Thanks.
First of all, you need to create a custom dialog or pop-up window to make the user choose whether he wants to capture an image with the camera or he want to select one from the gallery, Then you need to dispatch the right intent depend on what he will choose so if he chooses to capture and image from the gallery this will be your intent
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), yourRequestCode);
Your request code is simply an int you can distinguish with later when a result comes that it was the response for this intent action.
if the user chooses to snap a picture with the camera this is how your intent will be like
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
intent.putExtra(MediaStore.EXTRA_OUTPUT, selectedImageUri);
startActivityForResult(intent, antherRequestCode);
then after he successfully grab a picture from the gallery or snap one with the camera onActivityResult method will be invoked with the returned image, and there where you should handle what you are going to do with that image so first you ovride the method
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK ){
switch (requestCode) {
case GALLERY_INTENT_REQUEST_CODE:
Uri imageUri = data.getData();
Log.e("ImageUri", imageUri != null ? imageUri.toString() : "Empty Uri");
break;
case TAKE_IMAGE_INTENT_REQUEST_CODE:
Bundle extras = data.getExtras();
Bitmap imageBitmap = (Bitmap) extras.get("data");
Log.e("ImageUri", extras != null ? imageBitmap.toString() : "no Bitmap found");
break;
}
}
}
So as you can see from the code above the gallery intent returns the image Uri and the camera intent return a bitmap and now that you have the image you can encoded to base64 or turn it to a byte array or adding it to a file and send it to the desired reciever.
Related
when I open the gallery and go to dropbox or one drive I get a message unable to get path but when I go to google photos or local, I get the right image to load in a grid.
DependencyService.Get<IMediaService>().OpenGallery();
MessagingCenter.Unsubscribe<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelectedAndroid");
MessagingCenter.Subscribe<App, List<string>>((App)Xamarin.Forms.Application.Current, "ImagesSelectedAndroid", (s, images) =>
{
if (images.Count > 0)
{
Console.WriteLine($"Processed {images.Count} images");
UploadToBlob(images);
GetGallery();
}
public void OpenGallery()
{
try
{
var imageIntent = new Intent(Intent.ActionPick);
imageIntent.SetType("image/*");
imageIntent.PutExtra(Intent.ExtraAllowMultiple, true);
imageIntent.SetAction(Intent.ActionGetContent);
((Activity)CrossCurrentActivity.Current.Activity).StartActivityForResult(Intent.CreateChooser(imageIntent, "Select photo"), Opengallerycode);
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Tap and hold to select multiple photos.", ToastLength.Short)?.Show();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Toast.MakeText(CrossCurrentActivity.Current.Activity, "Error. Can not continue, try again.", ToastLength.Long)?.Show();
}
}
You could get the image into stream from dropbox or one drive and load in a grid.
Create the interface: IPhotoPickerService.cs
public interface IPhotoPickerService
{
Task<Stream> GetImageStreamAsync();
}
Android implementation:
MainActivity.cs
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
internal static MainActivity Instance { get; private set; }
... ...
// Field, property, and method for Picture Picker
public static readonly int PickImageId = 1000;
public TaskCompletionSource<Stream> PickImageTaskCompletionSource { set; get; }
protected override void OnActivityResult(int requestCode, Result resultCode, Intent intent)
{
base.OnActivityResult(requestCode, resultCode, intent);
if (requestCode == PickImageId)
{
if ((resultCode == Result.Ok) && (intent != null))
{
Android.Net.Uri uri = intent.Data;
Stream stream = ContentResolver.OpenInputStream(uri);
// Set the Stream as the completion of the Task
PickImageTaskCompletionSource.SetResult(stream);
}
else
{
PickImageTaskCompletionSource.SetResult(null);
}
}
}
}
PhotoPickerService.cs
public class PhotoPickerService : IPhotoPickerService
{
public Task<Stream> GetImageStreamAsync()
{
// Define the Intent for getting images
Intent intent = new Intent();
intent.SetType("image/*");
intent.SetAction(Intent.ActionGetContent);
// Start the picture-picker activity (resumes in MainActivity.cs)
MainActivity.Instance.StartActivityForResult(
Intent.CreateChooser(intent, "Select Photo"),
MainActivity.PickImageId);
// Save the TaskCompletionSource object as a MainActivity property
MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Stream>();
// Return Task object
return MainActivity.Instance.PickImageTaskCompletionSource.Task;
}
}
For more information about IOS, UWP implementation of photo picker, you could check the MS article. https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/dependency-service/photo-picker
And download the source file from link. https://learn.microsoft.com/zh-cn/samples/xamarin/xamarin-forms-samples/dependencyservice/
I am facing a problem where in when I am trying to crop an image after it has picked from Gallery or Camera.
When I choose the image from gallery it gets cropped correctly without any problem. When I choose image from camera, the cropping is done properly but it shows me an "intermediate" screen as seen below without taking me directly to the crop screen.
Note: Picture above is just for representation purposes to show the "intermediate" Recent screen.
I don't want this "intermediate" Recent screen to be displayed. Instead I want to directly navigate to the crop intent. In apps like Whatsapp this behavior is not seen when someone changes his/her profile pic. It directly navigates to crop intent without showing "intermediate" screen.
Can someone help solve this problem?
Here is my complete code
/**
* This activity is used to display profile picture and update the same
*
*/
public class ChangeProfilePhotoActivity extends BaseActivity implements
View.OnClickListener {
private TextView mTvTitle;
private ImageView mBtnChangePhoto;
private ImageView mIvProfileImage;
public static final int CROP_PIC_REQUEST_CODE = 3;
public static final int TAKE_PICTURE = 1;
public static final int GALLERY_IMAGE = 2;
public static final int IMAGE_CHOOSER_INTENT = 4;
int PERMISSION_ALL = 10;
String[] PERMISSIONS = { Manifest.permission.CAMERA};
//private Uri mImageUri;
//private Uri mCropImageUri;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_profile_photo);
initUI();
}
#Override
protected void onResume() {
super.onResume();
}
#Override
protected void onPause() {
super.onPause();
}
#Override
protected void onDestroy() {
super.onDestroy();
}
private void initUI() {
mBtnChangePhoto = (ImageView) findViewById(R.id.btnChangePhoto);
mIvProfileImage = (ImageView) findViewById(R.id.profile_image);
mBtnChangePhoto.setOnClickListener(this);
}
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnChangePhoto:
//launch intent chooser
getPickImageIntent(this);
break;
default:
break;
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
try {
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case IMAGE_CHOOSER_INTENT:
if(data!=null){
String action = data.getAction();
Uri selectedImageUri = data.getData();
//send image for cropping
doCrop(selectedImageUri);
}
break;
case CROP_PIC_REQUEST_CODE:
if(data!=null){
Bundle extras = data.getExtras();
if(extras != null) {
Bitmap bmp = (Bitmap) extras.get("data");
mIvProfileImage.setImageBitmap(bmp);
}
}
break;
default:
break;
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
private void doCrop(Uri picUri) {
try {
Intent cropIntent = new Intent("com.android.camera.action.CROP");
cropIntent.setDataAndType(picUri, "image/*");
cropIntent.putExtra("crop", "true");
cropIntent.putExtra("aspectX", 1);
cropIntent.putExtra("aspectY", 1);
cropIntent.putExtra("outputX", 128);
cropIntent.putExtra("outputY", 128);
cropIntent.putExtra("return-data", true);
startActivityForResult(cropIntent, CROP_PIC_REQUEST_CODE);
}
// respond to users whose devices do not support the crop action
catch (ActivityNotFoundException anfe) {
// display an error message
String errorMessage = "Your device doesn't support the crop action!";
Toast toast = Toast.makeText(this, errorMessage, Toast.LENGTH_SHORT);
toast.show();
}
}
public void getPickImageIntent(Context context) {
Intent chooserIntent = null;
List<Intent> intentList = new ArrayList<>();
Intent pickIntent = new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
//startActivityForResult(pickIntent, GALLERY_IMAGE);
Intent takePhotoIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
/* String imageFilePath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/crop_image.jpg";
File imageFile = new File(imageFilePath);
Uri picUri = Uri.fromFile(imageFile); // convert path to Uri
takePhotoIntent.putExtra( MediaStore.EXTRA_OUTPUT, picUri );*/
//takePhotoIntent.putExtra("return-data", false);
//startActivityForResult(takePhotoIntent, TAKE_PICTURE);
intentList = addIntentsToList(context, intentList, pickIntent);
intentList = addIntentsToList(context, intentList, takePhotoIntent);
if (intentList.size() > 0) {
chooserIntent = Intent.createChooser(intentList.remove(intentList.size() - 1),
context.getString(R.string.pick_image_intent_text));
chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intentList.toArray(new Parcelable[intentList.size()]));
}
startActivityForResult(chooserIntent, IMAGE_CHOOSER_INTENT);
}
private static List<Intent> addIntentsToList(Context context, List<Intent> list, Intent intent) {
try {
List<ResolveInfo> resInfo = context.getPackageManager().queryIntentActivities(intent, 0);
for (ResolveInfo resolveInfo : resInfo) {
String packageName = resolveInfo.activityInfo.packageName;
Intent targetedIntent = new Intent(intent);
targetedIntent.setPackage(packageName);
list.add(targetedIntent);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return list;
}
}
You're launching an intent. That means you're handing control off to another app. After that, you have no control over what happens. Of course what happens will be different on every device, as some OEMs will use their own Gallery app or Camera app that may behave completely differently.
So no, there's no way to prevent them from doing that extra screen. If you want total control, take the picture yourself via the camera or camera2 apis instead of calling an Intent. (Note: I don't actually suggest this, but if you want control its the only way).
I'm trying to send an image path from one activity to another. I'm catching the intent in onResume, but the string path is always null. I don't know what I'm doing wrong. Hopefully you guys can help me with this problem.
Here's my activity where I grab the image path and send an intent.
private Intent testImage = new Intent(this, MyActivity.class);
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.card_create_layout);
testImage = new Intent(this, MyActivity.class);
}
private void grabImage()
{
Intent imageGetter = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(imageGetter, RESULT_LOAD_IMAGE);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data)
{
Uri selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};//Array size of 1, and we put in a string
Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
user_image_path = cursor.getString(columnIndex);//here we have our image path.
cursor.close();
ImageView imageView = (ImageView) findViewById(R.id.imageView);
imageView.setImageBitmap(BitmapFactory.decodeFile(user_image_path));
}
testImage.putExtra("the_image", user_image_path);
}
#Override
public void onClick(View v)
{
switch (v.getId())
{
case R.id.theCreateButton:
grabImage();
break;
case R.id.theDesButton:
startActivity(sendInformation);
}
}
#Override
public void onBackPressed()
{
super.onBackPressed();
MyActivity.checkCard();
setResult(Activity.RESULT_OK, getIntent());
finish();
}
Now in my other activity, when I grab the image and press back
#Override
public void onResume()
{
super.onResume();
String ImagePath = getIntent().getStringExtra("the_image");
if(ImagePath == null)
{
Toast.makeText(this,"hello everyone",Toast.LENGTH_LONG).show();
}
}
It keeps on showing the toast message "hello everyone", which means ImagePath is continuously null. How do I fix this?
Pass mechanism between activities is available in three ways :
via DI(Dependency Injection)
via Bundle mechanism
via Singletone class which play a role a bridge or data holder between activities.
To avoid duplicating answer - please search any way(i recommend easiest - via Bundle) in stackoverflow.
Quick guide :
You put your string into bundle via intent.putExtra(String name, String value) in Activity A
Start this intent with startActivity(intent);
In B activity read value view getIntent().getStringExtra(String name) in OnCreate method.
name value is need the same in activity A and B. This is a key.
I don't see a
startActivity(testImage);
If you aren't using that intent to start the activity, then there is no extra called 'the_image' and the getStringExtra function will effectively return a null.
#Override
public void onBackPressed() {
Intent intent = new Intent();
intent.putExtra("the_image", user_image_path);
setResult(RESULT_OK, intent);
super.onBackPressed();
}
The above is how to correctly do it, if you have started an activity for result.
This question already has answers here:
Get/pick an image from Android's built-in Gallery app programmatically
(19 answers)
Closed 7 years ago.
Okay, so i'm very new to this android development.
I have a button. i want this button to open the pick image from... kinda activity so the user can pick image from system or different gallery apps he has or camera or web. like other apps who do so. I want that the image selected will get the image id and store it to a database, and display the image as the button. I will do the storing, but how do i get image ID? and all the other stuff? thanks alot for anyone who helps me! Cheers!
Add request code:
public class add_requests extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_requests);
}
Globals mThumbIds = Globals.getInstance();
public void onSaveClick(View view){
EditText desc = (EditText) findViewById(R.id.request_name);
EditText message = (EditText) findViewById(R.id.request_message);
String message1 = message.getText().toString();
String desc1 = desc.getText().toString();
Request r1 = new Request(R.drawable.iphone, message1,desc1);
mThumbIds.getData().add(r1);
finish();
}
public void browsePictures(){
Intent i = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.INTERNAL_CONTENT_URI);
}
}
Following is sample to pick and use picture from Gallery.
public void pickImage() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, PICK_PHOTO_FOR_AVATAR);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_PHOTO_FOR_AVATAR && resultCode == Activity.RESULT_OK) {
if (data == null) {
//Display an error
return;
}
InputStream inputStream = context.getContentResolver().openInputStream(data.getData());
//Now you can do whatever you want with your inpustream, save it as file, upload to a server, decode a bitmap...
}
}
I am trying to find the best way to implement a button in a MainActivity that launches the camera activity and returns the image to another activity. basically it returns the image to an activity to add a description to the image... what i thought would be a good idea is to start that single photo view activity when the camera button is pressed and from the new activity start the camera activity for result before doing anything else; but i have an intermittent issue that sometimes the camera gets stuck in a loop.
maybe there is a better approach? should i launch the camera activity for result first and then pass the image as an intent?
here is what i have now:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}else if ( id == R.id.menu_rules ){
Intent rulesIntent = new Intent(this, RulesActivity.class);
startActivity(rulesIntent);
return true;
}else if ( id == R.id.menu_import_photo ){
//pull in an image from the gallery
return true;
}else if ( id == R.id.menu_item_new_photo ){
startActivity(new Intent(MainActivity.this, SinglePhotoViewActivity.class));
}
return super.onOptionsItemSelected(item);
}
and the receiving activity..
public class SinglePhotoViewActivity extends Activity {
private static final String LOG_TAG = "Simple Camera App";
private static int TAKE_PICTURE = 1001;
private ImageView imageView;
private Uri imageUri;
private Bitmap bitmap;
private TextView textView;
private EditText editText;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_single_photo_view);
if ( bitmap == null )
takePhoto();
}
public void takePhoto(){
Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
File photo = new File(Environment
.getExternalStoragePublicDirectory(Environment
//this will continually overwrite the same file
//need to implement a date/ time string
//to save as file name.
.DIRECTORY_PICTURES), "pic.jpg");
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo));
imageUri = Uri.fromFile(photo);
startActivityForResult(intent, TAKE_PICTURE);
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case 1001:
if(resultCode == Activity.RESULT_OK) {
getContentResolver().notifyChange(imageUri, null);
imageView = (ImageView )findViewById(R.id.ivCameraImageView);
ContentResolver contentResolver = getContentResolver();
try {
bitmap = android.provider.MediaStore.Images.Media.getBitmap(contentResolver,
imageUri);
imageView.setImageBitmap(bitmap);
} catch(Exception e) {
Toast.makeText(SinglePhotoViewActivity.this, "failed to load",
Toast.LENGTH_LONG).show();
Log.e(LOG_TAG, e.toString());
}
}
}
}
}
Your situation is similar to what happens often when ACTION_IMAGE_CAPTURE intent is launched (see e.g. Android startCamera gives me null Intent and ... does it destroy my global variable?).
The cause is that the system may decide to destroy the caller activity (in your case, the SinglePhotoViewActivity), and recreate it again after the launched activity (in your case, system Camera activity) returns the result.
The ultimate fix involves implementing onSaveInstanceState(Bundle) in the calling activity. But in your specific situation, there is a shortcut. Check the intent in onCreate(), and if it comes from the MainActivity, then launch Camera. Else, proceed as if you are going to receive onActivityResult() right now.