My Content Uri's keep launching the same application - android

I'm using content URI's to link content (more like launch a specific activity) in an app and other apps that I've developed but the problem is anytime one application is selected from the android launcher the rest of the URI's keep opening using that singular app
I'm building the uri links using the Linkify class. Below shows the URI's
Pattern inlinkMatcher = Pattern.compile("\\(click[^()]*\\)|\\(you can[^()]*\\)|\\(check here [^()]*\\)");
String inLinkURL = "content://com.n4labs.sexed.providers/hgcontent/";
Pattern inlinkMatcher2 = Pattern.compile("\\(click here to find [^()]*\\)");
Pattern inlinkMatcher3 = Pattern.compile("\\(learn more [^()]*\\)|\\(talk to [^()]*\\)");
boolean yfsinstalled = appInstalledOrNot("com.n4labs.yfs");
String inLinkURL2 = "http://market.android.com/details/?id=com.n4labs.yfs";
if(yfsinstalled)
inLinkURL2 = "content://com.n4labs.yfs.providers/centersearch/";
boolean divainstalled = appInstalledOrNot("com.n4labs.diva");
String inLinkURL3 = "http://market.android.com/details/?id=com.n4labs.diva";
if(divainstalled)
inLinkURL3 = "content://com.n4labs.diva.providers/learn/";
And the calls to Linkify
if(yfsinstalled){
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher2, inLinkURL2);
}
else
{
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher2, inLinkURL2, null, mentionFilter);
}
if(divainstalled){
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher3, inLinkURL3);
}
else
{
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher3, inLinkURL3, null, mentionFilter);
}
Linkify.addLinks(itemController3.paragraphtext, inlinkMatcher, inLinkURL);
The provider in each app has the appropriate authority and is exported as such
<provider
android:name="com.n4labs.diva.providers.HealthGuideContentProvider"
android:authorities="com.n4labs.diva.providers"
android:exported="true">
</provider>
How can I ensure that each URI opens in the appropriate application automatically, or at least the option is displayed to the user every-time.
I hope I was clear enough.
Anyone?
Thanks.

Each of your ContentProviders is reporting that the MIME type associated with those Uri values is text/plain. This is a very common MIME type, one normally associated with standard text files.
When the user clicks on a link for any of those Uri values, Android will construct an ACTION_VIEW Intent, for a MIME type of text/plain, and attempt to start an activity for that, such as a text editor.
The key now is: what do these ContentProviders actually deliver, as content, for those Uri values? In other words, if I were to call openInputStream() on a ContentResolver, passing in one of those Uri values, what data do I get back in the stream?
There are five main possibilities that I see:
They legitimately return plain text, and you really do want an ordinary text editor to be an option for the user to work with that text. In that case, your setup is fine. Bear in mind that the user might elect to click the "always" option for handling these Uri values and therefore may not necessarily want to be presented with a choice of activities each time. After all, in this scenario, all three of your activities can work with all three of your providers, and regular text editors can also work with these providers.
They legitimately return plain text, but you really do not want anything other than your activities handling those Uri values. In that case, get rid of the ContentProviders, get rid of Linkify, and add your own ClickableSpans to the text to directly start activities of your choosing.
They do not return plain text, but instead return data in some other format, and you are willing for third-party apps to be able to work with that content. In that case, change the MIME type (in the provider and in the associated <intent-filter>) to the correct value, instead of text/plain. This may involve you creating your own custom "vendor" MIME type, if your data does not match any standard data format.
The openInputStream() call would crash, because you have a buggy ContentProvider that is not actually serving data for these Uri values. In that case, fix the ContentProvider, then run through this list of possibilities again. Since you are exporting this provider, you need to actually implement it properly.
The openInputStream() call would crash, or the providers would return something other than plain text, but you are not intending on anybody actually using this content other than yourself. In that case, get rid of the ContentProvider, get rid of Linkify, and add your own ClickableSpans to the text to directly start activities of your choosing.
My guess is that your case is #2 or #5.

Related

getType method in contentProvider subclass

i searched a lot about this topic
but i still can't wrap my brain around it
can someone "deeply explains to me " how getType() works ? and few examples that also explains the mime and how it is used when it is returned by getType() ?
Content URIs can be used to reference content from a wide variety of contexts. The getType method allows a content consumer - which might be a component in your app, but can also be component outside your app and which doesn't know anything specifically about your app except for the content URI - to find out what type of data a content URI refers to. The content consumer needs this information to know how what to do with the content - for example, how to display it - when it resolves the content URI. So in the simplest case, if the URI content://my.app/record/1 refers to a HTML file, then the type is text/html, and if the URI content://my.app/record/2 refers to a JPEG file then the type is image/jpeg. There is no other way to infer the content type from the URI (because e.g. there's no file extensions).
Android also provides some special MIME types for indicating table data, android.cursor.item/* and android.cursor.dir/*.
This approach is designed to fit in with Android's Activity based architecture, allowing the system to open content URIs by examining the content MIME type and then choosing an Intent to open an Activity which displays the content.

How to access linkify number

I need to make all numbers in a string become links.
The expected action when any of these links is clicked is to append the clicked number to an existing string.
I managed to linkify the numbers by using the following code:
Pattern myMatcher = Pattern.compile("[0-9]*");
Linkify.addLinks(myString, myMatcher, null);
How can I access and retrieve the clicked number in this case?
I tried looking in other questions related to Linkify but seems all are describing ways to have an action that opens an activity or open the default app for that link type (email address/web URL/etc.)
Thanks in advance for you help :)
You can Customize Linkify to append any predefiened string(scheme) into that.
Take a look at the following post Android Developer Blogspot (Search for "Custom Linkify")
For clarity I am describing a portion of that post here:
Linkify will automatically append whatever is matched to a scheme that
is supplied to it, so for the sake of argument let's assume we have a
ContentProvider that matches the following content URI:
content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord
The WikiWord part will be appended by Linkify when it finds a match,
so we just need the part before that as our scheme.
Now that we have these two things, we use Linkify to connect them up:
Pattern wikiWordMatcher = Pattern.compile("\\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\\b");
String wikiViewURL = "content://com.google.android.wikinotes.db.wikinotes/wikinotes/";
Linkify.addLinks(noteView, wikiWordMatcher, wikiViewURL);
Linkify can be used multiple times on the same view to add more links,
so using this after the Default Linkify call means that the existing
active links will be maintained and the new WikiWords will be added.
You could define more Linkify actions and keep applying them to the
same TextView if you wanted to.
Now, if we have a WikiWord in the TextView, let's say MyToDoList,
Linkify will turn it into an active link with the content URI:
content://com.google.android.wikinotes.db.wikinotes/wikinotes/MyToDoList
and if you click on it, Android will fire the default intent for that
content URI.
For this to all work, you will need a ContentProvider that understands
that Content URI, and you will need a default activity capable of
doing something with the resulting data. I plan to cover these in
future blog entries (and soon). In fact, the whole Wiki Note Pad
application is currently undergoing some clean up and review, and will
then hopefully be released as a sample application.

ShareActionProvider with a ListFragment

I would like to use a ShareActionProvider to share the contents of my ListFragment (which consists of text entries from an ArrayAdapter fed with a ArrayList<MyObject>).
How do I do this?
I know that I will have to create a new Intent and to use setType("text/plain") but for setAction() should I use Intent.ACTION_SEND and Intent.ACTION_SEND_MULTIPLE?
When setting the content, should I use putExtra or putParcelableArrayListExtra?
Do I set the Intent with the data from the ListFragment, or from the ArrayAdapter, or from the ArrayList<MyObject> that is fed into ArrayAdapter, or from the data before the ArrayList were constructed?
for setAction() should I use Intent.ACTION_SEND and Intent.ACTION_SEND_MULTIPLE?
That is your choice to make, as the author of the app. If you are expecting to share one piece of text (that you assembled from many pieces yourself), use ACTION_SEND. If you are expecting to share many pieces of text, use ACTION_SEND_MULTIPLE.
Note that I would expect about a 100:1 ratio of apps supporting ACTION_SEND compared to ACTION_SEND_MULTIPLE. So, if your objective is for this sharing to be generally useful, you would want to steer towards ACTION_SEND.
More importantly, you need to determine what the users are going to want to do. Presumably, the point behind your development is for 1+ humans to use this app. If the user of the app is expecting to send one email, or post one tweet, or upload one note based on this data, you should be using ACTION_SEND. If, instead, the user will be expecting to send N messages (or whatever), then that would be something to try with ACTION_SEND_MULTIPLE.
When setting the content, should I use putExtra or putParcelableArrayListExtra?
For ACTION_SEND, it would be putExtra(), passing in the String. For ACTION_SEND_MULTIPLE, it would be putStringArrayListExtra().
Do I set the Intent with the data from the ListFragment, or from the ArrayAdapter, or from the ArrayList that is fed into ArrayAdapter, or from the data before the ArrayList were constructed?
You use a String or ArrayList<String> as noted above. Where you get those values from is your business logic that you as a developer need to decide.

Pass a parameter to a Custom Search Suggestion ContentProvider

I have a working custom search suggestions class (via http://developer.android.com/guide/topics/search/adding-custom-suggestions.html). It currently returns one type of information - "product names".
I've added some additional activities (screens) to my app so that if a person is on a product page, starting up a search should return results from "product names", but if they are in another activity, I would like the search suggestions to pull "manufacturer names".
I saw Accessing appSearchData bundle from ContentProvider, but the custom search suggestions provider extends ContentProvider which doesn't work with the answer
Bundle b = intent.getBundleExtra(SearchManager.APP_DATA);
This Bundle is available to the search results class, but not the contentprovider.
How best to pass a parameter ("product" or "manufacturer") to a search suggestions content provider?
This doesn't seem like an ideal solution, but I had the same need and I found I could get the job done by adding a public ivar or method to the subclass of ContentProvider that handles the search suggestions. Prior to initiating the search, you can configure your provider as needed. You can access the provider instance from an activity like so:
ContentProviderClient client = getContentResolver().acquireContentProviderClient("my.searchsuggestionprovider");
MyProviderClass provider = (MyProviderClass) client.getLocalContentProvider();
Now you can configure with provider.setParameter("product") or whatever you need. You might need to reset the parameter to a default or something after building your cursor.
Edit: This turned out to be impractical, at least in my case, since the content provider is called with query() every time a character is typed. Instead, I have employed a workaround similar to what is described in set-search-hint-dynamically. By creating an alternate "searchable" XML definition and activity, you can alter the URI that's passed to the content provider in query(), adding a path component to provide the additional parameter or context you need.
I just made a static variable for the parameter on my content provider, and set it from the activity. I been thinking about it, and it's the cleanest workaround I have found!

Why use ContentProvider.getType() to get MIME type?

Looking at content providers, I'm not quite clean on the typical usage of the getType() method. The API doc says about implementing this method that
This allows [applications] to retrieve the MIME
type for a URI when dispatching
intents.
Could anyone describe a typical case where using it would be particularly useful?
For example, you're writing content provider for picture gallery. You should mention in your getType() method that you provide pictures - jpg or png. So, when one will launch image gallery, it will be able to show built-in pictures and pictures provided by your content provider.
In pseudocode the user of contentProvider do something like:
List contentProviders = getProviders();
List resultProviders;
final Type type = Type.JPG;
for (ContentProvider provider : contentProviders) {
if (type == provider.getType()) {
resultProviders.add(provider);
}
}
This is pseudocode, but I hope you will got the idea.
As I understand it, a use case could be the following:
App A contains the content provider. App B uses that content provider to retrieve all the data items from App A. The user then picks one of these (in App B) and after that an activity in App A to show/edit/delete the selected data item should be started. So App B then creates an intent, and to make sure that an activity in App A handles it, you need to set the (mime-)type of the intent to the mime-type of the uri (the show/edit/delete activities in App A has added this mime type to their intent filters).

Categories

Resources