公司某产品性能有限,需要屏蔽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" />