DIfference between Uri.fromParts and Uri.parse? - android

I'm creating an Intent for Android, to send e-mails.
And I'm getting confused about the behavior of Uri.fromParts.
Mi code:
This works fine!
uri=Uri.parse(
"mailto:" + toAddress +
(subject != null ?
("?" + "subject=" + Uri.encode(subject)) :
"")
The previous work fine, and create an Uri in the form mailto:john#doe.com?subject=Test
But if I try to use Uri.from parts, with this sample:
uriBuilder=Uri.fromParts("mailto",toAddress,null).buildUpon();
if (subject!=null) {
uriBuilder.appendQueryParameter("subject",subject);
}
uri=uriBuilder.build();
I get an error. The final uri is mailto:?subject=Test
The intermediate is correct, but when I use appendQueryParameter, it removes the content after the mailto scheme.
Do you know why? Which is the canonical way to do this?

Uri#fromParts()
Creates an opaque Uri from the given components. Encodes the ssp which means this method cannot be used to create hierarchical URIs.
When you call buildUpon() on this, the Builder contains the scheme, scheme-specific part (ssp) and the fragment (null in your case).
appendQueryParameter() then turns the Builder to a hierarchical one, deleting the opaque ssp data.
I don't think there's a "canonical" way. Just don't mix hierarchical and opaque builders.
For details on what happens under the hood, read the source.

Related

How do you resolve a relative Uri?

Given an absolute Uri and a relative Uri or relative path, how do you get the absolute Uri pointing to the relative location?
For example, suppose we have the Uri for file:///android_asset/dir, pointing to a location in our assets. Further suppose that elsewhere, we have a relative path of /foo. The absolute Uri for that relative path should be file:///android_asset/foo. Is there something on Uri, or elsewhere in the Android SDK, that I am missing that give me that result Uri?
Uri.withAppendedPath() is not the answer, as all it seems to do is handle trailing directory separators:
Uri abs=Uri.parse("file:///android_asset/");
Uri rel=Uri.withAppendedPath(abs, "/foo");
Assert.assertEquals("file:///android_asset/foo", rel.toString());
// actually returns file:///android_asset//foo
Uri abs2=Uri.parse("file:///android_asset/dir");
Uri rel2=Uri.withAppendedPath(abs2, "/foo");
Assert.assertEquals("file:///android_asset/foo", rel2.toString());
// actually returns file:///android_asset/dir//foo
Uri.Builder, via buildUpon() on Uri, is not an improvement:
Uri rel3=abs.buildUpon().appendPath("/foo").build();
Assert.assertEquals("file:///android_asset/foo", rel3.toString());
// actually returns file:///android_asset/%2Ffoo
Uri rel4=abs.buildUpon().appendEncodedPath("/foo").build();
Assert.assertEquals("file:///android_asset/foo", rel4.toString());
// actually returns file:///android_asset//foo
In a pinch I can try using java.net.URL and its URL(URL context, String spec) constructor, or just roll some code for it, but I was hoping to stay in the realm of Android Uri values if possible, just for any quirks differentiating URL and Uri.
Android doesn't make this easy.
In my case, I had to take a base url that may or may not have an included path:
http://www.myurl.com/myapi/
...and append a REST API method path, like:
api/where/agencies-with-coverage.json
...to produce the entire url:
http://www.myurl.com/myapi/api/where/agencies-with-coverage.json
Here's how I did it (compiled from various methods within the app - there may be a simpler way of doing this):
String baseUrlString = "http://www.myurl.com/myapi/";
String pathString = "api/where/agencies-with-coverage.json";
Uri.Builder builder = new Uri.Builder();
builder.path(pathString);
Uri baseUrl = Uri.parse(baseUrlString);
// Copy partial path (if one exists) from the base URL
Uri.Builder path = new Uri.Builder();
path.encodedPath(baseUrl.getEncodedPath());
// Then, tack on the rest of the REST API method path
path.appendEncodedPath(builder.build().getPath());
// Finally, overwrite builder with the full URL
builder.scheme(baseUrl.getScheme());
builder.encodedAuthority(baseUrl.getEncodedAuthority());
builder.encodedPath(path.build().getEncodedPath());
// Final Uri
Uri finalUri = builder.build();
In my case, the Builder classes for the API client code assembled the path prior to combining it with the baseURL, so that explains the order of things above.
If I've pulled together the above code correctly, it should handle port numbers as well as spaces in the URL string.
I pulled this source code from the OneBusAway Android app, specifically the ObaContext class. Note that this code on Github also handles the additional case where the user typed in a baseUrl (String serverName = Application.get().getCustomApiUrl() in the above code) that should override the region base URL (mRegion.getObaBaseUrl()), and the user-entered URL may not have http:// in front of it.
The unit tests that pass for the above code on Github, including cases where port numbers and spaces are included in the baseUrl and path, and the leading/trailing / may or may not be included, are here on Github. Related issues on Github where I was banging my head on the wall to try and get this all to work - 72, 126, 132.
I haven't tried this with non-HTTP URIs, but I believe it may work more generally.
There is an equivalent to urllib.parse.urljoin (Python) in Android URI.create(baseUrl).resolve(path).
import java.net.URI
URI.create("https://dmn92m25mtw4z.cloudfront.net/helpvids/f3_4/hls_480/480.m3u8")
.resolve("0.ts")
// output:
// https://dmn92m25mtw4z.cloudfront.net/helpvids/f3_4/hls_480/0.ts
Sean Barbeau answer returns wrong URL, it's just appending the 0.ts to the url.

Webview to PDF ignores job name

I am trying to print an HTML-page from a webview on KitKat (4.4.4) basically using the sample code provided in Google's API documentation. Accordingly, I set a print job name as follows:
String jobName = getString(R.string.app_name) + " Document";
PrintJob printJob = printManager.print(jobName, printAdapter,
new PrintAttributes.Builder().build());
My code runs fine and the page is printed as intended. Even if the user chooses the option "save as PDF" in the Android standard printing dialog, the codes renders a nice PDF and the user can choose a file name. At this point I would expect Android to use the string stored in the jobName field as file name. Instead it always uses webview as file name, although my code does not contain webview as string.
Is there a way to set another default name for storing a PDF file that is generated in my application?
Thanks for your hints...
Update:
I spent some additional time investigating this issue and I found that the WebView uses AwPrintDocumentAdapter as print adapter if the adapter is created by calling createPrintDocumentAdapter() as proposed in the API documentation. That class then calls
PrintDocumentInfo.Builder("webview") which seems to be the reason why the PDF always is named "webview". Some research reveals the following code snippet in AwPrintDocumentAdapter:
#Override
public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes,
CancellationSignal cancellationSignal, LayoutResultCallback callback,
Bundle metadata) {
mAttributes = newAttributes;
// TODO(sgurun) pass a meaningful string once b/10705082 is resolved
PrintDocumentInfo documentInfo = new PrintDocumentInfo
.Builder("webview")
.build();
// TODO(sgurun) once componentization is done, do layout changes and
// generate PDF here, set the page range information to documentinfo
// and call onLayoutFinished with true/false depending on whether
// layout actually changed.
callback.onLayoutFinished(documentInfo, true);
}
Hence, this seems to be the root cause for my problem - at least if that code made its way to my Nexus 4 test device... Finally, the best way to deal with this naming issue seems to be a custom print adapter implementation.
Are there any other solutions that do not require a custom print adapter (which should contain code for calculating the number of pages etc...)?

Easier way to produce HTTPGET REQUEST URI on Android

I'm trying to make an HTTPGET request to a REST server, the URL i need to send contains many parameters:
This is the URI :
http://darate.free.fr/rest/api.php?rquest=addUser&&login=samuel&&password=0757bed3d74ccc8fc8e67a13983fc95dca209407&&firstname=samuel&&lastname=barbier
I need to get the Login,password,first, name and last name that the user types, then produce an URI like the once above.
Is there any easy way to create the URI, without concatenate the first part of the URI http://darate.free.fr/rest/api.php?rquest=addUser with every &&parameter:value
I prefer to use Uri.Builder for building Uris. It makes sure everything is escaped properly.
My typical code:
Uri.Builder builder = Uri.parse(BASE_URI).buildUpon();
builder.appendPath(REQUEST_PATH);
builder.builder.appendQueryParameter("param1", value);
Uri builtUri = builder.build();
I hope you can use webview.posturl shown below
webview.postUrl("http://5.39.186.164/SEBC.php?user="+username));
It also worked fine for me to get the username from the database. I hope it will help you.

How can I upload multiple photos in one post on Google+ from G+ Android SDK?

I want to know how to upload multiple photos at a time thru google plus?
I found how to upload one photo and one message at a time from google plus sample code.
String action = "/?view=true";
Uri callToActionUrl = Uri.parse(getString(R.string.plus_example_deep_link_url) + action);
String callToActionDeepLinkId = getString(R.string.plus_example_deep_link_id) + action;
// Create an interactive post builder.
builder = new PlusShare.Builder(this, plusClient);
// Set call-to-action metadata.
builder.addCallToAction(LABEL_VIEW_ITEM, callToActionUrl, callToActionDeepLinkId);
// Set the target url (for desktop use).
builder.setContentUrl(Uri.parse(getString(R.string.plus_example_deep_link_url)));
// Set the target deep-link ID (for mobile use).
builder.setContentDeepLinkId(getString(R.string.plus_example_deep_link_id),
null, null, null);
// Set the message.
builder.setText("user message");
// Set the image
Uri uri = Uri.fromFile(new File("[user file path]"));
builder.setStream(uri);
Anyone knows about uploading multiple photos like facebook and twitter?
It should work with addStream() method, unfortunately... it doesn't work. Indeed it makes the application crash.
After a long search, I finally got it: it's not possible if using the simplified G+ SDK! (the one dedicated to Android).
There is a second one, included in the Google API family that you can find there:
http://code.google.com/p/google-api-java-client/wiki/APIs#Google+_API
This one will let you build more advanced post, included, several pic one.
Unfortunately the second SDK is much more low level, not dedicated to Android, it's a kind of Java abstraction over http request.
Regards

Mystery URL decoding of certain characters - Android URI / Google App Engine

I am having a curious problem that perhaps someone has insight into. I encode a query string into a URL on Android using the following code:
request = REQUEST_BASE + "?action=loadauthor&author=" + URLEncoder.encode(author, "UTF-8");
I then add a few other parameters to the string and create a URI like this:
uri = new URI(request);
At a certain point, I pull out the query string to make a checksum:
uri.getRawQuery().getBytes();
Then I send it on its way with:
HttpGet get = new HttpGet(uri);
On the Appengine server, I then retrieve the string and try to match the checksum:
String query = req.getQueryString();
Normally, this works fine. However, there are a few characters that seem to get unencoded on the way to the server. For example,
action=loadauthor&author=Charles+Alexander+%28Ohiyesa%29+Eastman&timestamp=1343261225838&user=1479845600
shows up in the server logs (and in the GAE app) as:
action=loadauthor&author=Charles+Alexander+(Ohiyesa)+Eastman&timestamp=1343261226837&user=1479845600
This only happens to a few characters (like parentheses). Other characters remain encoded all the way through. Does anyone have a thought about what I might be doing wrong? Any feedback is appreciated.
I never did find a solution for this problem. I worked around it by unencoding certain characters on the client before sending things to the server:
request = request.replace("%28", "(");
request = request.replace("%29", ")");
request = request.replace("%27", "'");
If anyone has a better solution, I am sure that I (and others) would be interested!
URLEncoder does not encode parentheses and certain other characters, as they are supposed to be "safe" for most servers. See URLEncoder. You will have to replace these yourself if necessary.
Example:
URI uri = new URI(request.replace("(","%28"));
If a lot of replacements are needed, you can try request.replaceAll(String regularExpression, String replacement). This, of course, requires knowledge of regular expressions.

Categories

Resources