The following method can be used to package the ContentProvider in the library and set ContentProvider permissions at runtime so that it can be included in several projects without a ContentProvider Authority conflict. This works because the real "authority" comes from AndroidManifest ... not the ContentProvider class.
Start with the main implementation of ContentProvider. AUTHORITY, CONTENT_URI and UriMatcher are static, but not "final" ....
public class MyContentProvider extends ContentProvider { public static String AUTHORITY = "com.foo.bar.content"; public static Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); protected static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
Then override the 'attachInfo' method so that the first time you initialize the ContentProvider, your ContentProvider is called using ProviderInfo, which is derived from AndroidManifest. This will happen before any possible requests are made, most likely during the initial setup of the application class. Use this feature to reset AUTHORITY, CONTENT_URI and UriMatcher for their "real" values, as provided by the application using the ContentProvider library.
@Override public void attachInfo(Context context, ProviderInfo info) { super.attachInfo(context, info); AUTHORITY = info.authority; CONTENT_URI = Uri.parse("content://" + AUTHORITY); uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, AlarmTable.TABLENAME, ALARMS); uriMatcher.addURI(AUTHORITY, AttributeTable.TABLENAME, ATTRIBUTES); uriMatcher.addURI(AUTHORITY, DeepLinkTable.TABLENAME, DEEPLINKS); uriMatcher.addURI(AUTHORITY, NotificationTable.TABLENAME, NOTIFICATIONS); uriMatcher.addURI(AUTHORITY, MetaDataTable.TABLENAME, RESOURCE_METADATA); uriMatcher.addURI(AUTHORITY, ResourceTable.TABLENAME, RESOURCES); uriMatcher.addURI(AUTHORITY, ResourceAttributeTable.TABLENAME, RESOURCES_ATTRIBUTES); uriMatcher.addURI(AUTHORITY, ResourceTagTable.TABLENAME, RESOURCES_TAGS); uriMatcher.addURI(AUTHORITY, TagTable.TABLENAME, TAGS); uriMatcher.addURI(AUTHORITY, UserTagTable.TABLENAME, USER_TAGS); uriMatcher.addURI(AUTHORITY, UserTable.TABLENAME, USERS); uriMatcher.addURI(AUTHORITY, CUSTOM, RAW); }
When the application is launched, the ContentProvider is actually created along with the Application class, so it will have access to all the necessary information about the package. the ProviderInfo object will contain the information presented in AndroidManifest ... A list included in the final application.
<provider android:authorities="com.foo.barapp.content" android:name="com.foo.bar.MyContentProvider"/>
Now the administrator will be rewritten using "com.foo.barapp.content" instead of the default value, and UriMatcher will be updated to the application value, and not by default. Classes that rely on "AUTHORITY" will now access the updated value, and UriMatcher will correctly distinguish between incoming requests for "com.foo.barapp.content".
I tested this with both the sample application and the androidTest package at the same time and found that it worked correctly.