I am trying to access the LauncherProvider
. You can find its source code here
I tried to query this ContentProvider
like this:
Uri uri = new Uri.Builder().scheme("content").authority("com.android.launcher.settings").appendPath("favorites").build();
String[] projection = new String[]{
"_id", "title", "intent", "container", "screen", "cellX", "cellY",
"spanX", "spanY", "itemType", "appWidgetId", "isShortcut", "iconType",
"iconPackage", "iconResource", "icon", "uri", "displayMode"
};
String selection = null;
String[] selectionArgs = null;
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
Cursor query = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
if (query != null) {
while (query.moveToNext()) {
Log.d(TAG, query.getString(2));
}
}
if (query != null) {
query.close();
}
However the Cursor
I get is always null
! This is the error I get in the logcat:
07-31 15:55:14.703 24773-24773/x.y.z.testE/ActivityThread﹕ Failed to find provider info for com.android.launcher.settings
Can anybody tell me what I'm doing wrong?
You are trying to access the LauncherProvider
, but that may not be as easy you want. There are two main problems:
The LauncherProvider has two permissions:
com.android.launcher.permission.READ_SETTINGS
to read from it.com.android.launcher.permission.WRITE_SETTINGS
to write to it.
Different OEMs write their own version of the LauncherProvider
and its authority might be different! On different versions of Android the authority might also be different. For example on my Nexus 5 the authority of the correct provider is com.android.launcher3.settings
.
Declaring the permissions is of course not a problem, but finding the correct ContentProvider
can prove difficult, fortunately there is a solution!
You first have to declare all the required permissions in the manifest like this:
<uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" />
<uses-permission android:name="com.android.launcher.permission.WRITE_SETTINGS" />
And after that we need to find the correct provider! You can do that by reading the PackageInfo
of all the installed apps and looping through all the ContentProviders
of each app. The ContentProvider
which has READ_SETTINGS
and WRITE_SETTINGS
as read and write permission is the one we are looking for. But we need a more complex logic to find the right one since the permissions are often based on the package name.
public static String findLauncherProviderAuthority(Context context) {
// Gets PackageInfo about all installed apps
final List<PackageInfo> packs = context.getPackageManager().getInstalledPackages(PackageManager.GET_PROVIDERS);
if (packs == null) {
return null;
}
for (PackageInfo pack : packs) {
// This gets the ProviderInfo of every ContentProvider in that app
final ProviderInfo[] providers = pack.providers;
if (providers == null) {
continue;
}
// This loops through the ContentProviders
for (ProviderInfo provider : providers) {
// And finally we look for the one with the correct permissions
// We use `startsWith()` and `endsWith()` since only the middle
// part might change
final String readPermission = provider.readPermission;
final String writePermission = provider.writePermission;
if(readPermission != null && writePermission != null) {
final boolean readPermissionMatches = readPermission.startsWith("com.android.") && readPermission.endsWith(".permission.READ_SETTINGS");
final boolean writePermissionMatches = writePermission.startsWith("com.android.") && writePermission.endsWith(".permission.WRITE_SETTINGS");
if(readPermissionMatches && writePermissionMatches) {
// And if we found the right one we return the authority
return provider.authority;
}
}
}
}
return null;
}
So this should very reliably return the correct ContentProvider
! You may want to tweak it a little more if you run into problems on some devices, but on all devices I could test it (and that's a lot of devices) it is working perfectly. You can use the method above like this:
final String authority = findLauncherProviderAuthority(getActivity());
final Uri uri = new Uri.Builder().scheme(CONTENT).authority(authority).appendPath(PATH).build();
...
I hope I could help you and if you have any further questions please feel free to ask!