What is the best way to attach multiple images? - java

Several of my timeline item designs require multiple images, yet I am having difficulty attaching them all reliably. The timeline.insert function only seems to allow for one attachment and inserting attachments after the timeline item is inserted sometimes results in the images not being rendered.
I also tried using setAttachments on the timeline item itself but it didn't seem to actually upload the attachments when inserting the item. Using the code below I tend to get mixed results. Sometimes it works and other times it fails to render the image. There seems to be a correlation with how long I wait to view the notification after receiving it, if I view it too quickly it never fully renders.
Does anyone have any thoughts or suggestions on how I could overcome this or see anything I'm doing wrong?
//CardFactory.java - Create TimelineItem with attachment list
public static TimelineItem getConceptCard(String conceptImage) {
TimelineItem timelineItem = new TimelineItem();
timelineItem.setHtml("<article class=\"photo\">\n <img src=\"attachment:0\" width=\"100%\" height=\"100%\">\n <div class=\"photo-overlay\"/>\n <section>\n <p class=\"text-auto-size\">Test</p>\n </section>\n</article>\n");
List<Attachment> attachments = new ArrayList<Attachment>();
Attachment img1 = new Attachment();
img1.setId("backImage");
img1.setContentType("image/jpeg");
img1.setContentUrl(WebUtil.buildStaticImgUrl("cardconcepts/" + conceptImage + ".JPG"));
attachments.add(img1);
timelineItem.setAttachments(attachments);
timelineItem.setNotification(new NotificationConfig().setLevel("DEFAULT"));
return timelineItem;
}
//MainServlet.java - Send TimelineItem on button press
} else if (req.getParameter("operation").equals("insertConceptCard")) {
TimelineItem timelineItem = CardFactory.getConceptCard(req.getParameter("conceptCard"));
MirrorClient.insertTimelineCard(credential, timelineItem);
//MirrorClient.java - Insert TimelineItem with multiple attachments
public static void insertTimelineCard(Credential credential, TimelineItem item) throws IOException {
Mirror.Timeline timeline = getMirror(credential).timeline();
TimelineItem timelineItem = timeline.insert(item).execute();
for(Attachment TAttach : item.getAttachments()){
InputStreamContent mediaContent = new InputStreamContent(TAttach.getContentType(), new URL(TAttach.getContentUrl()).openStream());
timeline.attachments().insert(timelineItem.getId(), mediaContent).execute();
}

I am not sure if it is possible given your requirements, but if the attachments are public images, you don't actually need to attach them. You can use the img tag with a normal http URL. My experience has been that these get fetched fairly quickly, are cached if you use them frequently, and render correctly even if they don't render immediately.
(Even if your requirements need to keep these more private, you may wish to use standard image fetching with some kind of nonce instead of trying to attach them. I realize this doesn't quite answer your question, but it may be a useful workaround.)

Related

How can I add notifications to my news App ANDROID?

I am working on a android news app which gets news from google news rss feed. I am currently getting news and showing it to the user in my app. But I want to show notification to the user when new news appears on google rss. I have no idea how to do it as I am new to android and could not find anything relevant on google. Thank you.
Here is my code I have done so far
internal static List<FeedItem> GetFeedItems(string url)
{
List<FeedItem> feedItemsList = new List<FeedItem>();
try
{
HttpClient wc = new HttpClient();
var html = wc.GetStringAsync(new Uri(url)).Result;
XElement xmlitems = XElement.Parse(html);
// We need to create a list of the elements
List<XElement> elements = xmlitems.Descendants("item").ToList();
// Now we're putting the informations that we got in our ListBox in the XAML code
// we have to use a foreach statment to be able to read all the elements
// Description , Link , Title are the attributes in the RSSItem class that I've already added
List<FeedItem> aux = new List<FeedItem>();
foreach (XElement rssItem in elements)
{
FeedItem rss = new FeedItem();
rss.Description = rssItem.Element("description").Value;
rss.Link = rssItem.Element("link").Value;
rss.Title = rssItem.Element("title").Value;
feedItemsList.Add(rss);
}
}
catch (Exception)
{
throw;
}
return feedItemsList;
}
Use parse's push notification,it's very easy to use and has great documents.
https://parse.com
go for push notification service. its the only way to get the notification .
follow this tutorial... http://www.androidhive.info/2012/10/android-push-notifications-using-google-cloud-messaging-gcm-php-and-mysql/
Notification manager is what you want here.
see this http://developer.android.com/guide/topics/ui/notifiers/notifications.html ?
A simple google search also shows tutorials for the same

XPages: Creating JSON String from large amount of document

I have been trying to create a Json String with a large amount document but using the below code but i get out of range or have to wait till up to 5min b4 the String is greated any idiea how i could optimise the code?
public String getJson() throws NotesException {
...
View view1 = ...;
ViewNavigator nav =view1.createViewNav();
ViewEntry ve = nav.getFirst();
JSONObject jsonMain = new JSONObject();
JSONArray items = new JSONArray();
Document docRoot = null
while (ve != null) {
docRoot= ve.getDocument();
items.add(getJsonDocAndChildren(docRoot));
ViewEntry veTemp = nav.getNextSibling(ve);
ve.recycle();
ve = docTemp;
}
jsonMain.put("identifier", "name");
jsonMain.put("label", "name");
jsonMain.put("items", items);
return jsonMain.toJSONString();
}
private JSONObject getJsonDocAndChildren(Document doc) throws NotesException {
String name = doc.getItemValueString("Name");
JSONObject jsonDoc = new JSONObject();
jsonDoc.put("name", name);
jsonDoc.put("field", doc.getItemValueString("field"));
DocumentCollection responses = doc.getResponses();
JSONArray children = new JSONArray();
getDocEntry(name,children);//this add all doc that has the fieldwith the same value name to children
if (responses.getCount() > 0) {
Document docResponse = responses.getFirstDocument();
while (docResponse != null) {
children.add(getJsonDocAndChildren(docResponse));
Document docTemp = responses.getNextDocument(docResponse);
docResponse.recycle();
docResponse = docTemp;
}
}
jsonDoc.put("children", children);
return jsonDoc;
}
There are a few things here, ranging from general efficiency to optimizations based on how you want to use the code.
The big one that would likely speed up your processing would be to do view operations only, without cracking open the documents. Since it looks like you want to get responses indiscriminately, you could add the response documents to the original view, with the "Show responses in hierarchy" option turned on. Then, if you have columns for Name and field in the view (and no "Show responses only") columns, then a nav.getNext() walk down the view will get them in turn. By storing the entry.getIndentLevel() value for each previous entry and comparing it at the start of the loop, you could "step" up and down the JSON tree: when the indent level increases by one, create a new array and add it to the existing object; when it decreases, step up one. It may be a little conceptually awkward at first, having to track previous states in a flat loop, but it'd be much more efficient.
Another option, also having the benefit of not having to crack open each individual document, would be to have a view of the response documents categorized by #Text($REF) and then making your recursive method look more like:
public static void walkTree(final View treeView, final String documentId) {
ViewNavigator nav = treeView.createViewNavFromCategory(documentId);
nav.setBufferMaxEntries(400);
for (ViewEntry entry : nav) {
// Do code here
walkTree(treeView, entry.getUniversalID(), callback);
}
}
(That example is using the OpenNTF Domino API, but, if you're not using that, you could down-convert the for loop to the legacy style)
As a minor improvement any time you traverse through ViewNavigators, you can set view.setAutoUpdate(false) and then nav.setBufferMaxEntries(400) to improve the internal caching.
And finally, depending on your needs - say, if you're outputting the JSON directly to an HTTP response's output stream - you could use JsonWriter instead of JsonObject to stream the content out instead of building a huge object in memory. I wrote about it with some simple code here: https://frostillic.us/blog/posts/EF0B875453B3CFC285257D570072F78F
You should first determine where the time is spent in your code. Maybe it is in doc.getResponses() or responses.getNextDocument() which you did not show here.
The obvious optimization which could be done within your code snippet is the following:
Basically you have some data structure called Document and build up a corresponding in memory JSON structure consisting of JSONObjects and JSONArrays. This JSON structure is then serialized to a String and returned.
Instead of building the JSON structure you could directly use a JsonWriter (don't know what JSON library you are using but there must be something like a JsonWriter). This avoids the memory allocations for the temporary JSON structure.
In getJson() you start:
StringWriter stringOut = new StringWriter();
JsonWriter out = new JsonWriter(stringOut);
and end
return stringOut.toString();
Now everywhere where you creating JSONObjects or JSONArrays you invoke corresponding writer methods. e.g.
private void getJsonDocAndChildren(Document doc, JsonWriter out) throws NotesException {
out.name("name");
out.value(doc.getItemValueString("Name"));
out.name("field");
out.value(doc.getItemValueString("field"));
DocumentCollection responses = doc.getResponses();
if (responses.getCount() > 0) {
Document docResponse = responses.getFirstDocument();
out.startArray();
...
Hope you get the idea.

Android: I am unable to download an image with the URL I have to use due to formatting issues

I am using an API that returns a String for the URL of a photo. It is in a strange format, however, and it is causing me issues downloading the images using Volley (or any other method for that matter).
My code looks like this:
imageview = (ImageView) findViewById(R.id.imageView);
String web_url = "http:\\/\\/static.giantbomb.com\\/uploads\\/square_avatar\\/8\\/87790\\/1814630-box_ff7.png";
String web_url2 = "http://www.finalfantasyviipc.com/images/media_cloud_big.jpg";
ImageRequest ir = new ImageRequest(web_url2, new Response.Listener<Bitmap>() {
#Override
public void onResponse(Bitmap response) {
imageview.setImageBitmap(response);
Log.d("image was ", "set");
}
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(), "ERROR: " + error.getMessage(), Toast.LENGTH_SHORT).show();
Log.d("ERROR", error.getMessage());
}
}, 0, 0, null, null);
requestQueue.add(ir);
As you can see, the second URL works fine, but the first URL, the one with the many backward and forward slashes, will not return an image. You can copy both into your browser and they work fine, but the first one cannot be read by my Android parsing. Does anyone have any recommendations of how to get an image from the first link? Nearly everything I have tried utilizes Strings, which seems to be a core part of the problem.
Thanks for your help!
-Sil
You can copy both into your browser and they work fine, but the first one cannot be read by my Android parsing
The first URL is definitely malformed but the reason why it works in browsers is because they automatically convert backslashes to forward slashes and most web servers tend to ignore multiple consecutive forward slashes.
For example, if I enter that URL in Chrome (OSX), the URL in the address bar changes to:
http://static.giantbomb.com///uploads///square_avatar///8///87790///1814630-box_ff7.png
which seems to work fine. So, to solve your problem on Android, just do the same:
web_url = web_url.replace("\\", "/");
or even better:
web_url = web_url.replace("\\", "");
That should convert the URL to http://static.giantbomb.com/uploads/square_avatar/8/87790/1814630-box_ff7.png and therefore fix your issue.

How do I send bundled cards all at the same time?

I've set up a Java application where I'm creating a bundle of 4 cards. The problem is that all the cards do not come in at once. Some times just one shows up, then a few seconds or minute later the other cards show up. How do I get them to all show up on the headset at the same time?
edit:
I tried HTML paging and that didn't work and now I think I'm more confused. So in my senario here I want to send a bunch of landmarks to the user that they can navigate to. I want all the landmarks in a bundle, I want a cover to the bundle that isn't an option in the bundle saying "here are your landmarks", and I'd like the bundle to get to the user all at the same time. How can I achieve this?
TimelineItem timelineItemEmpire = new TimelineItem();
timelineItemEmpire.setText("Empire State Building");
// Triggers an audible tone when the timeline item is received
timelineItemEmpire.setNotification(new NotificationConfig().setLevel("DEFAULT"));
Location empireLoc = new Location();
empireLoc.setLatitude(40.748492);
empireLoc.setLongitude(-73.985868);
timelineItemEmpire.setLocation(empireLoc);
// Attach an image, if we have one
URL url = new URL(WebUtil.buildUrl(req, "/static/images/empirestate.jpg"));
timelineItemEmpire.setBundleId(bundleId);
List<MenuItem> menuItemList = new ArrayList<MenuItem>();
menuItemList.add(new MenuItem().setAction("NAVIGATE"));
timelineItemEmpire.setMenuItems(menuItemList);
MirrorClient.insertTimelineItem(credential, timelineItemEmpire, contentType, url.openStream());
TimelineItem timelineItemCP = new TimelineItem();
timelineItemCP.setText("Central Park");
// Triggers an audible tone when the timeline item is received
timelineItemCP.setNotification(new NotificationConfig().setLevel("DEFAULT"));
// Attach an image, if we have one
URL url3 = new URL(WebUtil.buildUrl(req, "/static/images/central_park.jpg"));
timelineItemCP.setBundleId(bundleId);
Location cpLoc = new Location();
cpLoc.setLatitude(40.772263);
cpLoc.setLongitude(-73.974488);
timelineItemCP.setLocation(cpLoc);
timelineItemCP.setMenuItems(menuItemList);
MirrorClient.insertTimelineItem(credential, timelineItemCP, contentType, url3.openStream());
TimelineItem timelineCover = new TimelineItem();
timelineCover.setText("Nearby Landmarks");
timelineCover.setBundleId(bundleId);
// Triggers an audible tone when the timeline item is received
timelineCover.setNotification(new NotificationConfig().setLevel("DEFAULT"));
// Attach an image, if we have one
URL url4 = new URL(WebUtil.buildUrl(req, "/static/images/bundle_cover.jpg"));
MirrorClient.insertTimelineItem(credential, timelineCover, contentType, url4.openStream());
You need to set the isBundleCover resource to true for your cover; i.e.:
timelineCover.setIsBundleCover(true);
This will make it the entry point into the bundle, and prevent it from being displayed within the bundle, as described here.
Furthermore, you can use BatchRequest to make sure they're sent together; e.g.,:
BatchRequest batch = MirrorClient.getMirror(null).batch();
BatchCallback callback = new BatchCallback();
for (TimelineItem item : items) {
MirrorClient.getMirror(userCredential).timeline().insert(item).queue(batch, callback);
}
batch.execute();

Convert embedded pictures in database

I have a 'small' problem. In a database documents contain a richtextfield. The richtextfield contains a profile picture of a certain contact. The problem is that this content is not saved as mime and therefore I can not calculate the url of the image.
I'm using a pojo to retrieve data from the person profile and use this in my xpage control to display its contents. I need to build a convert agent which takes the content of the richtextitem and converts it to mime to be able to calculate the url something like
http://host/database.nsf/($users)/D40FE4181F2B86CCC12579AB0047BD22/Photo/M2?OpenElement
Could someone help me with converting the contents of the richtextitem to mime? When I check for embedded objects in the rt field there are none. When I get the content of the field as stream and save it to a new richtext field using the following code. But the new field is not created somehow.
System.out.println("check if document contains a field with name "+fieldName);
if(!doc.hasItem(fieldName)){
throw new PictureConvertException("Could not locate richtextitem with name"+fieldName);
}
RichTextItem pictureField = (RichTextItem) doc.getFirstItem(fieldName);
System.out.println("Its a richtextfield..");
System.out.println("Copy field to backup field");
if(doc.hasItem("old_"+fieldName)){
doc.removeItem("old_"+fieldName);
}
pictureField.copyItemToDocument(doc, "old_"+fieldName);
// Vector embeddedPictures = pictureField.getEmbeddedObjects();
// System.out.println(doc.hasEmbedded());
// System.out.println("Retrieved embedded objects");
// if(embeddedPictures.isEmpty()){
// throw new PictureConvertException("No embedded objects could be found.");
// }
//
// EmbeddedObject photo = (EmbeddedObject) embeddedPictures.get(0);
System.out.println("Create inputstream");
//s.setConvertMime(false);
InputStream iStream = pictureField.getInputStream();
System.out.println("Create notesstream");
Stream nStream = s.createStream();
nStream.setContents(iStream);
System.out.println("Create mime entity");
MIMEEntity mEntity = doc.createMIMEEntity("PictureTest");
MIMEHeader cdheader = mEntity.createHeader("Content-Disposition");
System.out.println("Set header withfilename picture.gif");
cdheader.setHeaderVal("attachment;filename=picture.gif");
System.out.println("Setcontent type header");
MIMEHeader cidheader = mEntity.createHeader("Content-ID");
cidheader.setHeaderVal("picture.gif");
System.out.println("Set content from stream");
mEntity.setContentFromBytes(nStream, "application/gif", mEntity.ENC_IDENTITY_BINARY);
System.out.println("Save document..");
doc.save();
//s.setConvertMime(true);
System.out.println("Done");
// Clean up if we are done..
//doc.removeItem(fieldName);
Its been a little while now and I didn't go down the route of converting existing data to mime. I could not get it to work and after some more research it seemed to be unnecessary. Because the issue is about displaying images bound to a richtextbox I did some research on how to compute the url for an image and I came up with the following lines of code:
function getImageURL(doc:NotesDocument, strRTItem,strFileType){
if(doc!=null && !"".equals(strRTItem)){
var rtItem = doc.getFirstItem(strRTItem);
if(rtItem!=null){
var personelDB = doc.getParentDatabase();
var dbURL = getDBUrl(personelDB);
var imageURL:java.lang.StringBuffer = new java.lang.StringBuffer(dbURL);
if("file".equals(strFileType)){
var embeddedObjects:java.util.Vector = rtItem.getEmbeddedObjects();
if(!embeddedObjects.isEmpty()){
var file:NotesEmbeddedObject = embeddedObjects.get(0);
imageURL.append("(lookupView)\\");
imageURL.append(doc.getUniversalID());
imageURL.append("\\$File\\");
imageURL.append(file.getName());
imageURL.append("?Open");
}
}else{
imageURL.append(doc.getUniversalID());
imageURL.append("/"+strRTItem+"/");
if(rtItem instanceof lotus.domino.local.RichTextItem){
imageURL.append("0.C4?OpenElement");
}else{
imageURL.append("M2?OpenElement");
}
}
return imageURL.toString()
}
}
}
It will check if a given RT field is present. If this is the case it assumes a few things:
If there are files in the rtfield the first file is the picture to display
else it will create a specified url if the item is of type Rt otherwhise it will assume it is a mime entity and will generate another url.
Not sure if this is an answer but I can't seem to add comments yet. Have you verified that there is something in your stream?
if (stream.getBytes() != 0) {
The issue cannot be resolved "ideally" in Java.
1) if you convert to MIME, you screw up the original Notes rich text. MIME allows only for sad approximation of original content; this might or might not matter.
If it matters, it's possible to convert a copy of the original field to MIME used only for display purposes, or scrape it out using DXL and storing separately - however this approach again means an issue of synchronization every time somebody changes the image in the original RT item.
2) computing URL as per OP code in the accepted self-answer is not possible in general as the constant 0.C4 in this example relates to the offset of the image in binary data of the RT item. Meaning any other design of rich text field, manually entered images, created by different version of Notes - all influence the offset.
3) the url can be computed correctly only by using C API that allows to investigate binary data in rich text item. This cannot be done from Java. IMO (without building JNI bridges etc)

Categories

Resources