Launcher2源码之壁纸设置

Android  源码分析  2018年6月20日 pm8:05发布7年前 (2018)更新 91es.com站长
96 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.com
3、 本站内容: 部分来源于网络,仅供学习和参考,若侵权请留言
3、 本站申明: 个人流水账日记,内容并不保证有效

暂无评论

暂无评论...

随机推荐

mediaserver的启动

前言之前介绍MediaPlayer的使用,上次写过《MediaPlayer JNI层介绍》,发现很多方法都是都是# //BpMediaPlayer.prepareAsync()mPlayer->start()调用,而且BpMediaPlayer也只是代理而已,真正调用的还是另有其人。...

Android反编译之vdex转dex查看源码

前言最近获取到客户Apk(客户版本Android 9)后使用工具没法看到源代码,system/priv-app/Media目录结构如下:C:.└─oat └─arm64 ├─Media.odex └─Media.vdex└─Media.apk...

adb shell 发送广播带包名

前言之前我们知道adb发送广播带参数,但是有于Android的权限慢慢收紧,如果不加上接收应用的包名,无法收到发送的静态广播。Android 8.0Beginning with Android 8.0 (API level 26), the system imposes additiona...

Android双屏异显(Presentation)的简单使用

前言Android 从4.2开始支持双屏显示,支持版本为17以上。Android 双屏原理说白了,自定义一个Presentation类,Android 的标准实现是使用 API Presentation 来实现异显的功能。public class Presentation extends D...

Android静态换肤-日夜主题切换之继承Activity记录

前言记录一下,有Activity换肤之日夜主题无缝切换。一般来说,换肤分为静态换肤和动态换肤,Android的日夜模式可以看做静态换肤的一种。是以资源存放位置来说的,其实不是很严谨,但换肤的本质都是一样的。正文Android高版本都支持日夜模式切换,资源放在对应日夜目录,比如...

C语言中的malloc、calloc和free函数的使用

前言记录C语言中内存分配的使用。正文C语言中不允许动态分配数组,这样就存在内容长度的变化导致存储越界问题。malloc函数的使用调用形式(类型说明符 * ) malloc(size);分配长度为size的连续区域,函数返回的是搞区域的首地址。举个例子:普通类型char *p;...