背景描述:
Google photo打开一张图片,点击设为、弹出提示框里选择photo,提示“发生错误,无法加载媒体”。
error,could not load media
问题分析
1、对比机同样操作,可以打开壁纸应用设置壁纸
2、其它对比机,打开Google photo自己的编辑图片界面,点击可以正常设置壁纸。
Log分析
Google相册里点击设为:
START u0 \{act=android.intent.action.CHOOSER flg=0x1 cmp=android/com.android.internal.app.ChooserActivity clip=\{image/jpeg \{...}} (has extras)} from uid 10211
弹出选择框后点击相册:
START u0 \{act=android.intent.action.ATTACH_DATA dat=content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/50/ORIGINAL/JPG/image/jpeg/380847275 typ=image/jpeg flg=0x3000001 cmp=com.google.android.apps.photos/.setwallpaper.SetWallpaperActivity (has extras)} from uid 10211
START u0 \{act=android.service.wallpaper.CROP_AND_SET_WALLPAPER dat=content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/50/ORIGINAL/JPG/image/jpeg/380847275 flg=0x1 pkg=com.google.android.apps.wallpaper cmp=com.google.android.apps.wallpaper/com.android.wallpaper.picker.StandalonePreviewActivity} from uid 10211
ActivityManager: Start proc 3437:com.google.android.apps.wallpaper/u0a241 for pre-top-activity \{com.google.android.apps.wallpaper/com.android.wallpaper.picker.StandalonePreviewActivity}
以上为Google pixel机器的log,如log显示,最终打开了com.google.android.apps.wallpaper Google自己的壁纸应用。
1、选择器界面为系统界面:android/com.android.internal.app.ChooserActivity
2、选择相册之后,可以看到一个action,裁剪并且设置壁纸 android.service.wallpaper.CROP_AND_SET_WALLPAPER可以看出是根据action和包类名去启动的界面
3.1、熟悉原生壁纸代码的话,可以很快意识到这个action是用来启动壁纸裁剪界面的
<activity android:name="com.android.wallpaper.picker.StandalonePreviewActivity"
android:resizeableActivity="false"
android:theme="@style/WallpaperTheme.Preview">
<intent-filter>
<action android:name="android.service.wallpaper.CROP_AND_SET_WALLPAPER" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="image/*" />
</intent-filter>
</activity>
3.2、设置壁纸的action
<activity android:name="com.android.wallpaper.picker.TopLevelPickerActivity"
android:label="@string/app_name"
android:theme="@style/WallpaperTheme.NoBackground"
android:resizeableActivity="false">
<intent-filter>
<action android:name="android.intent.action.SET_WALLPAPER"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
3.3、附加数据的action
Used to indicate that some piece of data should be attached to some other place. For example, image data could be attached to a contact. It is up to the recipient to decide where the data should be attached; the intent does not specify the ultimate destination.
Input: getData is URI of data to be attached.
Output: nothing
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ATTACH_DATA = "android.intent.action.ATTACH_DATA";
4、framework/base下面搜索CROP_AND_SET_WALLPAPER找到相关逻辑代码
frameworks/base/core/java/android/app/WallpaperManager.java
/**
* Gets an Intent that will launch an activity that crops the given
* image and sets the device's wallpaper. If there is a default HOME activity
* that supports cropping wallpapers, it will be preferred as the default.
* Use this method instead of directly creating a {@link #ACTION_CROP_AND_SET_WALLPAPER}
* intent.
*
* @param imageUri The image URI that will be set in the intent. The must be a content
* URI and its provider must resolve its type to "image/*"
*
* @throws IllegalArgumentException if the URI is not a content URI or its MIME type is
* not "image/*"
*/
public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
if (imageUri == null) {
throw new IllegalArgumentException("Image URI must not be null");
}
if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
throw new IllegalArgumentException("Image URI must be of the "
+ ContentResolver.SCHEME_CONTENT + " scheme type");
}
final PackageManager packageManager = mContext.getPackageManager();
Intent cropAndSetWallpaperIntent =
new Intent(ACTION_CROP_AND_SET_WALLPAPER, imageUri);
Log.d(TAG, "imageUri 111 : "+imageUri);
cropAndSetWallpaperIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Find out if the default HOME activity supports CROP_AND_SET_WALLPAPER
Intent homeIntent = new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME);
ResolveInfo resolvedHome = packageManager.resolveActivity(homeIntent,
PackageManager.MATCH_DEFAULT_ONLY);
if (resolvedHome != null) {
cropAndSetWallpaperIntent.setPackage(resolvedHome.activityInfo.packageName);
List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
cropAndSetWallpaperIntent, 0);
if (cropAppList.size() > 0) {
Log.w(TAG, "cropAndSetWallpaperIntent 111 : "+cropAndSetWallpaperIntent);
return cropAndSetWallpaperIntent;
}
}
// fallback crop activity
final String cropperPackage = mContext.getString(
com.android.internal.R.string.config_wallpaperCropperPackage);
cropAndSetWallpaperIntent.setPackage(cropperPackage);
List<ResolveInfo> cropAppList = packageManager.queryIntentActivities(
cropAndSetWallpaperIntent, 0);
if (cropAppList.size() > 0) {
Log.w(TAG, "cropAndSetWallpaperIntent 222 : "+cropAndSetWallpaperIntent);
return cropAndSetWallpaperIntent;
}
// If the URI is not of the right type, or for some reason the system wallpaper
// cropper doesn't exist, return null
throw new IllegalArgumentException("Cannot use passed URI to set wallpaper; " +
"check that the type returned by ContentProvider matches image/*");
}
原生的逻辑还是比较清晰的,
1、先看看homeIntent能否匹配到这个action(也就是看看launcher是否注册了这个action)
2、然后判断默认配置config_wallpaperCropperPackage的包名对应的应用是否有注册这个action(我们希望它走这里正常打开我们自己的壁纸界面,配置自己的壁纸应用包名即可)
3、如果都没有,最后Google photo会打开自己的壁纸编辑界面
5、配置路径和其它壁纸相关的配置
frameworks/base/core/res/res/values/config.xml
<!-- Component name of the built in wallpaper used to display bitmap wallpapers. This must not be null. -->
<string name="image_wallpaper_component" translatable="false">com.android.systemui/com.android.systemui.ImageWallpaper</string>
<!-- Class name of WallpaperManagerService. -->
<string name="config_wallpaperManagerServiceName" translatable="false">com.android.server.wallpaper.WallpaperManagerService</string>
<!-- If AOD can show an ambient version of the wallpaper -->
<bool name="config_dozeSupportsAodWallpaper">true</bool>
<!-- Wallpaper cropper package. Used as the default cropper if the active launcher doesn't
handle wallpaper cropping.
-->
<string name="config_wallpaperCropperPackage" translatable="false">com.android.wallpaperpicker</string>
<!-- The max scale for the wallpaper when it's zoomed in -->
<item name="config_wallpaperMaxScale" format="float" type="dimen">1.10</item>
6、如果是mtk平台,会有覆盖路径
device/mediatek/common/overlay/wallpaper/frameworks/base/core/res/res/values/config.xml
device/mediatek/system/common/overlay/wallpaper/frameworks/base/core/res/res/values/config.xml