公司某产品性能有限,需要屏蔽live wallpapers防止内存使用量过大影响客户体验,于是按照经验在Launcher2目录寻找设置壁纸对话框对应的代码,前一个"Add to Home screen"Dialog对象创建位置轻松找到,在Launcher.java中有如下代码:
if (mWorkspace.allowLongPress()) {
if (cellInfo.cell == null) {
if (cellInfo.valid) {
// User long pressed on empty space
mWorkspace.setAllowLongPress(false);
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
showAddDialog(cellInfo);
}
} else {
if (!(cellInfo.cell instanceof Folder)) {
// User long pressed on an item
mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mWorkspace.startDrag(cellInfo);
}
}
}
继续寻找showAddDialog(cellInfo):
private void showAddDialog(CellLayout.CellInfo cellInfo) {
mAddItemCellInfo = cellInfo;
mWaitingForResult = true;
showDialog(DIALOG_CREATE_SHORTCUT);
}
代码携带参数跳入Launcher.java的父类Activity.java的showDialog()方法,在Activity.java源码中查找,发现接下来将会跳入Launcher.java的onCreateDialog(int id)方法,代码如下:
@Override
protected Dialog onCreateDialog(int id) {
switch (id) {
case DIALOG_CREATE_SHORTCUT:
return new CreateShortcut().createDialog();
case DIALOG_RENAME_FOLDER:
return new RenameFolder().createDialog();
}
return super.onCreateDialog(id);
}
显然,这里return 的是case DIALOG_CREATE_SHORTCUT,再进入私有类CreateShortcut
Dialog createDialog() {
mWaitingForResult = true;
mAdapter = new AddAdapter(Launcher.this);
final AlertDialog.Builder builder = new AlertDialog.Builder(Launcher.this);
builder.setTitle(getString(R.string.menu_item_add_item));
builder.setAdapter(mAdapter, this);
builder.setInverseBackgroundForced(true);
AlertDialog dialog = builder.create();
dialog.setOnCancelListener(this);
dialog.setOnDismissListener(this);
dialog.setOnShowListener(this);
return dialog;
}
至此,看到了第一个"Add to Home screen"Dialog的初始化位置,进入AddAdapter的构造器,里面有如下代码:
mItems.add(new ListItem(res, R.string.group_shortcuts,
R.drawable.ic_launcher_shortcut, ITEM_SHORTCUT));
mItems.add(new ListItem(res, R.string.group_widgets,
R.drawable.ic_launcher_appwidget, ITEM_APPWIDGET));
mItems.add(new ListItem(res, R.string.group_live_folders,
R.drawable.ic_launcher_folder, ITEM_LIVE_FOLDER));
mItems.add(new ListItem(res, R.string.group_wallpapers,
R.drawable.ic_launcher_wallpaper, ITEM_WALLPAPER));
如果要对"Add to Home screen"对话框下手,此处正当其位.
然而,我的目标却不是它,继续往下走,郁闷的事情发生了,在"Add to Home screen"Dialog的ItemClick事件处理中,只有如下代码:
case AddAdapter.ITEM_WALLPAPER: {
startWallpaper();
break;
再看startWallpaper()方法
private void startWallpaper() {
closeAllApps(true);
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
Intent chooser = Intent.createChooser(pickWallpaper,
getText(R.string.chooser_wallpaper));
// NOTE: Adds a configure option to the chooser if the wallpaper supports it
// Removed in Eclair MR1
// WallpaperManager wm = (WallpaperManager)
// getSystemService(Context.WALLPAPER_SERVICE);
// WallpaperInfo wi = wm.getWallpaperInfo();
// if (wi != null && wi.getSettingsActivity() != null) {
// LabeledIntent li = new LabeledIntent(getPackageName(),
// R.string.configure_wallpaper, 0);
// li.setClassName(wi.getPackageName(), wi.getSettingsActivity());
// chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { li });
// }
startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);
}
由于对Intent的粗浅了解,很自然的,我直奔Launcher中注册有ACTION_SET_WALLPAPER的Activity--WallpaperChooser.java,悲剧的是,迎接我的,却是选择壁纸的初始化界面...
另一个dialog的初始化代码神秘的消失了...
我跳到Launcher的资源文件目录,想从strings.xml和drawable中找到第二个对话框引用的资源文件,然后所有资源名,找到加载资源的代码,但是,一个都没找到.....反倒在package目录的Wallpaper中找到.
百思不得其解折腾了一小时后,郁闷的上洗手间的时候我终于想到了它的原理:
原来,这第二个dialog并不属于Launcher应用,而是系统接收到这个叫chooser的intent后,查找所有能匹配的Activity得到结果,第二个dialog中的图片文字,在launcher的资源文件中也是没有的,这也是我在Launcher的strings.xml找不到线索的原因.幽默的是,我上洗手间之前,决定删除live Wallpaper对应的apk源码做尝试,而实际上,这就是切合原理的解决之道,而不会引起异常,当然,还有另一种方法,修改live wallpaper应用的intent注册内容也可以做到.
下午复查了下所有wallpaper app,果然都有
<action android:name="android.intent.action.SET_WALLPAPER" />