Launcher2源码之壁纸设置

Android  源码分析  2018年6月20日 pm8:05发布6年前 (2018)更新 91es.com站长
69 0 0


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

Launcher2源码之壁纸设置

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

直接上代码Launcher.java

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

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       ......
      //加载布局
        setContentView(R.layout.launcher);

        //初始化控件,并绑定
        setupViews();  //【2.0 初始化控件,同时设置长按监听事件】
        //显示第一次时的导航界面,,只是第一次才显示
        showFirstRunWorkspaceCling();
      ......
   }

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

    /**
     * Finds all the views we need and configure them properly.
     */
    private void setupViews() {
        .....
        // Setup the workspace
        mWorkspace.setHapticFeedbackEnabled(false);
        mWorkspace.setOnLongClickListener(this); //长按事件监听
        mWorkspace.setup(dragController);
        dragController.addDragListener(mWorkspace);
        ......
    }

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

3.0 onLongClick() 长按事件响应

    /**
     * 长按workspace
     */
    public boolean onLongClick(View v) {
    	//还加载资源或恢复时不允许拖拽
        if (!isDraggingEnabled()) return false;
        if (isWorkspaceLocked()) return false;
        if (mState != State.WORKSPACE) return false;

        if (!(v instanceof CellLayout)) {
            v = (View) v.getParent().getParent();
        }

        resetAddInfo();
        CellLayout.CellInfo longClickCellInfo = (CellLayout.CellInfo) v.getTag();
        // This happens when long clicking an item with the dpad/trackball
        if (longClickCellInfo == null) {
            return true;
        }

        // The hotseat touch handling does not go through Workspace, and we always allow long press
        // on hotseat items.
        final View itemUnderLongClick = longClickCellInfo.cell;
        //只有hotset和workspace控件布局允许长按响应
        boolean allowLongPress = isHotseatLayout(v) || mWorkspace.allowLongPress();
        if (allowLongPress && !mDragController.isDragging()) {
        	//此时长按的是非cellLayout部分,也就是空白处,长按响应设置壁纸,, 我们先关注壁纸设置
            if (itemUnderLongClick == null) {
                // User long pressed on empty space
                mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS,
                        HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
                startWallpaper(); //【4.0 startWallpaper()】
            } else {
            	//
                if (!(itemUnderLongClick instanceof Folder)) {
                    // User long pressed on an item
                    mWorkspace.startDrag(longClickCellInfo);
                }
            }
        }
        return true;
    }

4.0 startWallpaper()

    private void startWallpaper() {
        showWorkspace(true);
        //查询过滤Intent.ACTION_SET_WALLPAPER的所有Activity
        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);
    }

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

<intent-filter>
       <action android:name="android.intent.action.SET_WALLPAPER" />
       <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

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

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

packages/apps/Gallery/AndroidManifest.xml
packages/apps/Gallery2/AndroidManifest.xml
packages/apps/Launcher2/AndroidManifest.xml
packages/apps/Launcher3/AndroidManifest.xml

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

        <activity
            android:name="com.android.launcher2.WallpaperChooser"
            android:finishOnCloseSystemDialogs="true"
            android:icon="@mipmap/ic_launcher_wallpaper"
            android:label="@string/pick_wallpaper"
            android:process=":wallpaper_chooser"
            android:theme="@style/Theme.WallpaperPicker" >
            <intent-filter>
                <action android:name="android.intent.action.SET_WALLPAPER" />

                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <meta-data
                android:name="android.wallpaper.preview"
                android:resource="@xml/wallpaper_picker_preview" />
        </activity>

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

    @Override
    public void onCreate(Bundle icicle) {
        super.onCreate(icicle);
        setContentView(R.layout.wallpaper_chooser_base);

        Fragment fragmentView =
                getFragmentManager().findFragmentById(R.id.wallpaper_chooser_fragment);
        // TODO: The following code is currently not exercised. Leaving it here in case it
        // needs to be revived again.
        if (fragmentView == null) {
            /* When the screen is XLarge, the fragment is not included in the layout, so show it
             * as a dialog
             */
            DialogFragment fragment = WallpaperChooserDialogFragment.newInstance(); //【5.0 启动WallpaperChooserDialogFragment.java】
            fragment.show(getFragmentManager(), "dialog");
        }
    }

5.0 启动WallpaperChooserDialogFragment.java

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

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

1. 发现和加载图片资源
	private void findWallpapers() {
		mThumbs = new ArrayList<Integer>(24); //缩略图
		mImages = new ArrayList<Integer>(24); //大图

		final Resources resources = getResources();
		// Context.getPackageName() may return the "original" package name,
		// com.android.launcher2; Resources needs the real package name,
		// com.android.launcher. So we ask Resources for what it thinks the
		// package name should be.
		final String packageName = resources
				.getResourcePackageName(R.array.wallpapers);//在value中配置好了对应的图片名字
                //加载资源
		addWallpapers(resources, packageName, R.array.wallpapers);
		addWallpapers(resources, packageName, R.array.extra_wallpapers);
	}

	private void addWallpapers(Resources resources, String packageName, int list) {
		final String[] extras = resources.getStringArray(list);
		for (String extra : extras) {
			int res = resources.getIdentifier(extra, "drawable", packageName);
			if (res != 0) {
				int thumbRes = resources.getIdentifier(extra + "_small",
						"drawable", packageName);

				// Log.d(TAG, "add: [" + packageName + "]: " + extra + " (res="
				// + res + " thumb=" + thumbRes + ")");
				if (thumbRes == 0) {
					Log.w(TAG, "warning: built-in wallpaper " + extra
							+ " without " + extra + "_thumb");
					thumbRes = R.mipmap.ic_launcher_wallpaper;
				}
				mThumbs.add(thumbRes);
				mImages.add(res);
			}
		}
	}
2. 预览壁纸

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

	// Selection handler for the embedded Gallery view
	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int position,
			long id) {
		if (mLoader != null
				&& mLoader.getStatus() != WallpaperLoader.Status.FINISHED) {
			mLoader.cancel();
		}
		mLoader = (WallpaperLoader) new WallpaperLoader().execute(position);
	}

	class WallpaperLoader extends AsyncTask<Integer, Void, Bitmap> {
		WallpaperLoader() {
		}

		@Override
		protected Bitmap doInBackground(Integer... params) {
			if (isCancelled())
				return null;
			try {
				final Drawable d = getResources().getDrawable(
						mImages.get(params[0]));
				if (d instanceof BitmapDrawable) {
					return ((BitmapDrawable) d).getBitmap();
				}
				return null;
			} catch (OutOfMemoryError e) {
				Log.w(TAG, String.format(
						"Out of memory trying to load wallpaper res=%08x",
						params[0]), e);
				return null;
			}
		}

		@Override
		protected void onPostExecute(Bitmap b) {
			if (b == null)
				return;

			if (!isCancelled()) {
				View v = getView();
				if (v != null) {
					mWallpaperDrawable.setBitmap(b);
					v.postInvalidate();
				} else {
					mWallpaperDrawable.setBitmap(null);
				}
				mLoader = null;
			} else {
				b.recycle();
			}
		}

		void cancel() {
			super.cancel(true);
		}
	}
3. 设置壁纸
	/**
	 * 设置系统壁纸
	 *
	 * @param position
	 */
	private void selectWallpaper(int position) {
		try {
			WallpaperManager wpm = (WallpaperManager) getActivity()
					.getSystemService(Context.WALLPAPER_SERVICE);
			wpm.setResource(mImages.get(position));
			Activity activity = getActivity();
			activity.setResult(Activity.RESULT_OK);
			activity.finish();
		} catch (IOException e) {
			Log.e(TAG, "Failed to set wallpaper: " + e);
		}
	}

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

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

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

 历史上的今天

  1. 2024: Files中启动自己的播放器(0条评论)
  2. 2024: 朱自清:窗前的树(0条评论)
  3. 2022: JAVA 从一个List里删除包含另一个List的数据(0条评论)
  4. 2020: 常用的Monkey命令(0条评论)
版权声明 1、 本站名称: 91易搜
2、 本站网址: 91es.com3xcn.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

Android解析lrc文件代码片段

前言简单记录一下解析本地lrc文件中的文件代码。方便自己查阅。流水文,跳过吧。正文解析歌词分两种,一种是歌曲中内置的,另外一种是外置的。这里介绍外置的歌词,以常见的lrc歌词为例,也是比较简单的一种歌词文件。下面是项目中用的,涉及到文本编码格式的判断等。隐藏内容!付费阅读后才能查...

关闭Android Studio自带的模拟器

前言在Android Studio中打开自带的谷歌模拟器后,不管是点击关闭按钮,还是按Power键,都无法完全的把Android模拟器关闭。然后谷歌之后才发现需要命令才可以彻底关闭。记录一下,方便自己查阅。正文解决方法很简单,就是终端(我这里是cmd)中输入下面命令adb emu ki...

狄兰·托马斯:不要温和地走进那个良夜

不要温和地走进那个良夜,老年应当在日暮时燃烧咆哮;怒斥,怒斥光明的消逝。虽然智慧的人临终时懂得黑暗有理,因为他们的话没有迸发出闪电,他们也并不温和地走进那个良夜。善良的人,当最后一浪过去,高呼他们脆弱的善行可能曾会多么光辉地在绿色的海湾里舞蹈,怒斥,怒斥光明的消逝。狂暴的人抓住并歌唱过...

Android存储单位转换

G M K B 单位之间转换,直接上代码 // storage, G M K B public static String convertStorage(long size) { long kb = 1024; long mb = kb <...

个人常用ADB命令总结

获取Android系统版本adb shell getprop ro.build.version.release获取IP地址adb shell ifconfig | grep Mask获取屏幕密度adb shell wm density//修改density 后面直接带值即可ad...

彼得.B.巴赫:失去爱人的滋味

布宜诺斯艾利斯的街灯要比纽约的街灯暗得多,这是我们在阿根廷的半年里最深刻的体会。我们租用的车子老旧,车身落满了这座城市的灰尘,前挡风玻璃更加遮蔽了射进来的光。当我们驾车离开当地医院,在第一个路口等红灯时,我打破了我对露丝许下的两个最重要的结婚誓言:第一,我以一个医生的口吻和她说了话;第二,我欺骗了她...