上回我们简单介绍了Launcher中的布局,这次我们看看如何设置壁纸。

Launcher2源码之壁纸设置

在Launcher界面,长按空白处,就会弹出如上图的壁纸设置对话框。

直接上代码Launcher.java

1. onCreate() 加载布局和初始化控件

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. ......
  4. //加载布局
  5. setContentView(R.layout.launcher);
  6. //初始化控件,并绑定
  7. setupViews(); //【2.0 初始化控件,同时设置长按监听事件】
  8. //显示第一次时的导航界面,,只是第一次才显示
  9. showFirstRunWorkspaceCling();
  10. ......
  11. }
复制

2.0 setupViews()初始化控件,同时设置长按监听事件

  1. /**
  2. * Finds all the views we need and configure them properly.
  3. */
  4. private void setupViews() {
  5. .....
  6. // Setup the workspace
  7. mWorkspace.setHapticFeedbackEnabled(false);
  8. mWorkspace.setOnLongClickListener(this); //长按事件监听
  9. mWorkspace.setup(dragController);
  10. dragController.addDragListener(mWorkspace);
  11. ......
  12. }
复制

mWorkspace设置了长按监听事件,因此如果是我们长按,就直接进入onLongClick()事件。

3.0 onLongClick() 长按事件响应

  1. /**
  2. * 长按workspace
  3. */
  4. public boolean onLongClick(View v) {
  5. //还加载资源或恢复时不允许拖拽
  6. if (!isDraggingEnabled()) return false;
  7. if (isWorkspaceLocked()) return false;
  8. if (mState != State.WORKSPACE) return false;
  9. if (!(v instanceof CellLayout)) {
  10. v = (View) v.getParent().getParent();
  11. }
  12. resetAddInfo();
  13. CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
  14. // This happens when long clicking an item with the dpad/trackball
  15. if (longClickCellInfo == null) {
  16. return true;
  17. }
  18. // The hotseat touch handling does not go through Workspace, and we always allow long press
  19. // on hotseat items.
  20. final View itemUnderLongClick = longClickCellInfo.cell;
  21. //只有hotset和workspace控件布局允许长按响应
  22. boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
  23. if (allowLongPress && !mDragController.isDragging()) {
  24. //此时长按的是非cellLayout部分,也就是空白处,长按响应设置壁纸,, 我们先关注壁纸设置
  25. if (itemUnderLongClick == null) {
  26. // User long pressed on empty space
  27. mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
  28. HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
  29. startWallpaper(); //【4.0 startWallpaper()】
  30. } else {
  31. //
  32. if (!(itemUnderLongClick instanceof Folder)) {
  33. // User long pressed on an item
  34. mWorkspace.startDrag(longClickCellInfo);
  35. }
  36. }
  37. }
  38. return true;
  39. }
复制

4.0 startWallpaper()

  1. private void startWallpaper() {
  2. showWorkspace(true);
  3. //查询过滤Intent.ACTION_SET_WALLPAPER的所有Activity
  4. final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
  5. Intent chooser = Intent.createChooser(pickWallpaper,
  6. getText(R.string.chooser_wallpaper));
  7. // NOTE: Adds a configure option to the chooser if the wallpaper supports it
  8. // Removed in Eclair MR1
  9. // WallpaperManager wm = (WallpaperManager)
  10. // getSystemService(Context.WALLPAPER_SERVICE);
  11. // WallpaperInfo wi = wm.getWallpaperInfo();
  12. // if (wi != null && wi.getSettingsActivity() != null) {
  13. // LabeledIntent li = new LabeledIntent(getPackageName(),
  14. // R.string.configure_wallpaper, 0);
  15. // li.setClassName(wi.getPackageName(), wi.getSettingsActivity());
  16. // chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, new Intent[] { li });
  17. // }
  18. startActivityForResult(chooser, REQUEST_PICK_WALLPAPER);
  19. }
复制

过滤所有在AndroidManifest.xml中过滤有如下条件的所有Activity。

  1. <intent-filter>
  2. <action android:name="android.intent.action.SET_WALLPAPER" />
  3. <category android:name="android.intent.category.DEFAULT" />
  4. </intent-filter>
复制

文章开头图片中就显示有两个Activity符合条件:动态壁纸和壁纸。

我在所有源码中查询了一下,发下如下应用符合条件

  1. packages/apps/Gallery/AndroidManifest.xml
  2. packages/apps/Gallery2/AndroidManifest.xml
  3. packages/apps/Launcher2/AndroidManifest.xml
  4. packages/apps/Launcher3/AndroidManifest.xml
复制

在这里我们不分析“动态壁纸”这个或许在Gallery或Gallery2中,懒得下载代码。而“壁纸”是在Launcher中的。我们看Launcher的AndroidManifest.xml中的配置

  1. <activity
  2. android:name="com.android.launcher2.WallpaperChooser"
  3. android:finishOnCloseSystemDialogs="true"
  4. android:icon="@mipmap/ic_launcher_wallpaper"
  5. android:label="@string/pick_wallpaper"
  6. android:process=":wallpaper_chooser"
  7. android:theme="@style/Theme.WallpaperPicker" >
  8. <intent-filter>
  9. <action android:name="android.intent.action.SET_WALLPAPER" />
  10. <category android:name="android.intent.category.DEFAULT" />
  11. </intent-filter>
  12. <meta-data
  13. android:name="android.wallpaper.preview"
  14. android:resource="@xml/wallpaper_picker_preview" />
  15. </activity>
复制

因此,点击“壁纸”就启动了com.android.launcher2.WallpaperChooser这个类,

  1. @Override
  2. public void onCreate(Bundle icicle) {
  3. super.onCreate(icicle);
  4. setContentView(R.layout.wallpaper_chooser_base);
  5. Fragment fragmentView =
  6. getFragmentManager().findFragmentById(R.id.wallpaper_chooser_fragment);
  7. // TODO: The following code is currently not exercised. Leaving it here in case it
  8. // needs to be revived again.
  9. if (fragmentView == null) {
  10. /* When the screen is XLarge, the fragment is not included in the layout, so show it
  11. * as a dialog
  12. */
  13. DialogFragment fragment = WallpaperChooserDialogFragment.newInstance(); //【5.0 启动WallpaperChooserDialogFragment.java】
  14. fragment.show(getFragmentManager(), "dialog");
  15. }
  16. }
复制

5.0 启动WallpaperChooserDialogFragment.java

WallpaperChooserDialogFragment继承DialogFragment,这个可以看上一篇摘抄的《[摘]DialogFragment 使用总结》,细节我就不在这里过多解释。

在这里就是查询xml中配置的条件,然后再加载对应的图片资源。

1. 发现和加载图片资源
  1. private void findWallpapers() {
  2. mThumbs = new ArrayList<Integer>(24); //缩略图
  3. mImages = new ArrayList<Integer>(24); //大图
  4. final Resources resources = getResources();
  5. // Context.getPackageName() may return the "original" package name,
  6. // com.android.launcher2; Resources needs the real package name,
  7. // com.android.launcher. So we ask Resources for what it thinks the
  8. // package name should be.
  9. final String packageName = resources
  10. .getResourcePackageName(R.array.wallpapers);//在value中配置好了对应的图片名字
  11. //加载资源
  12. addWallpapers(resources, packageName, R.array.wallpapers);
  13. addWallpapers(resources, packageName, R.array.extra_wallpapers);
  14. }
  15. private void addWallpapers(Resources resources, String packageName, int list) {
  16. final String[] extras = resources.getStringArray(list);
  17. for (String extra : extras) {
  18. int res = resources.getIdentifier(extra, "drawable", packageName);
  19. if (res != 0) {
  20. int thumbRes = resources.getIdentifier(extra + "_small",
  21. "drawable", packageName);
  22. // Log.d(TAG, "add: [" + packageName + "]: " + extra + " (res="
  23. // + res + " thumb=" + thumbRes + ")");
  24. if (thumbRes == 0) {
  25. Log.w(TAG, "warning: built-in wallpaper " + extra
  26. + " without " + extra + "_thumb");
  27. thumbRes = R.mipmap.ic_launcher_wallpaper;
  28. }
  29. mThumbs.add(thumbRes);
  30. mImages.add(res);
  31. }
  32. }
  33. }
复制
2. 预览壁纸

预览壁纸时是使用了AsyncTask进行加载大图,这样切换流畅。

  1. // Selection handler for the embedded Gallery view
  2. @Override
  3. public void onItemSelected(AdapterView<?> parent, View view, int position,
  4. long id) {
  5. if (mLoader != null
  6. && mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
  7. mLoader.cancel();
  8. }
  9. mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
  10. }
  11. class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
  12. WallpaperLoader() {
  13. }
  14. @Override
  15. protected Bitmap doInBackground(Integer... params) {
  16. if (isCancelled())
  17. return null;
  18. try {
  19. final Drawable d = getResources().getDrawable(
  20. mImages.get(params[0]));
  21. if (d instanceof BitmapDrawable) {
  22. return ((BitmapDrawable) d).getBitmap();
  23. }
  24. return null;
  25. } catch (OutOfMemoryError e) {
  26. Log.w(TAG, String.format(
  27. "Out of memory trying to load wallpaper res=%08x",
  28. params[0]), e);
  29. return null;
  30. }
  31. }
  32. @Override
  33. protected void onPostExecute(Bitmap b) {
  34. if (b == null)
  35. return;
  36. if (!isCancelled()) {
  37. View v = getView();
  38. if (v != null) {
  39. mWallpaperDrawable.setBitmap(b);
  40. v.postInvalidate();
  41. } else {
  42. mWallpaperDrawable.setBitmap(null);
  43. }
  44. mLoader = null;
  45. } else {
  46. b.recycle();
  47. }
  48. }
  49. void cancel() {
  50. super.cancel(true);
  51. }
  52. }
复制
3. 设置壁纸
  1. /**
  2. * 设置系统壁纸
  3. *
  4. * @param position
  5. */
  6. private void selectWallpaper(int position) {
  7. try {
  8. WallpaperManager wpm = (WallpaperManager) getActivity()
  9. .getSystemService(Context.WALLPAPER_SERVICE);
  10. wpm.setResource(mImages.get(position));
  11. Activity activity = getActivity();
  12. activity.setResult(Activity.RESULT_OK);
  13. activity.finish();
  14. } catch (IOException e) {
  15. Log.e(TAG, "Failed to set wallpaper: " + e);
  16. }
  17. }
复制

设置挺简单的,就直接设置下去就可以了。

如果你的应用背景也需要跟着壁纸换,你可以把Activity的主题设置为

android:theme=”@android:style/Theme.DeviceDefault.Wallpaper”或android:theme=”@android:style/Theme.DeviceDefault.Wallpaper.NoTitleBar”  即可。

相关文章

暂无评论

none
暂无评论...