- 浏览: 25341 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
喜物悲己:
看着很不错,不过是语言不通顺还是我领悟能力太低了...
android电源管理之框架分析(转) -
William_Sim:
...
eclipse关联android源码及提取android2.3源码 -
kaiwangkuaile:
敢问楼主,你都试验过吗?
eclipse关联android源码及提取android2.3源码 -
dahui12344321:
嗯。写的很详细。
android电源管理之框架分析(转)
android之壁纸机制
1.涉及核心类:
1>ImageWallpaper.java(IW):继承WallpaperService主要负责静态壁纸的draw处理;
2>WallpaperManager.java(WM):主要负责壁纸的存取方法管理(可能会多个实例);
3>WallpaperManagerService(WMS).java:主要是对WalllpaperManager一些核心方法提供,及一些初始参数的保存(服务);
4>iWallpaperManager.aidl(IWM):负责WallpaperManager与WallpaperManagerService之间的通信;
5>IWallpaperManagerCallback(IMC).aidl:负责WallpaperManager与WallpaperManagerService之间的通信,这是一个回调机制与前面不同;
6>WallpaperService.java(WS):设置壁纸的引擎机制(包括动态与静态);//这类工作时没有修改过,所以个人了解不是很清楚,希望有朋友补充.
7>launcher.java(LC)设置壁纸初始化值,带到壁纸机制的转屏.
2. 壁纸从设置存到取流程:
1>首先WM.setBitmap(bitmap)
public void setBitmap(Bitmap bitmap) throws IOException {
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
return;
}
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
} finally {
if (fos != null) {
fos.close();
}
}
} catch (RemoteException e) {
}
}
2>然后WMS.setWallpaper(null),设置成功会写入到壁纸相应文件里,文件监听类此时会触发
private final FileObserver mWallpaperObserver = new FileObserver(
WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) {
@Override
public void onEvent(int event, String path) {
if (path == null) {
return;
}
synchronized (mLock) {
// changing the wallpaper means we'll need to back up the new one
long origId = Binder.clearCallingIdentity();
BackupManager bm = new BackupManager(mContext);
bm.dataChanged();
Binder.restoreCallingIdentity(origId);
File changedFile = new File(WALLPAPER_DIR, path);
if (WALLPAPER_FILE.equals(changedFile)) {
notifyCallbacksLocked();//会发出广播与调用回调方法
}
}
}
};
//notifyCallbacksLocked()做两件事情
private void notifyCallbacksLocked() {
final int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
mCallbacks.getBroadcastItem(i).onWallpaperChanged();//回调机制在WM实现onWallpaperChanged()
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);//壁纸变化的广播意图
mContext.sendBroadcast(intent);//IW会接收到此意图,IW.updateWallpaper()去获取新壁纸.
}
3>WM.onWallpaperChanged()通过handler机制清除壁纸缓存
private final Handler mHandler;
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CLEAR_WALLPAPER:
synchronized (this) {
mWallpaper = null;//用户自定义壁纸
mDefaultWallpaper = null;//系统默认壁纸
}
break;
}
}
};
}
public void onWallpaperChanged() {
/* The wallpaper has changed but we shouldn't eagerly load the
* wallpaper as that would be inefficient. Reset the cached wallpaper
* to null so if the user requests the wallpaper again then we'll
* fetch it.
*/
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
//IW.updateWallpaper()
void updateWallpaper() {
synchronized (mLock) {
try {
mBackground = mWallpaperManager.getFastDrawable();//WM去获取壁纸
} catch (RuntimeException e) {
Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
}
}
}
//收到壁纸变换广播
class WallpaperObserver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
updateWallpaper();//调用
drawFrame();
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
}
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);//
mReceiver = new WallpaperObserver();
registerReceiver(mReceiver, filter);//注册
updateWallpaper();
surfaceHolder.setSizeFromLayout();
}
4>mWallpaperManager.getFastDrawable();//WM去获取壁纸
a. public Drawable getFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);//获取壁纸总方法
if (bm != null) {
Drawable dr = new FastBitmapDrawable(bm);
return dr;
}
return null;
}
b. public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
return mWallpaper;
}
if (mDefaultWallpaper != null) {
return mDefaultWallpaper;
}
mWallpaper = null;
try {
mWallpaper = getCurrentWallpaperLocked(context);//调用获取用户自定义壁纸方法
} catch (OutOfMemoryError e) {
Log.w(TAG, "No memory load current wallpaper", e);
}
if (mWallpaper == null && returnDefault) {
mDefaultWallpaper = getDefaultWallpaperLocked(context);调用默认壁纸方法
return mDefaultWallpaper;
}
return mWallpaper;
}
}
c. 两方法分析
private Bitmap getCurrentWallpaperLocked(Context context) {
try {
Bundle params = new Bundle();
ParcelFileDescriptor fd = mService.getWallpaper(this, params);//WMS.getWallpaper(this, params),params是out型表示参数传送是从WMS传到WM,是与平时java编码不合适习惯的这android一特性也是aidl机制的一部分;这里留个问题就WMS是如何获取到的params参数呢?
if (fd != null) {
int width = params.getInt("width", 0);
int height = params.getInt("height", 0);
if (width <= 0 || height <= 0) {
// Degenerate case: no size requested, just load
// bitmap as-is.
Bitmap bm = null;
try {
bm = BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, null);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode file", e);
}
try {
fd.close();
} catch (IOException e) {
}
if (bm != null) {
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
}
return bm;
}
// Load the bitmap with full color depth, to preserve
// quality for later processing.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bm = BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, options);
try {
fd.close();
} catch (IOException e) {
}
return generateBitmap(context, bm, width, height);
}
} catch (RemoteException e) {
}
return null;
}
private Bitmap getDefaultWallpaperLocked(Context context) {
try {
InputStream is = context.getResources().openRawResource(
com.android.internal.R.drawable.default_wallpaper);
if (is != null) {
int width = mService.getWidthHint();
int height = mService.getHeightHint();
if (width <= 0 || height <= 0) {
// Degenerate case: no size requested, just load
// bitmap as-is.
Bitmap bm = null;
try {
bm = BitmapFactory.decodeStream(is, null, null);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode stream", e);
}
try {
is.close();
} catch (IOException e) {
}
if (bm != null) {
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
}
return bm;
}
5>WMS.getWallpaper(this, params)
public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
Bundle outParams) {
synchronized (mLock) {
try {
if (outParams != null) {
outParams.putInt("width", mWidth);
outParams.putInt("height", mHeight);
}
mCallbacks.register(cb);
File f = WALLPAPER_FILE;
if (!f.exists()) {
return null;
}
return ParcelFileDescriptor.open(f, MODE_READ_ONLY);//ParcelFileDescriptor是google自定义的句柄具有安全性,对它所属的流具体保护性,否会图像丢失出现花屏情况.我对它了解也不深,不遇到类似的bug.
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
Slog.w(TAG, "Error getting wallpaper", e);
}
return null;
}
}
6>呵呵呵,该画了IW.draw(),考虑有很多东西要跟大家分享下就把IW类粘贴出来
package com.android.internal.service.wallpaper;
import com.android.internal.view.WindowManagerPolicyThread;
import android.app.WallpaperManager;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.content.Context;
import android.content.IntentFilter;
import android.content.Intent;
import android.content.BroadcastReceiver;
/**
* Default built-in wallpaper that simply shows a static image.
*/
public class ImageWallpaper extends WallpaperService {
WallpaperManager mWallpaperManager;
private HandlerThread mThread;
@Override
public void onCreate() {
super.onCreate();
mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
Looper looper = WindowManagerPolicyThread.getLooper();
if (looper != null) {
setCallbackLooper(looper);
} else {
mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
mThread.start();
setCallbackLooper(mThread.getLooper());
}
}
public Engine onCreateEngine() {
return new DrawableEngine();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mThread != null) {
mThread.quit();
}
}
class DrawableEngine extends Engine {
private final Object mLock = new Object();
private WallpaperObserver mReceiver;
Drawable mBackground;
float mXOffset;
float mYOffset;
class WallpaperObserver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
updateWallpaper();
drawFrame();
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
}
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
mReceiver = new WallpaperObserver();
registerReceiver(mReceiver, filter);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
@Override
public void onVisibilityChanged(boolean visible) {//亮屏时会执行
drawFrame();
}
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixels, int yPixels) {//滑动壁纸时会执行
mXOffset = xOffset;
mYOffset = yOffset;
drawFrame();
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {//开机和转屏时会执行
super.onSurfaceChanged(holder, format, width, height);
drawFrame();
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
}
void drawFrame() {
SurfaceHolder sh = getSurfaceHolder();
Canvas c = sh.lockCanvas();//锁住canvas
if (c != null) {
final Rect frame = sh.getSurfaceFrame();
synchronized (mLock) {
final Drawable background = mBackground;
final int dw = frame.width();
final int dh = frame.height();
final int bw = background != null ? background.getIntrinsicWidth() : 0;
final int bh = background != null ? background.getIntrinsicHeight() : 0;
final int availw = dw-bw;
final int availh = dh-bh;
int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2);
c.translate(xPixels, yPixels);//滑动后计算到壁纸画起点位置
if (availw<0 || availh<0) {
c.save(Canvas.CLIP_SAVE_FLAG);
c.clipRect(0, 0, bw, bh, Op.DIFFERENCE);
c.drawColor(0xff000000);//出现壁纸尺寸异常或是转屏延迟就会画黑
c.restore();
}
if (background != null) {
background.draw(c);
}
}
sh.unlockCanvasAndPost(c);//解锁canvas并提交
}
}
void updateWallpaper() {
synchronized (mLock) {
try {
mBackground = mWallpaperManager.getFastDrawable();
} catch (RuntimeException e) {
Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
}
}
}
}
}
3.壁纸长宽初始化值及转屏处理
1>LC.setWallpaperDimension()
private void setWallpaperDimension() {
WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
Display display = getWindowManager().getDefaultDisplay();
boolean isPortrait = display.getWidth() < display.getHeight();
final int width = isPortrait ? display.getWidth() : display.getHeight();
final int height = isPortrait ? display.getHeight() : display.getWidth();
wpm.suggestDesiredDimensions(width * WALLPAPER_SCREENS_SPAN, height);//WM.setsuggestDesiredDimensions(width,height) 设置长宽
}
2>
public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
try {
sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);//WMS.setsetDimensionHints(..)
} catch (RemoteException e) {
}
}
3>
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
synchronized (mLock) {
if (width != mWidth || height != mHeight) {
mWidth = width;
mHeight = height;
saveSettingsLocked();//将值以xml形式存储,开机时候会调用loadSettingsLocked()读取
if (mWallpaperConnection != null) {
if (mWallpaperConnection.mEngine != null) {
try {
mWallpaperConnection.mEngine.setDesiredSize(
width, height);
} catch (RemoteException e) {
}
notifyCallbacksLocked();//通知壁纸有变化(包括换壁纸与横竖转换).
}
}
}
}
}
4>android的壁纸机制用得IPC机制,aidl机制,广播机制,这里我们就不再介绍.不太清楚google吧.另外我将aidl内容贴出来,希望对大家的理解有帮助.
/** @hide */
1>IWallpaperManager.aidl
interface IWallpaperManager {
/**
* Set the wallpaper.
*/
ParcelFileDescriptor setWallpaper(String name);
/**
* Set the live wallpaper.
*/
void setWallpaperComponent(in ComponentName name);
/**
* Get the wallpaper.
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
/**
* Get information about a live wallpaper.
*/
WallpaperInfo getWallpaperInfo();
/**
* Clear the wallpaper.
*/
void clearWallpaper();
/**
* Sets the dimension hint for the wallpaper. These hints indicate the desired
* minimum width and height for the wallpaper.
*/
void setDimensionHints(in int width, in int height);
/**
* Returns the desired minimum width for the wallpaper.
*/
int getWidthHint();
/**
* Returns the desired minimum height for the wallpaper.
*/
int getHeightHint();
}
2>IWallpaperManagerCallback.aidl
oneway interface IWallpaperManagerCallback {
/**
* Called when the wallpaper has changed
*/
void onWallpaperChanged();
}
1.涉及核心类:
1>ImageWallpaper.java(IW):继承WallpaperService主要负责静态壁纸的draw处理;
2>WallpaperManager.java(WM):主要负责壁纸的存取方法管理(可能会多个实例);
3>WallpaperManagerService(WMS).java:主要是对WalllpaperManager一些核心方法提供,及一些初始参数的保存(服务);
4>iWallpaperManager.aidl(IWM):负责WallpaperManager与WallpaperManagerService之间的通信;
5>IWallpaperManagerCallback(IMC).aidl:负责WallpaperManager与WallpaperManagerService之间的通信,这是一个回调机制与前面不同;
6>WallpaperService.java(WS):设置壁纸的引擎机制(包括动态与静态);//这类工作时没有修改过,所以个人了解不是很清楚,希望有朋友补充.
7>launcher.java(LC)设置壁纸初始化值,带到壁纸机制的转屏.
2. 壁纸从设置存到取流程:
1>首先WM.setBitmap(bitmap)
public void setBitmap(Bitmap bitmap) throws IOException {
try {
ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null);
if (fd == null) {
return;
}
FileOutputStream fos = null;
try {
fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
bitmap.compress(Bitmap.CompressFormat.PNG, 90, fos);
} finally {
if (fos != null) {
fos.close();
}
}
} catch (RemoteException e) {
}
}
2>然后WMS.setWallpaper(null),设置成功会写入到壁纸相应文件里,文件监听类此时会触发
private final FileObserver mWallpaperObserver = new FileObserver(
WALLPAPER_DIR.getAbsolutePath(), CREATE | CLOSE_WRITE | DELETE | DELETE_SELF) {
@Override
public void onEvent(int event, String path) {
if (path == null) {
return;
}
synchronized (mLock) {
// changing the wallpaper means we'll need to back up the new one
long origId = Binder.clearCallingIdentity();
BackupManager bm = new BackupManager(mContext);
bm.dataChanged();
Binder.restoreCallingIdentity(origId);
File changedFile = new File(WALLPAPER_DIR, path);
if (WALLPAPER_FILE.equals(changedFile)) {
notifyCallbacksLocked();//会发出广播与调用回调方法
}
}
}
};
//notifyCallbacksLocked()做两件事情
private void notifyCallbacksLocked() {
final int n = mCallbacks.beginBroadcast();
for (int i = 0; i < n; i++) {
try {
mCallbacks.getBroadcastItem(i).onWallpaperChanged();//回调机制在WM实现onWallpaperChanged()
} catch (RemoteException e) {
// The RemoteCallbackList will take care of removing
// the dead object for us.
}
}
mCallbacks.finishBroadcast();
final Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);//壁纸变化的广播意图
mContext.sendBroadcast(intent);//IW会接收到此意图,IW.updateWallpaper()去获取新壁纸.
}
3>WM.onWallpaperChanged()通过handler机制清除壁纸缓存
private final Handler mHandler;
Globals(Looper looper) {
IBinder b = ServiceManager.getService(Context.WALLPAPER_SERVICE);
mService = IWallpaperManager.Stub.asInterface(b);
mHandler = new Handler(looper) {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_CLEAR_WALLPAPER:
synchronized (this) {
mWallpaper = null;//用户自定义壁纸
mDefaultWallpaper = null;//系统默认壁纸
}
break;
}
}
};
}
public void onWallpaperChanged() {
/* The wallpaper has changed but we shouldn't eagerly load the
* wallpaper as that would be inefficient. Reset the cached wallpaper
* to null so if the user requests the wallpaper again then we'll
* fetch it.
*/
mHandler.sendEmptyMessage(MSG_CLEAR_WALLPAPER);
}
//IW.updateWallpaper()
void updateWallpaper() {
synchronized (mLock) {
try {
mBackground = mWallpaperManager.getFastDrawable();//WM去获取壁纸
} catch (RuntimeException e) {
Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
}
}
}
//收到壁纸变换广播
class WallpaperObserver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
updateWallpaper();//调用
drawFrame();
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
}
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);//
mReceiver = new WallpaperObserver();
registerReceiver(mReceiver, filter);//注册
updateWallpaper();
surfaceHolder.setSizeFromLayout();
}
4>mWallpaperManager.getFastDrawable();//WM去获取壁纸
a. public Drawable getFastDrawable() {
Bitmap bm = sGlobals.peekWallpaperBitmap(mContext, true);//获取壁纸总方法
if (bm != null) {
Drawable dr = new FastBitmapDrawable(bm);
return dr;
}
return null;
}
b. public Bitmap peekWallpaperBitmap(Context context, boolean returnDefault) {
synchronized (this) {
if (mWallpaper != null) {
return mWallpaper;
}
if (mDefaultWallpaper != null) {
return mDefaultWallpaper;
}
mWallpaper = null;
try {
mWallpaper = getCurrentWallpaperLocked(context);//调用获取用户自定义壁纸方法
} catch (OutOfMemoryError e) {
Log.w(TAG, "No memory load current wallpaper", e);
}
if (mWallpaper == null && returnDefault) {
mDefaultWallpaper = getDefaultWallpaperLocked(context);调用默认壁纸方法
return mDefaultWallpaper;
}
return mWallpaper;
}
}
c. 两方法分析
private Bitmap getCurrentWallpaperLocked(Context context) {
try {
Bundle params = new Bundle();
ParcelFileDescriptor fd = mService.getWallpaper(this, params);//WMS.getWallpaper(this, params),params是out型表示参数传送是从WMS传到WM,是与平时java编码不合适习惯的这android一特性也是aidl机制的一部分;这里留个问题就WMS是如何获取到的params参数呢?
if (fd != null) {
int width = params.getInt("width", 0);
int height = params.getInt("height", 0);
if (width <= 0 || height <= 0) {
// Degenerate case: no size requested, just load
// bitmap as-is.
Bitmap bm = null;
try {
bm = BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, null);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode file", e);
}
try {
fd.close();
} catch (IOException e) {
}
if (bm != null) {
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
}
return bm;
}
// Load the bitmap with full color depth, to preserve
// quality for later processing.
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bm = BitmapFactory.decodeFileDescriptor(
fd.getFileDescriptor(), null, options);
try {
fd.close();
} catch (IOException e) {
}
return generateBitmap(context, bm, width, height);
}
} catch (RemoteException e) {
}
return null;
}
private Bitmap getDefaultWallpaperLocked(Context context) {
try {
InputStream is = context.getResources().openRawResource(
com.android.internal.R.drawable.default_wallpaper);
if (is != null) {
int width = mService.getWidthHint();
int height = mService.getHeightHint();
if (width <= 0 || height <= 0) {
// Degenerate case: no size requested, just load
// bitmap as-is.
Bitmap bm = null;
try {
bm = BitmapFactory.decodeStream(is, null, null);
} catch (OutOfMemoryError e) {
Log.w(TAG, "Can't decode stream", e);
}
try {
is.close();
} catch (IOException e) {
}
if (bm != null) {
bm.setDensity(DisplayMetrics.DENSITY_DEVICE);
}
return bm;
}
5>WMS.getWallpaper(this, params)
public ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
Bundle outParams) {
synchronized (mLock) {
try {
if (outParams != null) {
outParams.putInt("width", mWidth);
outParams.putInt("height", mHeight);
}
mCallbacks.register(cb);
File f = WALLPAPER_FILE;
if (!f.exists()) {
return null;
}
return ParcelFileDescriptor.open(f, MODE_READ_ONLY);//ParcelFileDescriptor是google自定义的句柄具有安全性,对它所属的流具体保护性,否会图像丢失出现花屏情况.我对它了解也不深,不遇到类似的bug.
} catch (FileNotFoundException e) {
/* Shouldn't happen as we check to see if the file exists */
Slog.w(TAG, "Error getting wallpaper", e);
}
return null;
}
}
6>呵呵呵,该画了IW.draw(),考虑有很多东西要跟大家分享下就把IW类粘贴出来
package com.android.internal.service.wallpaper;
import com.android.internal.view.WindowManagerPolicyThread;
import android.app.WallpaperManager;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.Region.Op;
import android.graphics.drawable.Drawable;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Process;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.content.Context;
import android.content.IntentFilter;
import android.content.Intent;
import android.content.BroadcastReceiver;
/**
* Default built-in wallpaper that simply shows a static image.
*/
public class ImageWallpaper extends WallpaperService {
WallpaperManager mWallpaperManager;
private HandlerThread mThread;
@Override
public void onCreate() {
super.onCreate();
mWallpaperManager = (WallpaperManager) getSystemService(WALLPAPER_SERVICE);
Looper looper = WindowManagerPolicyThread.getLooper();
if (looper != null) {
setCallbackLooper(looper);
} else {
mThread = new HandlerThread("Wallpaper", Process.THREAD_PRIORITY_FOREGROUND);
mThread.start();
setCallbackLooper(mThread.getLooper());
}
}
public Engine onCreateEngine() {
return new DrawableEngine();
}
@Override
public void onDestroy() {
super.onDestroy();
if (mThread != null) {
mThread.quit();
}
}
class DrawableEngine extends Engine {
private final Object mLock = new Object();
private WallpaperObserver mReceiver;
Drawable mBackground;
float mXOffset;
float mYOffset;
class WallpaperObserver extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
updateWallpaper();
drawFrame();
// Assume we are the only one using the wallpaper in this
// process, and force a GC now to release the old wallpaper.
System.gc();
}
}
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
super.onCreate(surfaceHolder);
IntentFilter filter = new IntentFilter(Intent.ACTION_WALLPAPER_CHANGED);
mReceiver = new WallpaperObserver();
registerReceiver(mReceiver, filter);
updateWallpaper();
surfaceHolder.setSizeFromLayout();
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(mReceiver);
}
@Override
public void onVisibilityChanged(boolean visible) {//亮屏时会执行
drawFrame();
}
@Override
public void onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
}
@Override
public void onOffsetsChanged(float xOffset, float yOffset,
float xOffsetStep, float yOffsetStep,
int xPixels, int yPixels) {//滑动壁纸时会执行
mXOffset = xOffset;
mYOffset = yOffset;
drawFrame();
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {//开机和转屏时会执行
super.onSurfaceChanged(holder, format, width, height);
drawFrame();
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
}
void drawFrame() {
SurfaceHolder sh = getSurfaceHolder();
Canvas c = sh.lockCanvas();//锁住canvas
if (c != null) {
final Rect frame = sh.getSurfaceFrame();
synchronized (mLock) {
final Drawable background = mBackground;
final int dw = frame.width();
final int dh = frame.height();
final int bw = background != null ? background.getIntrinsicWidth() : 0;
final int bh = background != null ? background.getIntrinsicHeight() : 0;
final int availw = dw-bw;
final int availh = dh-bh;
int xPixels = availw < 0 ? (int)(availw*mXOffset+.5f) : (availw/2);
int yPixels = availh < 0 ? (int)(availh*mYOffset+.5f) : (availh/2);
c.translate(xPixels, yPixels);//滑动后计算到壁纸画起点位置
if (availw<0 || availh<0) {
c.save(Canvas.CLIP_SAVE_FLAG);
c.clipRect(0, 0, bw, bh, Op.DIFFERENCE);
c.drawColor(0xff000000);//出现壁纸尺寸异常或是转屏延迟就会画黑
c.restore();
}
if (background != null) {
background.draw(c);
}
}
sh.unlockCanvasAndPost(c);//解锁canvas并提交
}
}
void updateWallpaper() {
synchronized (mLock) {
try {
mBackground = mWallpaperManager.getFastDrawable();
} catch (RuntimeException e) {
Log.w("ImageWallpaper", "Unable to load wallpaper!", e);
}
}
}
}
}
3.壁纸长宽初始化值及转屏处理
1>LC.setWallpaperDimension()
private void setWallpaperDimension() {
WallpaperManager wpm = (WallpaperManager)getSystemService(WALLPAPER_SERVICE);
Display display = getWindowManager().getDefaultDisplay();
boolean isPortrait = display.getWidth() < display.getHeight();
final int width = isPortrait ? display.getWidth() : display.getHeight();
final int height = isPortrait ? display.getHeight() : display.getWidth();
wpm.suggestDesiredDimensions(width * WALLPAPER_SCREENS_SPAN, height);//WM.setsuggestDesiredDimensions(width,height) 设置长宽
}
2>
public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
try {
sGlobals.mService.setDimensionHints(minimumWidth, minimumHeight);//WMS.setsetDimensionHints(..)
} catch (RemoteException e) {
}
}
3>
public void setDimensionHints(int width, int height) throws RemoteException {
checkPermission(android.Manifest.permission.SET_WALLPAPER_HINTS);
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("width and height must be > 0");
}
synchronized (mLock) {
if (width != mWidth || height != mHeight) {
mWidth = width;
mHeight = height;
saveSettingsLocked();//将值以xml形式存储,开机时候会调用loadSettingsLocked()读取
if (mWallpaperConnection != null) {
if (mWallpaperConnection.mEngine != null) {
try {
mWallpaperConnection.mEngine.setDesiredSize(
width, height);
} catch (RemoteException e) {
}
notifyCallbacksLocked();//通知壁纸有变化(包括换壁纸与横竖转换).
}
}
}
}
}
4>android的壁纸机制用得IPC机制,aidl机制,广播机制,这里我们就不再介绍.不太清楚google吧.另外我将aidl内容贴出来,希望对大家的理解有帮助.
/** @hide */
1>IWallpaperManager.aidl
interface IWallpaperManager {
/**
* Set the wallpaper.
*/
ParcelFileDescriptor setWallpaper(String name);
/**
* Set the live wallpaper.
*/
void setWallpaperComponent(in ComponentName name);
/**
* Get the wallpaper.
*/
ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
out Bundle outParams);
/**
* Get information about a live wallpaper.
*/
WallpaperInfo getWallpaperInfo();
/**
* Clear the wallpaper.
*/
void clearWallpaper();
/**
* Sets the dimension hint for the wallpaper. These hints indicate the desired
* minimum width and height for the wallpaper.
*/
void setDimensionHints(in int width, in int height);
/**
* Returns the desired minimum width for the wallpaper.
*/
int getWidthHint();
/**
* Returns the desired minimum height for the wallpaper.
*/
int getHeightHint();
}
2>IWallpaperManagerCallback.aidl
oneway interface IWallpaperManagerCallback {
/**
* Called when the wallpaper has changed
*/
void onWallpaperChanged();
}
相关推荐
对于初学者来说,这是一次了解Android服务和动画机制的好机会;对于有经验的开发者,这则可以作为一个起点,启发更多创新的动态壁纸设计。记得在研究源码时,结合Android官方文档和其他教程,以加深理解并提升你的...
在Android操作系统中,动态壁纸(Dynamic Wallpapers)是一种超越传统静态图像的个性化设置方式,它为用户提供了丰富的视觉体验和互动功能。动态壁纸允许背景随着用户的操作或时间变化而变化,创造出更为生动的桌面...
开发动态壁纸涉及到OpenGL ES、动画框架、多线程以及Android系统服务等多个方面,深入学习可以提升对Android系统底层机制的理解。推荐阅读Android官方文档,以及相关开源项目的源码,如Android开放源代码项目(AOSP...
通过对这套代码的学习和研究,开发者不仅可以实现个性化的锁屏壁纸功能,还能深入理解Android系统的壁纸服务机制,提高自己的Android开发技能。对于希望在MTK平台上开发特色锁屏壁纸的应用开发者来说,这是一个非常...
1. **Android壁纸服务**:Android系统提供了壁纸服务框架,允许开发者创建自定义壁纸应用。动态壁纸服务继承自`WallpaperService`类,通过重写其提供的方法来实现动画效果和用户交互。 2. **SurfaceView**:动态...
"Android壁纸源码Galaxy4(android-5.1.1_r1)"是一个专门研究Android 5.1.1版本中Galaxy4壁纸应用的源代码库,它揭示了Android壁纸应用开发的内部机制,对于想要深入了解Android系统或者进行壁纸应用开发的开发者来...
1. **Android壁纸服务**:Android系统提供了壁纸服务框架,开发者可以通过实现`WallpaperService`类来创建自己的动态壁纸。这个服务会在用户切换到桌面时启动,并在后台运行,处理壁纸的动画和交互。 2. ** ...
综上所述,开发一个简单的Android壁纸设置程序涉及Android SDK的使用、Activity生命周期管理、Intent机制、壁纸服务的运用、图像处理技术、文件管理和界面设计等多个方面。通过深入理解和实践这些知识点,你可以创建...
创建Android动态壁纸需要对Android系统服务、绘图机制以及触摸事件处理有深入理解。通过`WallpaperService`和其子类`Engine`,我们可以实现丰富多样的动态效果。例如,`TimeWall`就是一个很好的实例,它展示了如何...
【Android动态壁纸源码解析】 Android动态壁纸是Android操作系统中的一种特色功能,允许用户自定义主屏幕背景,使其具有交互性和动画效果。本资源提供的"Android动态壁纸源码"可以帮助开发者深入了解如何创建自定义...
1. **Android壁纸服务(Wallpaper Service)**: 动态壁纸是通过继承`android.service.wallpaper.WallpaperService`类来创建的。你需要重写`Engine`类,并在其中实现动态效果的逻辑。`Engine`类是壁纸服务的核心,...
在Android平台上,开发者可以利用系统提供的API来实现各种定制化的功能,其中之一就是创建自定义的锁屏界面。这个"安卓锁屏九宫格锁屏解锁壁纸相关-拯救电源键最详尽的android开发一键锁屏实例源码"的资源包,提供了...
这个项目对于初学者来说是一个很好的实践,因为可以深入理解Android的消息处理机制——`Handler`,以及如何在Android应用中实现定时任务。 `Handler`是Android中用于线程间通信的关键组件,特别是在主线程和工作...
- **性能优化**:利用硬件加速和缓存机制可以提高动态壁纸的渲染效率。 - **适配不同分辨率**:为不同屏幕尺寸和分辨率设计适应性布局和绘制策略。 - **主题定制**:提供配置选项让用户可以自定义颜色和样式等。 ...
【标题】"安卓锁屏九宫格锁屏解锁壁纸相关-android一键锁屏源代码android4.2工作正常.zip" 涉及的核心知识点是Android系统的锁屏机制,特别是九宫格锁屏和壁纸的实现。九宫格锁屏是Android系统中一种常见的用户安全...