Customize "share picture via" menu on Android(安卓)(Android(安卓)Intent Filters)
http://eggie5.com/8-hook-share-picture-via-menu-android
You know in the android gallery when you view a picture there is the share menu that allows you to upload your picture to various services. It is the job of the app to handle the upload - for example on my phone (depending on the apps you have installed) facebook, picasa, blogger all have entries in that list. This article will describe the process to get your app in that list and post the picture over HTTP.
Basically there are 3 steps to get this working:
- Register your app w/ the android platform to show your app in the platform share menu. (see Intents)
- Get the image from the Album app using android APIs (see ContentResolver)
- Do actual HTTP post request
1. Add hook to AndroidManifest.xml
If you intend to get your app in the share menu you must register that intent (pun intended) w/ the andoid system. This is done via and intent-filter in the AndroidManifest.xml
file.
In order to use the internet to make and HTTP request we must also register that w/ Android via the use-permission directive in the manifest file. See below example:
<?xml version="1.0" encoding="utf-8"?>
2. Get image from Gallery
Getting an image from the camera isn't as straight forward as it seems. It's not just open the file at this path - you must use the ContentResolver/ContentProvider API in android - which the gallery app exposes. See code example:
public void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); Bundle extras = intent.getExtras(); String action = intent.getAction(); // if this is from the share menu if (Intent.ACTION_SEND.equals(action)) { if (extras.containsKey(Intent.EXTRA_STREAM)) { try { // Get resource path from intent callee Uri uri = (Uri) extras.getParcelable(Intent.EXTRA_STREAM); // Query gallery for camera picture via // Android ContentResolver interface ContentResolver cr = getContentResolver(); InputStream is = cr.openInputStream(uri); // Get binary bytes for encode byte[] data = getBytesFromFile(is); // base 64 encode for text transmission (HTTP) byte[] encoded_data = Base64.encodeBase64(data); String data_string = new String(encoded_data); // convert to string SendRequest(data_string); return; } catch (Exception e) { Log.e(this.getClass().getName(), e.toString()); } } else if (extras.containsKey(Intent.EXTRA_TEXT)) { return; } }}
First we get a path to the image (uri
) from the share menu of the gallery when we clicked on share. It's not however just a path to the image - it's a content uri
which is android platform specific way to refrence a resource. It looks somehting like this content://com.example.gallery/3
. With a URI you can then query gallery for the resource. The key here is getContentResolver()
method - it will get you a handle to android internal DRM system which the cameria/gallery exposes(uses). Then in order to sent the image over HTTP we must convert it to plaintext encoding (base64) from binary. We do this by gettings it's bits and converting to base64 string representation (details are beyond the scope of this article - see source for details).
3. HTTP Post Request
Rather than choose a high level library for the HTTP action I chose to implement it using sockets as an exercise (more fun - we can really see what's happening).
First we build the xml post body string. We then create the request and send it. Note: most people would do this using multipart/mime but I choose just to encode the image into the xml photo node.
private void SendRequest(String data_string){ try { String xmldata = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + "" + data_string + " via android - " + new Date().toString() + " "; // Create socket String hostname = "eggie5.com"; String path = "/photos"; int port = 80; InetAddress addr = InetAddress.getByName(hostname); Socket sock = new Socket(addr, port); // Send header BufferedWriter wr = new BufferedWriter(new OutputStreamWriter( sock.getOutputStream(), "UTF-8")); wr.write("POST " + path + " HTTP/1.1\r\n"); wr.write("Host: eggie5.com\r\n"); wr.write("Content-Length: " + xmldata.length() + "\r\n"); wr.write("Content-Type: text/xml; charset=\"utf-8\"\r\n"); wr.write("Accept: text/xml\r\n"); wr.write("\r\n"); // Send data wr.write(xmldata); wr.flush(); // Response BufferedReader rd = new BufferedReader(new InputStreamReader( sock.getInputStream())); String line; while ((line = rd.readLine()) != null) { Log.v(this.getClass().getName(), line); } } catch (Exception e) { Log.e(this.getClass().getName(), "Upload failed", e); }}
Then on the server side - I must decode the base64 stream back into binary which I did in ruby:
Base64.decode64(incoming_file)
See full source on github: https://github.com/eggie5/android-share-menu
Next Steps:
When the image is uploading the UI kinda locks up - the next step would be to have some type of progress bar like the facebook or picasa app does.
Also usually the images are way to big for the front page of this site (where they go) - should implement some type of resize on the phone. This would also make the upload faster.
ps
Uros Mesaric 3 comments collapsed Collapse ExpandTnx for code. Just what I needed.
- A Like
- Reply
glad i could help!
- A Like
- Reply
thanxxxxxx alot exactly the same thing i want.....
- A Like
- Reply
Added thread via AsyncTask for server call and progress dialog. Updated code available at my github fork:
https://github.com/sasykes/and...
- A Like
- Reply
finally code that works sending data to a server!!! thanks!! ibe been trying tens of examples and this is the first one successfull!!
- A Like
- Reply
GOOD
- A Like
- Reply
Thanks for the code. How if I want to resize the photo to any size(VGA, 1M...) on the phone before upload to server?
- A Like
- Reply
Hi all,
I found this link useful and yes,
thanks for this good example. In this example we get the URI
which gives the path for the resource in the gallery, that URI isn't the
path pointing towards the location of the resource(Image) in sdcard(If
it wer to have existed in sdcard). I would like to know how you the path
which gives the location for the resource. Please Help. Thanks in
advance.
- A Like
- Reply
Well the Gallery app "owns" the images and is implemented in such a way that you must use the ContentResolver API to get access to them. I suppose, of course, that there is a file path to them somewhere on the SD card, but those details aren't exposed.
- A Like
- Reply
Slightly off topic, but do you happen to know if you can start the "Share Via" activity from your own activity?
- A Like
- Reply
uh, not sure what you mean...
- A Like
- Reply
Hi Eggie5,
After an hour searching I found the answer here: - http://stackoverflow.com/quest... (2 mins after posting above :))I mean I would like to take a screenshot of my app, save it to the SD card then call the Share Via dialog (like you get when you take a pic on the camera and it allows you to send it to email / tweet / facebook etc.)Hope this helps,All the best,Ash
- A Like
- Reply
Are you programaticly want to invoke the share via dialog from your activity? How do you take a screenshot? I'm curious...
- A Like
- Reply
I suspect it's only possible to take a screenshot with an OpenGL app, but this is how: - http://stackoverflow.com/quest... HTH!
- A Like
- Reply
I used this code and I still cant get my app to show up inthe share menu on the emulator or the droid x after selecting some image ans clicking on share... it just goes right to an mms message... frustrating....
- A Like
- Reply
I think it is working for sharing 1 image but not multi
- A Like
- Reply
I designed it to only upload 1 photo at a time.
To upload multiple you might have to change something in the manifest file. If you figure it out, let me know.
- A Like
- Reply
The following settings I have in my AndroidManifest.xml will handle single and multiple share in the emulator.
This my oncreate method to access the multiple files. it just logs the uri
public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent intent = getIntent(); Bundle extras = intent.getExtras(); String action = intent.getAction(); // if this is from the share menu if (Intent.ACTION_SEND_MULTIPLE.equals(action)) { if (extras.containsKey(Intent.EXTRA_STREAM)) { ArrayList
- A Like
- Reply
cool thanks for the update - maybe I should add it to the code I posted...
- A Like
- Reply
cant we give the priority to ur intent filter in this case, so that when the menu is displayed by the android system, our application should be the first option
- A Like
- Reply
It just seems alphabetical on my phone.... I don't know any android settings to change the order...
- A Like
- Reply
hi there. can you show the server side? is it php?
- A Like
- Reply
Hi,
The server side can be anything - this particular site is running ruby. The server just needs to accept an xml post request with base64 encoded photo data in the
Here is a snippet of my ruby server code:
#decode binary data
@temp_file = Base64.decode64(incoming_file)
#save to disk
#FileUtils.mkdir_p(full_directory_name)
#File.open(full_filename, "wb") {|f| f.write(@temp_file.read)}
#or save to amazon s3
@s3 = Rightscale::S3.new(ENV['AMAZON_ACCESS_KEY_ID'], ENV['AMAZON_SECRET_ACCESS_KEY'])
b=@s3.bucket("#{my_bucket}#{Rails.env}")
b.put("#{photo_path}/#{self.id}", @temp_file, {}, "public-read-write")
- A Like
- Reply
Hm, eclipse is complaining about Base64, SendRequest and getBytesFromFile. Where can I import these from?
- A Like
- Reply
if you look at my github example project the library is included, https://github.com/eggie5/andr... or just search org.apache.commons.codec.binary.Base64 and get the jar off the internet and include it in whatever build system/IDE you use.
- A Like
- Reply
This very example is something I've been looking for. Is it possible for somebody to make a ready-complied version for me? This would be very useful for calling from App Inventor apps.
marius@evang.no
- A Like
- Reply
never used app inventor before... sorry...
- A Like
- Reply
Thanks for the code snipe
Oh my bad of course i messed up the xml.
and also i had to covert the uri to absolute path something.
Can i ask , when i press the post_to_eggie5 in the share menu , screen goes black with the text post_to_eggie5 at the top.
How do i disable that?
- A Like
- Reply
updated - if your logcat is still broke sounds like an issue w/ your eclipse/android sdk setup...
- A Like
- Reply
hi, actually I didn't finish this code yet - I got too busy w/ finals at school. I plan on finishing it this week - I'll let you know...
- A Like
- Reply
hmm
Im new to Android and created a new android project in Eclipse
but get "unable to instantiate activity error from the Logcat log.
Do I have to put something in that addAttachment(Strin... method??
hmm
I did put an image into my virtual sdcard and try sharing clicking but program/activity crash
- A Like
- Reply
更多相关文章
- 代码中设置drawableleft
- android 3.0 隐藏 系统标题栏
- Android开发中activity切换动画的实现
- Android(安卓)学习 笔记_05. 文件下载
- Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
- 技术博客汇总
- android 2.3 wifi (一)
- AndRoid Notification的清空和修改
- Android中的Chronometer