I am writing a component that makes certain functionality available to
any application running on an Android device (e.g. an advertising
service, stock ticker cache, Snowball server, etc).
This functionality is useful for application developers, but not
interesting to actual users i.e. my component should be included as
part of a new application, but not require the end user to explicitly
install the additional component themselves.
I expect that over time multiple applications installed on the phone
will want to communicate with my component. As each new application
will have a different certificate, I want to communicate between
applications using an Android Content Provider. To save resources on
the device (networking, caching, etc) only one instance of my
component should be appointed to handle all queries.
This works well as Android only registers the first Content Provider
for a given URI and then ignores the rest (throwing an “WARN/
PackageManager: Skipping provider name xxxx name already used” error
each time a new one is installed).
However if the registered Content Provider is uninstalled, it will
immediately break all the other applications that rely on it, even
though other instances of the component still exist.
Questions:
- Does anyone have any suggestions on how to better handle this
situation?
- If I could reregister Content Providers I could handle situations
like this, and upgrade components when newer versions are installed.
Perhaps the Android OS could also handle this situation better, by
tracking Content Provider naming collisions?
- Should I be looking at other communication methods to solve this
issue?
> I am writing a component that makes certain functionality available to > any application running on an Android device (e.g. an advertising > service, stock ticker cache, Snowball server, etc).
> This functionality is useful for application developers, but not > interesting to actual users i.e. my component should be included as > part of a new application, but not require the end user to explicitly > install the additional component themselves.
> I expect that over time multiple applications installed on the phone > will want to communicate with my component. As each new application > will have a different certificate, I want to communicate between > applications using an Android Content Provider. To save resources on > the device (networking, caching, etc) only one instance of my > component should be appointed to handle all queries.
> This works well as Android only registers the first Content Provider > for a given URI and then ignores the rest (throwing an "WARN/ > PackageManager: Skipping provider name xxxx name already used" error > each time a new one is installed).
> However if the registered Content Provider is uninstalled, it will > immediately break all the other applications that rely on it, even > though other instances of the component still exist.
> Questions: > - Does anyone have any suggestions on how to better handle this > situation? > - If I could reregister Content Providers I could handle situations > like this, and upgrade components when newer versions are installed. > Perhaps the Android OS could also handle this situation better, by > tracking Content Provider naming collisions? > - Should I be looking at other communication methods to solve this > issue?
It seems the attribute “android:multiprocess” in the “provider” tag
seems to have a behaviour that is not relevant to this problem, i.e.
it prevents multiple instances of the same Content Provider from
existing, rather than affecting multiple Content Providers trying to
use the same namespace.
Also, having it set to either true or false didn’t affect the outcome
of my tests.
I’ve only limited experience of Android inter-process communication,
and would be grateful if someone could shed some light on this issue.
Regards
Mark
On Jan 8, 4:45 pm, "Muthu Ramadoss" <muthu.ramad...@gmail.com> wrote:
> > I am writing a component that makes certain functionality available to
> > any application running on an Android device (e.g. an advertising
> > service, stock ticker cache, Snowball server, etc).
> > This functionality is useful for application developers, but not
> > interesting to actual users i.e. my component should be included as
> > part of a new application, but not require the end user to explicitly
> > install the additional component themselves.
> > I expect that over time multiple applications installed on the phone
> > will want to communicate with my component. As each new application
> > will have a different certificate, I want to communicate between
> > applications using an Android Content Provider. To save resources on
> > the device (networking, caching, etc) only one instance of my
> > component should be appointed to handle all queries.
> > This works well as Android only registers the first Content Provider
> > for a given URI and then ignores the rest (throwing an "WARN/
> > PackageManager: Skipping provider name xxxx name already used" error
> > each time a new one is installed).
> > However if the registered Content Provider is uninstalled, it will
> > immediately break all the other applications that rely on it, even
> > though other instances of the component still exist.
> > Questions:
> > - Does anyone have any suggestions on how to better handle this
> > situation?
> > - If I could reregister Content Providers I could handle situations
> > like this, and upgrade components when newer versions are installed.
> > Perhaps the Android OS could also handle this situation better, by
> > tracking Content Provider naming collisions?
> > - Should I be looking at other communication methods to solve this
> > issue?
AFAIK, a Content Provider is tied up to a unique Authority.
If you want to support multiple URI's you do so accordingly by providing different URI paths using the same authority.
Here is a recap of the important parts of a content URI:
[image: Elements of a content URI]
1. Standard required prefix. Never modified. 2. Authority part. For third-party applications, this should be a fully-qualified class to ensure uniqueness. This corresponds to the value in the <provider> element's *authorities* attribute: <provider class="TransportationProvider" authorities="com.example.transportationprovider" /> 3. The path that the content provider uses to determine what kind of data is being requested. This can be zero or more segments: if the content provider exposes only one type of data (only trains, for example), this can be absent. If it provides several types, including subtypes, this can be several elements long: e.g., "land/bus, land/train, sea/ship, and sea/submarine" to give four possibilities. 4. A specific record being requested, if any. This is the _id value of a specific record being requested. If all records of a specific type are being requested, omit this and the trailing slash: content://com.example.transportationprovider/trains
On Thu, Jan 8, 2009 at 11:19 PM, whitemice <markbr...@zedray.co.uk> wrote:
> Hi Muthu > Thanks for the response.
> It seems the attribute "android:multiprocess" in the "provider" tag > seems to have a behaviour that is not relevant to this problem, i.e. > it prevents multiple instances of the same Content Provider from > existing, rather than affecting multiple Content Providers trying to > use the same namespace.
> Also, having it set to either true or false didn't affect the outcome > of my tests.
> I've only limited experience of Android inter-process communication, > and would be grateful if someone could shed some light on this issue.
> > > I am writing a component that makes certain functionality available to > > > any application running on an Android device (e.g. an advertising > > > service, stock ticker cache, Snowball server, etc).
> > > This functionality is useful for application developers, but not > > > interesting to actual users i.e. my component should be included as > > > part of a new application, but not require the end user to explicitly > > > install the additional component themselves.
> > > I expect that over time multiple applications installed on the phone > > > will want to communicate with my component. As each new application > > > will have a different certificate, I want to communicate between > > > applications using an Android Content Provider. To save resources on > > > the device (networking, caching, etc) only one instance of my > > > component should be appointed to handle all queries.
> > > This works well as Android only registers the first Content Provider > > > for a given URI and then ignores the rest (throwing an "WARN/ > > > PackageManager: Skipping provider name xxxx name already used" error > > > each time a new one is installed).
> > > However if the registered Content Provider is uninstalled, it will > > > immediately break all the other applications that rely on it, even > > > though other instances of the component still exist.
> > > Questions: > > > - Does anyone have any suggestions on how to better handle this > > > situation? > > > - If I could reregister Content Providers I could handle situations > > > like this, and upgrade components when newer versions are installed. > > > Perhaps the Android OS could also handle this situation better, by > > > tracking Content Provider naming collisions? > > > - Should I be looking at other communication methods to solve this > > > issue?
This is a wider issue than just content providers, consider a library
that exports some non-trivial Activity (such that you don't want to
copy/paste it into each app). I don't think there is any solution for
versioning of Intent protocols today, or at least I didn't see one.
For what it's worth, MacOS X uses a similar versioning scheme to what
you propose - if it finds multiple copies of a library included inside
app packages, it'll use whichever is the latest version, so you get
both memory efficiency and ease of distribution. It's more network/
disk heavy, but the complexity reduction over a full dependency solver
is easily worth it.
I think Android could do worse than copying this approach. Right now
the approach seems to be asking the user to manually install separate
packages from the Market, there's even a software libraries category.
The Android approach right now is to bundle the components as an apk and then use the apk install/upgrade/remove mechanism respectively to install/upgrade/remove components.
On Fri, Jan 9, 2009 at 2:23 PM, Mike Hearn <mh.in.engl...@gmail.com> wrote:
> This is a wider issue than just content providers, consider a library > that exports some non-trivial Activity (such that you don't want to > copy/paste it into each app). I don't think there is any solution for > versioning of Intent protocols today, or at least I didn't see one.
> For what it's worth, MacOS X uses a similar versioning scheme to what > you propose - if it finds multiple copies of a library included inside > app packages, it'll use whichever is the latest version, so you get > both memory efficiency and ease of distribution. It's more network/ > disk heavy, but the complexity reduction over a full dependency solver > is easily worth it.
> I think Android could do worse than copying this approach. Right now > the approach seems to be asking the user to manually install separate > packages from the Market, there's even a software libraries category.
Just to clarify: I am writing an advertising server component at the
moment, but other projects that I have in the pipeline essentially
have the same requirement.
>>Dianne Hackborn - As far as naming issues, this is why you should use an authority in a
namespace/domain you own, so that there will not be naming
collisions.<<
My application sits in its own namespace. I am only having conflicts
with different copies of the same Content Provider Component being
installed with different applications.
>>Dianne Hackborn - …any client app that is relying on a component that is not part of the base platform needs to deal with the error cases if that component does not exist.<<
If the component is not there, then the application would show an
error on start and normally refuse to run. Result: Bad user
experience.
>>Peli - Hm, I think you end up with unnecessary code duplication if you include your component / content provider in every application.<<
This isn’t an issue, as my component is delivered as a small Java
class included with the main application. When activated, the
component inflates in size as it downloads content over the internet.
My goal is to manage this process by having only one component
activated regardless of how many applications are installed on the
device.
>>Peli - I think it would be better if every application that wants to use your component shows a small dialog "You need to install the following component..." with a button that brings you to the download page of the Market for your component...<<
Catching a missing component is easy enough. It’s just that what you
describe adds up to a bad user experience:
- No user will download a 3rd party advertising server (or any non-
core functionality) just to run a game.
- Installation is already a convoluted process and should only take
place once. Additional APK installations require more downloading,
application permission settings, button pressing, confusion, etc.
- No client of mine will accept a solution that asks the user to jump
through any additional hoops (e.g. even the Android Developer
Challenge only permitted a single executable).
>>Peli - At OpenIntents we try to resolve dependencies as late as possible - i.e. not at installation time, but the first time the user actually wants to use a particular feature (they may never use it in which case there is no need to install it).<<
This doesn’t work for me as ad funded Applications generally require
my component to be available on startup.
>>Peli - I think in the long run Market should have better tools for resolving compulsory dependencies automatically, but for the moment I think this is a good compromise for developers and end users.<<
I agree that this needs to be improved, as there is currently no
support for components (downloading, versioning, upgrading, etc) in
Android or on the Android Market. Hence I am trying to get around
this issue by “managing” a Content Provider.
>>Dianne Hackborn - Oh wait if what is being talked about is having the same content provider in multiple applications, that is completely the wrong approach. For a given authority there must be one and only one content provider implementation, living in a single specific .apk.<<
This is how it’s done at the moment, i.e. Android will log a warning
(and do nothing) every time an application tries to register a Content
Provider URI that’s already in use. This means that subsequent
applications will be broken (and need to be reinstalled) if the
original Content Provider is ever uninstalled. I don’t seem to be
able to reregister a missing Content Provider URI at runtime.
>>Muthu Ramadoss - AFAIK, a Content Provider is tied up to a unique Authority. If you want to support multiple URI's you do so accordingly by providing different URI paths using the same authority.<<
I explored this approach initially, but it still has the following
problem:
Over time, I release a number of versions of my component that other
developers subsequently integrate into their own applications. My
component uses the following URI conventions:
content://mynamespace.mycomponentnamespace.version1/
content://mynamespace.mycomponentnamespace.version2/
content://mynamespace.mycomponentnamespace.version3/
Android allows me to search and interrogate each URI to check the
status of each Content Provider (allowing me to version my
component). This is fine until v3 of my component becomes really
popular and a user installs five games on their phone, each with the
same component trying to register the same URI.
The user then gets bored of the first game and uninstalls it, thereby
breaking all the other games that rely on the Content Provider that it
contains. As URIs are set at install time, none of the other games
will work until the user reinstalls an existing game or downloads a
new one - This is a terrible user experience.
But fundamentally, activities are not shared libraries. An activity is something that knows how to operate on an Intent for the user. If you try to call startActivity() with an Intent for which there are multiple possible activities that can handle it, then the user will be prompted with a dialog to decide what they actually want to do at that point. There is no versioning here, there is the question "which specific type of operation were you interested in doing?".
Managing dependencies is another issue, but at the Activity level these are not versioning dependencies, these are feature dependencies. For example, there is a radar activity on the market, and someone else could write an app that allows you to invoke a radar view from it. It would be nice for it to declare in its manifest that it needs a radar activity, so the Market could have the user pick an app with a radar activity (other people could write alternative types of radars, again not "clearly better than" newer versions) when downloading the original app.
Or we have also talked about, when actually invoking the radar activity, having the system present a UI to find and download an app that does that at the point it is needed. This seems pretty reasonable because also unlike libraries, activities are a fundamental part of user flow, so interacting with the user to resolve dependencies at the point of use would seems fairly viable.
On Fri, Jan 9, 2009 at 12:53 AM, Mike Hearn <mh.in.engl...@gmail.com> wrote:
> This is a wider issue than just content providers, consider a library > that exports some non-trivial Activity (such that you don't want to > copy/paste it into each app). I don't think there is any solution for > versioning of Intent protocols today, or at least I didn't see one.
> For what it's worth, MacOS X uses a similar versioning scheme to what > you propose - if it finds multiple copies of a library included inside > app packages, it'll use whichever is the latest version, so you get > both memory efficiency and ease of distribution. It's more network/ > disk heavy, but the complexity reduction over a full dependency solver > is easily worth it.
> I think Android could do worse than copying this approach. Right now > the approach seems to be asking the user to manually install separate > packages from the Market, there's even a software libraries category.
Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them.
> Or we have also talked about, when actually invoking the radar activity,
> having the system present a UI to find and download an app that does that at
> the point it is needed. This seems pretty reasonable because also unlike
> libraries, activities are a fundamental part of user flow, so interacting
> with the user to resolve dependencies at the point of use would seems fairly
> viable.
Yes, that approach sounds reasonable. Although the Market UI paradigm
is pretty limited - if I click a button and the OS asks me to pick one
of three radar views, it might be hard for me to figure out which one
I want. They're all radars right? How fancy can it get?
They could be sorted in order of star rating, or show user comments
etc, but then I'm being distracted from what I actually want to do
with a choice that might be (in the larger scheme of things)
irrelevant.
Perhaps then a middle path - the author of an activity can fire an
intent with a recommended package name which is automatically fetched
if no suitable activity is installed, but the user can still see a
list of available alternatives in the manage applications view, and of
course the app could open that alternatives picker activity from its
settings menu or whatever.
"The federation of loosely coupled components" philosophy of Android design seems to give a lot of power to Users (which is cool!) to configure their applications in a powerful way. Whatever would make it more easier for User like providing ratings, preferred and recommended Components is a definite plus.
To add more on the radar discussion:
If the User had already selected a radar as his default, it would be nice if the platform has the ability to list all available components again that can handle this particular action on a request basis. I'm not sure if the User is given the choice again after he had selected a component as his default.
On Sat, Jan 10, 2009 at 3:31 AM, Mike Hearn <mh.in.engl...@gmail.com> wrote:
> > Or we have also talked about, when actually invoking the radar activity, > > having the system present a UI to find and download an app that does that > at > > the point it is needed. This seems pretty reasonable because also unlike > > libraries, activities are a fundamental part of user flow, so interacting > > with the user to resolve dependencies at the point of use would seems > fairly > > viable.
> Yes, that approach sounds reasonable. Although the Market UI paradigm > is pretty limited - if I click a button and the OS asks me to pick one > of three radar views, it might be hard for me to figure out which one > I want. They're all radars right? How fancy can it get?
> They could be sorted in order of star rating, or show user comments > etc, but then I'm being distracted from what I actually want to do > with a choice that might be (in the larger scheme of things) > irrelevant.
> Perhaps then a middle path - the author of an activity can fire an > intent with a recommended package name which is automatically fetched > if no suitable activity is installed, but the user can still see a > list of available alternatives in the manage applications view, and of > course the app could open that alternatives picker activity from its > settings menu or whatever.
On Fri, Jan 9, 2009 at 9:01 PM, Muthu Ramadoss <muthu.ramad...@gmail.com>wrote:
> If the User had already selected a radar as his default, it would be nice > if the platform has the ability to list all available components again that > can handle this particular action on a request basis. I'm not sure if the > User is given the choice again after he had selected a component as his > default.
Normally after selecting a default you won't be asked again for that particular intent, since that is the point of selecting a default. If you want to reselect, you need to go to manage applications and remove defaults for that app. That's unfortunately very not discoverable, it is true.
Note: please don't send private questions to me, as I don't have time to provide private support. All such questions should be posted on public forums, where I and others can see and answer them.
If I find more than one valid Content Provider I can then pass around
Synchronisation information (validity, compatibility, version, status,
etc) using any of the ContentProvider class methods (I used getType
()).
The only problem with this approach is that the application developer
who imports my component (as a JAR) will have to define their own
custom Content Provider. This is done by extending the
MyComponentContentProvider class (from my JAR) and defining a
CONTENT_URI variable.
package test;
import com.whitemice.MyComponentContentProvider;
public class TheirContentProvider extends MyComponentContentProvider {
public static final Uri CONTENT_URI =
Uri.parse( "content://
myComponentNamespace.theirApplicaitonNamespace");
}
As well as adding the custom provider to the Android manifest.
Without the custom Content Provider configuration, Android will behave
strangely and sometimes call a different .APK file if it has a class
in it with the same name.
As this is a work time project, I will have to check if I can release
the synchronisation code as a working example. If I do it will appear
on my blog here:
http://tinyurl.com/9hwdva