您的位置:首页 > 移动开发 > Android开发

Launcher3--壁纸

2016-07-05 18:11 134 查看
    在说Launcher上设置壁纸时,首先需要弄清楚的是,壁纸的设置属于系统行为,而不是Launcher的应用特性。在Launcher中,壁纸的设置最终也是通过调用系统壁纸设置接口来完成的,所有,不仅仅是Launcher,很多第三方应用也是可以设置壁纸的。
    Android中,可以使用WallpaperManager这一壁纸管理类来设置壁纸,有如下几种方法,



 
  我们可以根据壁纸资源的不同,选择合适的方法,其中,最后一个可以用来设置动态壁纸。

 
  下面就来说说Launcher3中是如何设置壁纸的,我们直接从壁纸设置界面的入口说起,

/**
* Event handler for the wallpaper picker button that appears after a long press
* on the home screen.
*/
protected void onClickWallpaperPicker(View v) {
if (LOGD) Log.d(TAG, "onClickWallpaperPicker");
final Intent pickWallpaper = new Intent(Intent.ACTION_SET_WALLPAPER);
pickWallpaper.setComponent(getWallpaperPickerComponent());
startActivityForResult(pickWallpaper, REQUEST_PICK_WALLPAPER);

if (mLauncherCallbacks != null) {
mLauncherCallbacks.onClickWallpaperPicker(v);
}
}
protected ComponentName getWallpaperPickerComponent() {
if (mLauncherCallbacks != null) {
return mLauncherCallbacks.getWallpaperPickerComponent();
}
return new ComponentName(getPackageName(), LauncherWallpaperPickerActivity.class.getName());
}
 
  很显然,LauncherWallpaperPickerActivity就是壁纸设置界面了,LauncherWallpaperPickerActivity继承于WallpaperPickerActivity,WallpaperPickerActivity又继承于WallpaperCropActivity,这么多继承,看来这个界面还是比较复杂的。从命名来看的话,也是为了区分每个类的处理重点,WallpaperCropActivity用来进行壁纸的裁剪,将图片裁剪到合适的尺寸;WallpaperPickerActivity就是壁纸选择器,选择壁纸并设置;至于LauncherWallpaperPickerActivity,从代码中看到只是重写了父类的两个方法,没什么可分析的,这里我们重点分析WallpaperPickerActivity这个类。
一、壁纸类型对象
    作为内部类,定义在WallpaperPickerActivity类中,
public static abstract class WallpaperTileInfo {
protected View mView;
public Drawable mThumb;

public void setView(View v) {
mView = v;
}
public void onClick(WallpaperPickerActivity a) {}// 缩略图点击事件
public void onSave(WallpaperPickerActivity a) {}// 设置壁纸,并做一些保存操作
public void onDelete(WallpaperPickerActivity a) {}// 删除壁纸
public boolean isSelectable() { return false; }// 是否可选
public boolean isNamelessWallpaper() { return false; }// 壁纸是否没有名字
public void onIndexUpdated(CharSequence label) {// 更新索引
if (isNamelessWallpaper()) {
mView.setContentDescription(label);
}
}
}
 
  壁纸对象的一个抽象类,不直接使用,具体的壁纸继承该类并根据自身特点扩展。壁纸来源有多个途径,如应用内置的壁纸、图库、第三方等,另外设为壁纸的方式也不一定相同,需要对不同来源区分处理,所有就定义了以下几个壁纸类对象,

PickImageInfo--图片选择器,在Activity中添加属性<action android:name="android.intent.action.GET_CONTENT" />,就可以隐式调用到,如图库

UriWallpaperInfo--通过图片的Uri来设置壁纸

FileWallpaperInfo--通过图片文件来设置壁纸

ResourceWallpaperInfo--Launcher3中内置的壁纸资源来设置

DefaultWallpaperInfo--系统默认壁纸,资源在framework中

    这几个类实现其抽象父类中的方法,具体代码实现就不一一细说,后面说到具体方法时会举其中的例子来说明,这里对几个抽象方法已经做了注释。

二、加载壁纸列表
    图1是壁纸设置界面,界面简单,包含了壁纸列表、设置壁纸按钮以及壁纸预览图等。



图1
 
  WallpaperPickerActivity中没有重写onCreate方法,而是通过父类的onCreate的方法调用了重写的init方法,进行布局的加载和初始化。

1、布局

<?xml version="1.0" encoding="utf-8"?><!--
/*
**
** Copyright 2013, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
** You may obtain a copy of the License at
**
**     http://www.apache.org/licenses/LICENSE-2.0 **
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
-->

<com.android.launcher3.WallpaperRootView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/wallpaper_root"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.android.launcher3.CropView
android:id="@+id/cropView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<ProgressBar
android:id="@+id/loading"
style="@android:style/Widget.Holo.ProgressBar.Large"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@android:color/transparent"
android:indeterminate="true"
android:indeterminateOnly="true"
android:visibility="invisible" />

<LinearLayout
android:id="@+id/wallpaper_strip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:orientation="vertical">

<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@drawable/tile_shadow_top" />

<HorizontalScrollView
android:id="@+id/wallpaper_scroll_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">

<LinearLayout
android:id="@+id/master_wallpaper_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">

<LinearLayout
android:id="@+id/wallpaper_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />

<LinearLayout
android:id="@+id/live_wallpaper_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />

<LinearLayout
android:id="@+id/third_party_wallpaper_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" />
</LinearLayout>
</HorizontalScrollView>

<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@drawable/tile_shadow_bottom" />
</LinearLayout>
</com.android.launcher3.WallpaperRootView>

WallpaperRootView是根视图,继承RelativeLayout自定义的一个视图,重写了fitSystemWindows方法,

protected boolean fitSystemWindows(Rect insets) {
a.setWallpaperStripYOffset(insets.bottom);
return true;
}
    这么做的目的是为了让视图内离底部一段距离,否则会出现如图2的情况,跟虚拟键重合,就不大美观了。



图2
setContentView(R.layout.wallpaper_picker);

mCropView = (CropView) findViewById(R.id.cropView);
mCropView.setVisibility(View.INVISIBLE);// 默认是不可见的

mWallpaperStrip = findViewById(R.id.wallpaper_strip);

1)CropView--裁剪视图,用于壁纸的裁剪、预览,还有手势操作(两个手指缩放)。

2)进度条--加载该界面时的进度条。

3)壁纸列表--LinearLayout布局块,其中的子视图HorizontalScrollView是一个横向的滑动视图,就是我们的壁纸列表,也是根据壁纸类型的分了多个布局块,分别加载。


好像还少了ActionBar,这个是在代码中动态添加的,下面会说到。


2、接口回调和监听事件
mCropView.setTouchCallback(new CropView.TouchCallback() {
ViewPropertyAnimator mAnim;
@Override
public void onTouchDown() {
if (mAnim != null) {
mAnim.cancel();
}
if (mWallpaperStrip.getAlpha() == 1f) {
mIgnoreNextTap = true;
}
mAnim = mWallpaperStrip.animate();
mAnim.alpha(0f)
.setDuration(150)
.withEndAction(new Runnable() {
public void run() {
mWallpaperStrip.setVisibility(View.INVISIBLE);
}
});
mAnim.setInterpolator(new AccelerateInterpolator(0.75f));
mAnim.start();
}
@Override
public void onTouchUp() {
mIgnoreNextTap = false;
}
@Override
public void onTap() {
boolean ignoreTap = mIgnoreNextTap;
mIgnoreNextTap = false;
if (!ignoreTap) {
if (mAnim != null) {
mAnim.cancel();
}
mWallpaperStrip.setVisibility(View.VISIBLE);
mAnim = mWallpaperStrip.animate();
mAnim.alpha(1f)
.setDuration(150)
.setInterpolator(new DecelerateInterpolator(0.75f));
mAnim.start();
}
}
});

CropView的touch回调处理,这里只做了一些动画效果,具体裁剪的操作还是在CropView中实现的,这里就不详细说明了。

mThumbnailOnClickListener = new OnClickListener() {
public void onClick(View v) {
if (mActionMode != null) {
// When CAB is up, clicking toggles the item instead
if (v.isLongClickable()) {
mLongClickListener.onLongClick(v);
}
return;
}
mSetWallpaperButton.setEnabled(true);
WallpaperTileInfo info = (WallpaperTileInfo) v.getTag();
if (info.isSelectable() && v.getVisibility() == View.VISIBLE) {
selectTile(v);
}
info.onClick(WallpaperPickerActivity.this);// 缩略图点击事件
}
};

缩略图点击事件,如果处于ActionMode(长按事件),处理长按事件,否则回调该壁纸所实现的onClick方法,启用mSetWallpaperButton,该控件定义在其父类WallpaperCropActivity中,
// Action bar
// Show the custom action bar view
final ActionBar actionBar = getActionBar();
actionBar.setCustomView(R.layout.actionbar_set_wallpaper);
actionBar.getCustomView().setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
boolean finishActivityWhenDone = true;
cropImageAndSetWallpaper(imageUri, null, finishActivityWhenDone);
}
});
mSetWallpaperButton = findViewById(R.id.set_wallpaper_button);


mLongClickListener = new View.OnLongClickListener() {
// Called when the user long-clicks on someView
public boolean onLongClick(View view) {
CheckableFrameLayout c = (CheckableFrameLayout) view;
c.toggle();
if (mActionMode != null) {
mActionMode.invalidate();
} else {
// Start the CAB using the ActionMode.Callback defined below
mActionMode = startActionMode(mActionModeCallback);
int childCount = mWallpapersView.getChildCount();
for (int i = 0; i < childCount; i++) {
mWallpapersView.getChildAt(i).setSelected(false);
}
}
return true;
}
};

定义了缩略图长按事件,并不是所有的壁纸类型都设置了长按事件,下面会讲到。


3、获取壁纸资源,将缩略图加载到横向scrollview

    1)添加Launcher3中内置的壁纸资源和系统默认壁纸

// Populate the built-in wallpapers
// 填充内置壁纸,资源文件配置的壁纸和系统默认壁纸
ArrayList<WallpaperTileInfo> wallpapers = findBundledWallpapers();
mWallpapersView = (LinearLayout) findViewById(R.id.wallpaper_list);
SimpleWallpapersAdapter ia = new SimpleWallpapersAdapter(this, wallpapers);
populateWallpapersFromAdapter(mWallpapersView, ia, false);
 
  通过findBundledWallpapers来查找壁纸,
private ArrayList<WallpaperTileInfo> findBundledWallpapers() {
final PackageManager pm = getPackageManager();
final ArrayList<WallpaperTileInfo> bundled = new ArrayList<WallpaperTileInfo>(24);

Partner partner = Partner.get(pm);
if (partner != null) {
final Resources partnerRes = partner.getResources();
final int resId = partnerRes.getIdentifier(Partner.RES_WALLPAPERS, "array",
partner.getPackageName());
if (resId != 0) {
addWallpapers(bundled, partnerRes, partner.getPackageName(), resId);
}

// Add system wallpapers
File systemDir = partner.getWallpaperDirectory();
if (systemDir != null && systemDir.isDirectory()) {
for (File file : systemDir.listFiles()) {
if (!file.isFile()) {
continue;
}
String name = file.getName();
int dotPos = name.lastIndexOf('.');
String extension = "";
if (dotPos >= -1) {
extension = name.substring(dotPos);
name = name.substring(0, dotPos);
}

if (name.endsWith("_small")) {
// it is a thumbnail
continue;
}

File thumbnail = new File(systemDir, name + "_small" + extension);
Bitmap thumb = BitmapFactory.decodeFile(thumbnail.getAbsolutePath());
if (thumb != null) {
bundled.add(new FileWallpaperInfo(file, new BitmapDrawable(thumb)));
}
}
}
}

// 添加Launcher中配置的壁纸
Pair<ApplicationInfo, Integer> r = getWallpaperArrayResourceId();
if (r != null) {
try {
Resources wallpaperRes = getPackageManager().getResourcesForApplication(r.first);
addWallpapers(bundled, wallpaperRes, r.first.packageName, r.second);
} catch (PackageManager.NameNotFoundException e) {
}
}

// 创建一个空的实体,用于放置默认壁纸
if (partner == null || !partner.hideDefaultWallpaper()) {
// Add an entry for the default wallpaper (stored in system resources)
WallpaperTileInfo defaultWallpaperInfo =
(Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
? getPreKKDefaultWallpaperInfo()
: getDefaultWallpaper();
if (defaultWallpaperInfo != null) {
bundled.add(0, defaultWallpaperInfo);
}
}
return bundled;
}

    加载系统中有监听特定广播的应用中的资源,这个广播是"com.android.launcher3.action.PARTNER_CUSTOMIZATION"
    加载Launcher3中配置的壁纸,这些壁纸放在drawable-xxx目录下,并在wallpapers.xml中配置(必须有原图和缩略图)
<resources>
<string-array name="wallpapers" translatable="false">
<!-- This special drawable references the platform's private
default_wallpaper resource so the user can always choose it. -->
<item>zzz_wallpaper</item>
<item>zzz_wallpaper_small</item>
<!-- If you want additional bitmap drawable resources to appear in the
wallpaper picker, add them to this list. For each foo.jpg be sure
to include a foo_small.jpg to be used as a thumbnail in the
scrolling gallery widget. -->
</string-array>
</resources>
    加载默认壁纸,默认壁纸放在framework资源目录下
    这样就获取到壁纸列表,定义适配器,通过populateWallpapersFromAdapter方法将其显示,

private void populateWallpapersFromAdapter(ViewGroup parent, BaseAdapter adapter,
boolean addLongPressHandler) {
for (int i = 0; i < adapter.getCount(); i++) {
FrameLayout thumbnail = (FrameLayout) adapter.getView(i, null, parent);
parent.addView(thumbnail, i);
WallpaperTileInfo info = (WallpaperTileInfo) adapter.getItem(i);
thumbnail.setTag(info);
info.setView(thumbnail);
if (addLongPressHandler) {// 是否添加长按事件,只对数据库中保存的壁纸处理
addLongPressHandler(thumbnail);
}
thumbnail.setOnClickListener(mThumbnailOnClickListener);
}
}
 
  这个方法比较好理解,需要注意的是第三个参数,这个布尔值用来确定该类型壁纸是否添加长按事件,这里是false,不添加;根据后面的分析来看,也只有保存在数据库中的壁纸添加该操作,这也好理解,因为其他几种类型都不是用户自己定义的,不允许删除壁纸,长按操作就是用来删除该壁纸的。

 
  2)添加保存在数据库中的壁纸


// Populate the saved wallpapers
// 填充保存在数据库中的壁纸
mSavedImages = new SavedWallpaperImages(this);
mSavedImages.loadThumbnailsAndImageIdList();
populateWallpapersFromAdapter(mWallpapersView, mSavedImages, true);
    3)添加动态壁纸
// Populate the live wallpapers
// 填充动态壁纸
final LinearLayout liveWallpapersView =
(LinearLayout) findViewById(R.id.live_wallpaper_list);
final LiveWallpaperListAdapter a = new LiveWallpaperListAdapter(this);
a.registerDataSetObserver(new DataSetObserver() {
public void onChanged() {
liveWallpapersView.removeAllViews();
populateWallpapersFromAdapter(liveWallpapersView, a, false);
initializeScrollForRtl();
updateTileIndices();
}
});

    在Android中,除了可以显示静态壁纸外,也可以使用动态壁纸。当然,跟普通的壁纸不同的是,它是已apk的形式安装到手机中的(至于怎么制作一个动态壁纸的apk,不是我们这边所讲的,就不阐述了),加载动态壁纸就是要查找系统中已安装的动态壁纸应用。
    动态壁纸也定义了一个适配器类LiveWallpaperListAdapter,定义动态壁纸对象,查找动态壁纸应用等。
public LiveWallpaperListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPackageManager = context.getPackageManager();

List<ResolveInfo> list = mPackageManager.queryIntentServices(
new Intent(WallpaperService.SERVICE_INTERFACE),
PackageManager.GET_META_DATA);

mWallpapers = new ArrayList<LiveWallpaperTile>();

new LiveWallpaperEnumerator(context).execute(list);
}
    这是构造方法,查询action为"android.service.wallpaper.WallpaperService"的service,这是动态壁纸应用中必须配置的,如果我们自己想做一个动态壁纸也是要添加这个action的。
public static class LiveWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {
private Drawable mThumbnail;
private WallpaperInfo mInfo;
public LiveWallpaperTile(Drawable thumbnail, WallpaperInfo info, Intent intent) {
mThumbnail = thumbnail;
mInfo = info;
}
@Override
public void onClick(WallpaperPickerActivity a) {
Intent preview = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);
preview.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT,
mInfo.getComponent());
a.onLiveWallpaperPickerLaunch(mInfo);
a.startActivityForResultSafely(preview, WallpaperPickerActivity.PICK_LIVE_WALLPAPER);
}
}
     WallpaperTileInfo的子类,然后异步加载信息。
for (ResolveInfo resolveInfo : list) {
WallpaperInfo info = null;
try {
info = new WallpaperInfo(mContext, resolveInfo);
} catch (XmlPullParserException e) {
Log.w(LOG_TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
continue;
} catch (IOException e) {
Log.w(LOG_TAG, "Skipping wallpaper " + resolveInfo.serviceInfo, e);
continue;
}

// 获取动态壁纸信息
Drawable thumb = info.loadThumbnail(packageManager);
Intent launchIntent = new Intent(WallpaperService.SERVICE_INTERFACE);
launchIntent.setClassName(info.getPackageName(), info.getServiceName());
LiveWallpaperTile wallpaper = new LiveWallpaperTile(thumb, info, launchIntent);
publishProgress(wallpaper);
}
    4)第三方壁纸
// Populate the third-party wallpaper pickers
// 填充第三方壁纸选择器
final LinearLayout thirdPartyWallpapersView =
(LinearLayout) findViewById(R.id.third_party_wallpaper_list);
final ThirdPartyWallpaperPickerListAdapter ta =
new ThirdPartyWallpaperPickerListAdapter(this);
populateWallpapersFromAdapter(thirdPartyWallpapersView, ta, false);

    加载第三方壁纸选择器,这个还是很友好的,这样手机中如果装有其他的第三方壁纸设置的应用,也可以在此处显示出来。查询是在ThirdPartyWallpaperPickerListAdapter适配器类中进行的,这个适配器跟刚才说的动态壁纸适配器类类似。
    定义了第三方壁纸对象ThirdPartyWallpaperTile,
public static class ThirdPartyWallpaperTile extends WallpaperPickerActivity.WallpaperTileInfo {

private ResolveInfo mResolveInfo;
public ThirdPartyWallpaperTile(ResolveInfo resolveInfo) {
mResolveInfo = resolveInfo;
}

@Override
public void onClick(WallpaperPickerActivity a) {
final ComponentName itemComponentName = new ComponentName(
mResolveInfo.activityInfo.packageName, mResolveInfo.activityInfo.name);
Intent launchIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
launchIntent.setComponent(itemComponentName);
a.startActivityForResultSafely(launchIntent, WallpaperPickerActivity.PICK_WALLPAPER_THIRD_PARTY_ACTIVITY);// 启动第三方壁纸选择器
}
}
    在构造方法中查询第三方壁纸应用,
public ThirdPartyWallpaperPickerListAdapter(Context context) {
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
mPackageManager = context.getPackageManager();
mIconSize = context.getResources().getDimensionPixelSize(R.dimen.wallpaperItemIconSize);
final PackageManager pm = mPackageManager;

final Intent pickWallpaperIntent = new Intent(Intent.ACTION_SET_WALLPAPER);
final List<ResolveInfo> apps = pm.queryIntentActivities(pickWallpaperIntent, 0);

// Get list of image picker intents
Intent pickImageIntent = new Intent(Intent.ACTION_GET_CONTENT);
pickImageIntent.setType("image/*");
final List<ResolveInfo> imagePickerActivities =
pm.queryIntentActivities(pickImageIntent, 0);
final ComponentName[] imageActivities = new ComponentName[imagePickerActivities.size()];
for (int i = 0; i < imagePickerActivities.size(); i++) {
ActivityInfo activityInfo = imagePickerActivities.get(i).activityInfo;
imageActivities[i] = new ComponentName(activityInfo.packageName, activityInfo.name);
}

outerLoop:
for (ResolveInfo info : apps) {
final ComponentName itemComponentName =
new ComponentName(info.activityInfo.packageName, info.activityInfo.name);
final String itemPackageName = itemComponentName.getPackageName();
// Exclude anything from our own package, and the old Launcher,
// and live wallpaper picker
if (itemPackageName.equals(context.getPackageName()) ||
itemPackageName.equals("com.android.launcher") ||
itemPackageName.equals("com.android.wallpaper.livepicker")) {
continue;
}
// Exclude any package that already responds to the image picker intent
for (ResolveInfo imagePickerActivityInfo : imagePickerActivities) {
if (itemPackageName.equals(
imagePickerActivityInfo.activityInfo.packageName)) {
continue outerLoop;
}
}
mThirdPartyWallpaperPickers.add(new ThirdPartyWallpaperTile(info));
}
}
    根据"android.intent.action.SET_WALLPAPER"来查找的,然后做一些过滤,添加到列表中。
    5)添加图库

// Add a tile for the Gallery
// 列表开头放置图库选择器
LinearLayout masterWallpaperList = (LinearLayout) findViewById(R.id.master_wallpaper_list);
FrameLayout pickImageTile = (FrameLayout) getLayoutInflater().
inflate(R.layout.wallpaper_picker_image_picker_item, masterWallpaperList, false);
setWallpaperItemPaddingToZero(pickImageTile);
masterWallpaperList.addView(pickImageTile, 0);

// Make its background the last photo taken on external storage
Bitmap lastPhoto = getThumbnailOfLastPhoto();
if (lastPhoto != null) {
ImageView galleryThumbnailBg =
(ImageView) pickImageTile.findViewById(R.id.wallpaper_image);
galleryThumbnailBg.setImageBitmap(getThumbnailOfLastPhoto());
int colorOverlay = getResources().getColor(R.color.wallpaper_picker_translucent_gray);
galleryThumbnailBg.setColorFilter(colorOverlay, PorterDuff.Mode.SRC_ATOP);

}

PickImageInfo pickImageInfo = new PickImageInfo();
pickImageTile.setTag(pickImageInfo);
pickImageInfo.setView(pickImageTile);
pickImageTile.setOnClickListener(mThumbnailOnClickListener);
 
  在列表开头添加图库入口,这样用户就可以选择任一图片了。

    
    其他的初始化设置就不一一赘述了。

三、壁纸预览和设置
    之前说到不同类型的壁纸对象时,会重写父类的方法,实现具体的功能,这里我们已ResourceWallpaperInfo为例,来说明壁纸的预览和设置的。
@Override
public void onClick(WallpaperPickerActivity a) {
Log.d("dingfeng","ResourceWallpaperInfo onClick...");
BitmapRegionTileSource.ResourceBitmapSource bitmapSource =
new BitmapRegionTileSource.ResourceBitmapSource(
mResources, mResId, BitmapRegionTileSource.MAX_PREVIEW_SIZE);
bitmapSource.loadInBackground();
BitmapRegionTileSource source = new BitmapRegionTileSource(a, bitmapSource);
CropView v = a.getCropView();
v.setTileSource(source, null);
Point wallpaperSize = WallpaperCropActivity.getDefaultWallpaperSize(
a.getResources(), a.getWindowManager());
RectF crop = WallpaperCropActivity.getMaxCropRect(
source.getImageWidth(), source.getImageHeight(),
wallpaperSize.x, wallpaperSize.y, false);
v.setScale(wallpaperSize.x / crop.width());
v.setTouchEnabled(false);
a.setSystemWallpaperVisiblity(false);
}
@Override
public void onSave(WallpaperPickerActivity a) {
Log.d("dingfeng","ResourceWallpaperInfo onSave...");
boolean finishActivityWhenDone = true;
a.cropImageAndSetWallpaper(mResources, mResId, finishActivityWhenDone);
}
@Override
public boolean isSelectable() {
return true;
}
@Override
public boolean isNamelessWallpaper() {
return true;
}

    实现了四个方法,后面两个返回bool值得含义之前已经说过,我们不细说。先看onClick,这个方法在点击缩略图列表是触发,看看它究竟做了什么。
    这面用到了BitmapRegionTileSource及其内部类对象,这些类定义在src\main\java\com\android\photos\目录下,自定义了图片对象,实现了滚动、缩放等功能,这里就不展开了,可以自己查看代码




     生成BitmapRegionTileSource对象后,设置到CropView上,然后做合适的缩放,再将系统壁纸设为不可见,这样就可以达到壁纸预览的目的。
     再看onSave方法,这个方法在点击ActionBar时调用,该方法中调用WallpaperCropActivity的cropImageAndSetWallpaper来裁剪和设置壁纸,
protected void cropImageAndSetWallpaper(
Resources res, int resId, final boolean finishActivityWhenDone) {
// crop this image and scale it down to the default wallpaper size for
// this device
int rotation = getRotationFromExif(res, resId);
Point inSize = mCropView.getSourceDimensions();
Point outSize = getDefaultWallpaperSize(getResources(), getWindowManager());
RectF crop = getMaxCropRect(inSize.x, inSize.y, outSize.x, outSize.y, false);
Runnable onEndCrop = new Runnable() {
public void run() {
// Passing 0, 0 will cause launcher to revert to using the
// default wallpaper size
updateWallpaperDimensions(0, 0);
if (finishActivityWhenDone) {
setResult(Activity.RESULT_OK);
finish();
}
}
};
BitmapCropTask cropTask = new BitmapCropTask(this, res, resId,
crop, rotation, outSize.x, outSize.y, true, false, onEndCrop);
cropTask.execute();
}
    设置裁剪大小,将其作为参数传递给异步任务执行,
@Override
protected Boolean doInBackground(Void... params) {
return cropBitmap();
}
    最终就是cropBitmap方法来做最后的裁剪和壁纸设置操作。
 
  其他几种类型的壁纸也是类似的,根据壁纸来源做出相应的操作,比如第三方壁纸时,点击缩略图就是打开第三方应用;如果是图库,就打开图库,总之都是在这几个重写方法中实现的。如果以后有什么不同于目前几种类型的,也可以依此来扩展。
    
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android Launcher3