目录
上回我们简单介绍了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" 即可。
历史上的今天
暂无评论...
随机推荐
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;...