Android 6.0 Launcher2源码分析之壁纸设置

极客导航  2018-06-20 20:05  阅读 86 次 评论 0 条


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

在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"  即可。

本文地址: https://www.125la.com/441.html
关注我们:请关注一下我们站长微信:扫描二维码125啦读书导航的微信号,微信号:yudemi(十三少)
版权声明:本文为原创或转载文章,版权归原作者所有,欢迎分享本文,转载请保留出处!
第一个读书导航

发表评论


表情