Trying to access the LauncherProvider

别来无恙 提交于 2019-12-04 14:50:12

问题


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?


回答1:


Explanation of your problems

You are trying to access the LauncherProvider, but that may not be as easy you want. There are two main problems:

  1. 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.

  2. 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!


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!




回答2:


For my Nexus 5 device different permissions required

<uses-permission android:name="com.google.android.launcher.permission.READ_SETTINGS"/>
<uses-permission android:name="com.google.android.launcher.permission.WRITE_SETTINGS"/>

Above solution doesn't worked, until i changed that.

  if(readPermission != null && writePermission != null) {

      final boolean readPermissionMatches = readPermission.startsWith("com.") 
            && readPermission.endsWith(".permission.READ_SETTINGS");
     final boolean writePermissionMatches = writePermission.startsWith("com.") 
            && writePermission.endsWith(".permission.WRITE_SETTINGS");


来源:https://stackoverflow.com/questions/25060064/trying-to-access-the-launcherprovider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!