日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

Android WallpaperManager 壁纸分析

發(fā)布時(shí)間:2023/12/20 Android 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android WallpaperManager 壁纸分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Android中的壁紙分為靜態(tài)壁紙和動(dòng)態(tài)壁紙, 這兩類壁紙本質(zhì)都是一樣的, 都是通過(guò)繼承WallpaperService來(lái)實(shí)現(xiàn)的,只不過(guò)是繪制方面的差異。WallpaperManagerService用于管理壁紙的運(yùn)行與切換,并通過(guò)WallpaperManager類向外界提供操作壁紙的接口,主要體現(xiàn)了對(duì)壁紙的管理方式。WallpaperService則對(duì)應(yīng)壁紙的具體實(shí)現(xiàn),實(shí)現(xiàn)壁紙服務(wù)相關(guān)的核心是WallpaperService中的Engine類

1 簡(jiǎn)單壁紙案列

1.1 新建壁紙服務(wù)
public class MyWallPaperService extends WallpaperService {private static final String TAG = "MyWallPaperService";@Overridepublic Engine onCreateEngine() {return new MyEngine();}class MyEngine extends Engine {@Overridepublic void onSurfaceCreated(SurfaceHolder holder) {super.onSurfaceCreated(holder);Canvas canvas = holder.lockCanvas();canvas.drawColor(Color.GREEN);holder.unlockCanvasAndPost(canvas);}} }
1.2 配置文件中配置相關(guān)
<!-- AndroidManifest.xml中service配置 --> <service android:name=".MyWallPaperService"android:enabled="true"android:permission="android.permission.BIND_WALLPAPER"><intent-filter ><action android:name="android.service.wallpaper.WallpaperService"/></intent-filter><meta-dataandroid:name="android.service.wallpaper"android:resource="@xml/wallpaper_resource"/> </service><!-- wallpaper_resource.xml配置 --> <?xml version="1.0" encoding="utf-8"?> <wallpaper xmlns:android="http://schemas.android.com/apk/res/android"/>
1.3 通過(guò)壁紙選擇器設(shè)置壁紙,最終壁紙顯示為綠色背景
void setWallpaper() {Intent intent = new Intent(WallpaperManager.ACTION_CHANGE_LIVE_WALLPAPER);ComponentName componentName = new ComponentName(this, MyWallPaperService.class);intent.putExtra(WallpaperManager.EXTRA_LIVE_WALLPAPER_COMPONENT, componentName);startActivity(intent); }

2 WallpaperManager相關(guān)介紹

// 主屏幕壁紙flag public static final int FLAG_SYSTEM = 1 << 0;// 鎖屏壁紙flag public static final int FLAG_LOCK = 1 << 1; // 設(shè)置動(dòng)態(tài)壁紙 public boolean setWallpaperComponent(ComponentName name)// 清除鎖屏壁紙 public void clear(WallpaperManager.FLAG_LOCK)// 清除所有壁紙 public void clearWallpaper()// 獲取靜態(tài)壁紙圖片 public Bitmap getBitmap()// 設(shè)置靜態(tài)壁紙 public void setBitmap(Bitmap bitmap)
2.1 WallpaperService和WallpaperManagerService之間的關(guān)系

2.2 WallpaperManager和WallpaperManagerService之間的關(guān)系

2.3 壁紙涉及到的類介紹
// 壁紙服務(wù)信息封裝 WallpaperInfo// 提供接口對(duì)壁紙服務(wù)的訪問(wèn) WallpaperManager// IWallpaperEngine接口服務(wù)端對(duì)象 // class IWallpaperEngineWrapper extends IWallpaperEngine.Stub IWallpaperEngineWrapper// IWallpaperService接口服務(wù)端對(duì)象 // IWallpaperServiceWrapper extends IWallpaperService.Stub IWallpaperServiceWrapper// 用戶壁紙相關(guān)信息存儲(chǔ) WallpaperData// 監(jiān)聽WallPaperService之間的連接狀態(tài)和實(shí)現(xiàn)IWallpaperConnection接口服務(wù)端實(shí)現(xiàn) // class WallpaperConnection extends IWallpaperConnection.Stub // implements ServiceConnection WallpaperConnection// 壁紙服務(wù) // public class WallpaperManagerService extends IWallpaperManager.Stub WallpaperManagerService// 壁紙核心和壁紙繪制相關(guān) Engine

3 壁紙相關(guān)代碼分析

WallpaperManager的setWallpaperComponent函數(shù)為設(shè)置動(dòng)態(tài)壁紙函數(shù),接下來(lái)以動(dòng)態(tài)壁紙為入口分析相關(guān)代碼。Globals實(shí)現(xiàn)了IWallpaperManagerCallback接口,sGlobals.mService為WallpaperManagerService的代理對(duì)象,sGlobals.mService最終通過(guò)binder調(diào)用WallpaperManagerService的setWallpaperComponent函數(shù),name為對(duì)應(yīng)壁紙服務(wù)的包名。

private static class Globals extends IWallpaperManagerCallback.Stub {private final IWallpaperManager mService; }public boolean setWallpaperComponent(ComponentName name, int userId) {if (sGlobals.mService == null) {Log.w(TAG, "WallpaperService not running");throw new RuntimeException(new DeadSystemException());}try {// step 1, 調(diào)用WallpaperManagerService的setWallpaperComponentChecked函數(shù)sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName(),userId);return true;} catch (RemoteException e) {throw e.rethrowFromSystemServer();} }
3.1 WallpaperManagerService::setWallpaperComponent

擁有android.Manifest.permission.SET_WALLPAPER_COMPONENT權(quán)限的apk才能設(shè)置動(dòng)態(tài)壁紙,壁紙選擇器有這個(gè)設(shè)置權(quán)限,首先進(jìn)行權(quán)限的相關(guān)檢查, 然后獲取用戶設(shè)置的壁紙相關(guān)信息, 錯(cuò)誤判斷等, 接下來(lái)bindWallpaperComponentLocked函數(shù)才是核心,對(duì)WallpaperService的條件判斷以及綁定

private void setWallpaperComponent(ComponentName name, int userId) {userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,false /* all */, true /* full */, "changing live wallpaper", null /* pkg */);// step 1, 權(quán)限檢查checkPermission(android.Manifest.permission.SET_WALLPAPER_COMPONENT);int which = FLAG_SYSTEM;boolean shouldNotifyColors = false;WallpaperData wallpaper;synchronized (mLock) {if (DEBUG) Slog.v(TAG, "setWallpaperComponent name=" + name);// step 2, 獲取用戶壁紙相關(guān)信息wallpaper = mWallpaperMap.get(userId);if (wallpaper == null) {throw new IllegalStateException("Wallpaper not yet initialized for user " + userId);}final long ident = Binder.clearCallingIdentity();// step 3 , 如果鎖屏壁紙沒(méi)有添加,則將鎖屏壁紙flag添加上if (mLockWallpaperMap.get(userId) == null) {which |= FLAG_LOCK;}try {wallpaper.imageWallpaperPending = false;boolean same = changingToSame(name, wallpaper);// step 3, 綁定WallpaperService服務(wù)if (bindWallpaperComponentLocked(name, false, true, wallpaper, null)) {if (!same) {wallpaper.primaryColors = null;}wallpaper.wallpaperId = makeWallpaperIdLocked();notifyCallbacksLocked(wallpaper);shouldNotifyColors = true;}} finally {Binder.restoreCallingIdentity(ident);}}if (shouldNotifyColors) {// step 4, 通知壁紙狀態(tài)改變notifyWallpaperColorsChanged(wallpaper, which);notifyWallpaperColorsChanged(mFallbackWallpaper, FLAG_SYSTEM);} }
3.2 WallpaperManagerService::bindWallpaperComponentLocked
  • bindWallpaperComponentLocked函數(shù)較長(zhǎng),分開來(lái)分析。
  • step 1, 如果設(shè)置的壁紙服務(wù)包名和現(xiàn)在設(shè)置的包名相同則返回不做處理
  • step 2, 根據(jù)componentName來(lái)查詢對(duì)應(yīng)的服務(wù)相關(guān)信息,即ServiceInfo,si為空說(shuō)明對(duì)應(yīng)包名的服務(wù)不存在,也返回不做處理了
  • step 3, 對(duì)應(yīng)包名的WallpaperService沒(méi)有包含android.Manifest.permission.BIND_WALLPAPER權(quán)限,返回不做后續(xù)處理
// step 1 , 壁紙對(duì)應(yīng)的包名是否改變,不是則是相同的壁紙返回,不做處理 if (!force && changingToSame(componentName, wallpaper)) {return true; }int serviceUserId = wallpaper.userId; // step 2, 通過(guò)PackageManager查找是否存在對(duì)應(yīng)包名的Service相關(guān)信息,不存在則返回 ServiceInfo si = mIPackageManager.getServiceInfo(componentName,PackageManager.GET_META_DATA | PackageManager.GET_PERMISSIONS, serviceUserId); if (si == null) {Slog.w(TAG, "Attempted wallpaper " + componentName + " is unavailable");return false; }// step 3, 如果service不包含android.Manifest.permission.BIND_WALLPAPER權(quán)限則返回 if (!android.Manifest.permission.BIND_WALLPAPER.equals(si.permission)) {String msg = "Selected service does not have "+ android.Manifest.permission.BIND_WALLPAPER+ ": " + componentName;if (fromUser) {throw new SecurityException(msg);}Slog.w(TAG, msg);return false; }
3.3 WallpaperManagerService::bindWallpaperComponentLocked

ris為查詢系統(tǒng)中所有的WallpaperService,篩選componentName包名相同的WallpaperService,并創(chuàng)建相關(guān)WallpaperInfo,wi為null的情況, 則說(shuō)明對(duì)應(yīng)的WallpaperService不存在,返回

WallpaperInfo wi = null;Intent intent = new Intent(WallpaperService.SERVICE_INTERFACE); if (componentName != null && !componentName.equals(mImageWallpaper)) {// Make sure the selected service is actually a wallpaper service.List<ResolveInfo> ris =mIPackageManager.queryIntentServices(intent,intent.resolveTypeIfNeeded(mContext.getContentResolver()),PackageManager.GET_META_DATA, serviceUserId).getList();for (int i=0; i<ris.size(); i++) {ServiceInfo rsi = ris.get(i).serviceInfo;// step 1, 如果componentName包名對(duì)應(yīng)的service存在,創(chuàng)建WallpaperInfo保存ServiceInfo信息if (rsi.name.equals(si.name) &&rsi.packageName.equals(si.packageName)) {try {wi = new WallpaperInfo(mContext, ris.get(i));} catch (XmlPullParserException e) {if (fromUser) {throw new IllegalArgumentException(e);}Slog.w(TAG, e);return false;} catch (IOException e) {if (fromUser) {throw new IllegalArgumentException(e);}Slog.w(TAG, e);return false;}break;}}// step 2, componentName包名對(duì)應(yīng)的service不存在, 直接返回if (wi == null) {String msg = "Selected service is not a wallpaper: "+ componentName;if (fromUser) {throw new SecurityException(msg);}Slog.w(TAG, msg);return false;} }
3.4 WallpaperManagerService::bindWallpaperComponentLocked

wi不為空, 對(duì)應(yīng)的WallpaperService存在,后續(xù)做綁定服務(wù)的工作,創(chuàng)建WallpaperConnection對(duì)象,WallpaperConnection繼承IWallpaperConnection接口, 并且實(shí)現(xiàn)了ServiceConnection接口。接下來(lái)就是通過(guò)mContext.bindServiceAsUser來(lái)綁定componentName對(duì)應(yīng)的WallpaperService,綁定服務(wù)成功后會(huì)回調(diào)ServiceConnection接口的onServiceConnected函數(shù),即WallpaperConnection的onServiceConnected函數(shù),onServiceConnected函數(shù)放到后面分析,同一個(gè)用戶,并且上次用戶設(shè)置的信息不為空(mLastWallpaper != null),取消掉上一次的壁紙?jiān)O(shè)定。

class WallpaperConnection extends IWallpaperConnection.StubServiceConnection {}final int componentUid = mIPackageManager.getPackageUid(componentName.getPackageName(),MATCH_DIRECT_BOOT_AUTO, wallpaper.userId); // step 1, 創(chuàng)建WallpaperConnection對(duì)象 WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper, componentUid); intent.setComponent(componentName); intent.putExtra(Intent.EXTRA_CLIENT_LABEL,com.android.internal.R.string.wallpaper_binding_label); intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivityAsUser(mContext, 0,Intent.createChooser(new Intent(Intent.ACTION_SET_WALLPAPER),mContext.getText(com.android.internal.R.string.chooser_wallpaper)),0, null, new UserHandle(serviceUserId)));// step 2, 綁定服務(wù), 服務(wù)綁定成功會(huì)回調(diào)WallpaperConnection的onServiceConnected函數(shù) if (!mContext.bindServiceAsUser(intent, newConn,Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI| Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE| Context.BIND_INCLUDE_CAPABILITIES,new UserHandle(serviceUserId))) {String msg = "Unable to bind service: "+ componentName;if (fromUser) {throw new IllegalArgumentException(msg);}Slog.w(TAG, msg);return false; }// step 3, 取消上一次的壁紙服務(wù) if (wallpaper.userId == mCurrentUserId && mLastWallpaper != null&& !wallpaper.equals(mFallbackWallpaper)) {detachWallpaperLocked(mLastWallpaper); } wallpaper.wallpaperComponent = componentName; wallpaper.connection = newConn; newConn.mReply = reply; if (wallpaper.userId == mCurrentUserId && !wallpaper.equals(mFallbackWallpaper)) {mLastWallpaper = wallpaper; }
3.5 detachWallpaperLocked

wallpaper.connection不為空, 說(shuō)明WallPaperService還在運(yùn)行,wallpaper.connection.mService為IWallpaperService接口,detach函數(shù)Android9.0以前不存在,回調(diào)IWallpaperService的detach函數(shù),最終調(diào)用WallPaperService的detach函數(shù)來(lái)回收相關(guān)資源,和attach函數(shù)相對(duì)應(yīng),通過(guò)mContext.unbindService(wallpaper.connection)取消綁定服務(wù)來(lái)銷毀服務(wù)。WallpaperConnection.DisplayConnector::disconnectLocked善后工作

private void detachWallpaperLocked(WallpaperData wallpaper) {// step 1, wallpaper.connection不為空, 說(shuō)明WallPaperService還在運(yùn)行if (wallpaper.connection != null) {try {// step 2, 回調(diào)WallpaperService的detach函數(shù)if (wallpaper.connection.mService != null) {wallpaper.connection.mService.detach();}} catch (RemoteException e) {Slog.w(TAG, "Failed detaching wallpaper service ", e);}// step 3, 取消綁定WallpaperServicemContext.unbindService(wallpaper.connection);// step 4調(diào)用WallpaperConnection.DisplayConnector::disconnectLocked函數(shù)// 將壁紙的WindowToken從WindowManagerService中移除,壁紙將無(wú)法顯示wallpaper.connection.forEachDisplayConnector(WallpaperConnection.DisplayConnector::disconnectLocked);wallpaper.connection.mService = null;wallpaper.connection.mDisplayConnector.clear();wallpaper.connection = null;if (wallpaper == mLastWallpaper) mLastWallpaper = null;} }
3.6 WallpaperConnection::DisplayConnector::disconnectLocked
void WallpaperConnection::DisplayConnector::disconnectLocked() {try {// step 1 清除壁紙的WindowTokenmIWindowManager.removeWindowToken(mToken, mDisplayId);} catch (RemoteException e) {}try {// step 2 回調(diào)mEngine的destroy函數(shù)if (mEngine != null) {mEngine.destroy();}} catch (RemoteException e) {}mEngine = null; }
3.7 WallpaperConnection::onServiceConnected
public void WallpaperConnection::onServiceConnected(ComponentName name, IBinder service) {synchronized (mLock) {if (mWallpaper.connection == this) {mService = IWallpaperService.Stub.asInterface(service);// step 1, 調(diào)用attachServiceLocked函數(shù)attachServiceLocked(this, mWallpaper);// step 2, 將用戶相關(guān)數(shù)據(jù)保存到XML文件中if (!mWallpaper.equals(mFallbackWallpaper)) {saveSettingsLocked(mWallpaper.userId);}FgThread.getHandler().removeCallbacks(mResetRunnable);if (mPerformance != null) {// step 3, 通知壁紙相關(guān)信息改變mPerformance.notifyWallpaperChanged(name.getPackageName());}}} }
3.8 WallpaperConnection::attachServiceLocked
private void attachServiceLocked(WallpaperConnection conn, WallpaperData wallpaper) {conn.forEachDisplayConnector(connector-> connector.connectLocked(conn, wallpaper)); }
3.9 WallpaperConnection::DisplayConnector::connectLocked

connection.mService為IWallpaperService接口,如果為空直接返回, 接下來(lái)添加壁紙的token到WindowManagerService中, 這樣壁紙窗口才能添加到WindowManagerService中顯示出來(lái).IWallpaperService的attach為WallpaperService的attach函數(shù),回調(diào)attach函數(shù)來(lái)對(duì)WallpaperService的Engine等相關(guān)資源的初始化。

void WallpaperConnection::DisplayConnector::connectLocked(WallpaperConnection connection, WallpaperData wallpaper) {// step 1, IWallpaperService為空直接返回if (connection.mService == null) {Slog.w(TAG, "WallpaperService is not connected yet");return;}try {// step 2, 將壁紙相關(guān)的WindowToken添加到WMS中// 得有壁紙Token, WallPaperService才能往WMS中添加壁紙窗口mIWindowManager.addWindowToken(mToken, TYPE_WALLPAPER, mDisplayId);} catch (RemoteException e) {Slog.e(TAG, "Failed add wallpaper window token on display " + mDisplayId, e);return;}final DisplayData wpdData = getDisplayDataOrCreate(mDisplayId);try {// step 3, 回調(diào)WallPaperService的attach函數(shù)connection.mService.attach(connection, mToken, TYPE_WALLPAPER, false,wpdData.mWidth, wpdData.mHeight,wpdData.mPadding, mDisplayId);} catch (RemoteException e) {Slog.w(TAG, "Failed attaching wallpaper on display", e);if (wallpaper != null && !wallpaper.wallpaperUpdating&& connection.getConnectedEngineSize() == 0) {bindWallpaperComponentLocked(null /* componentName */, false /* force */,false /* fromUser */, wallpaper, null /* reply */);}} }
4 WallPaperService代碼分析
4.1 WallpaperService::attach

如果服務(wù)以及銷毀,則返回,接下來(lái)是初始化相關(guān).mSession變量的初始化, 用來(lái)向WindowManagerService添加壁紙窗口,surfeace相關(guān)初始化后,初始化完成, 更新surface相關(guān)信息,最后調(diào)用updateSurface函數(shù)

void attach(IWallpaperEngineWrapper wrapper) {// step 1 ,如果已經(jīng)銷毀,返回if (mDestroyed) {return;}mInitializing = true;// step 2 ,獲取Session對(duì)象, 和WMS直接通信mSession = WindowManagerGlobal.getWindowSession();mWindow.setSession(mSession);// step 3 , surface相關(guān)初始化onCreate(mSurfaceHolder);mInitializing = false;mReportedVisible = false;updateSurface(false, false, false); }
WallpaperService::updateSurface

創(chuàng)建事件接收者對(duì)象mInputEventReceiver ,調(diào)用mSession的addToDisplay將壁紙窗口mWinodw添加到WindowManagerservice中,mSession.relayout將為mWindow分配surface,以及窗口大小告知WallpaperService。mIWallpaperEngine.reportShown()來(lái)告知WallpaperManagerService壁紙已經(jīng)開始顯示了。

void updateSurface(boolean forceRelayout, boolean forceReport, boolean redrawNeeded) {if (mDestroyed) {Log.w(TAG, "Ignoring updateSurface: destroyed");}if (forceRelayout || creating || surfaceCreating || formatChanged || sizeChanged|| typeChanged || flagsChanged || redrawNeeded|| !mIWallpaperEngine.mShownReported) {try {if (!mCreated) {mInputChannel = new InputChannel();// step 1, 將mWindow添加到WindowManagerService中if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE,mDisplay.getDisplayId(), mWinFrame, mContentInsets, mStableInsets,mOutsets, mDisplayCutout, mInputChannel,mInsetsState) < 0) {Log.w(TAG, "Failed to add window while updating wallpaper surface.");return;}mCreated = true;// step 2, 創(chuàng)建按鍵接收者mInputEventReceiver = new WallpaperInputEventReceiver(mInputChannel, Looper.myLooper());}// step 3, 給壁紙窗口布局和分配surfacefinal int relayoutResult = mSession.relayout(mWindow, mWindow.mSeq, mLayout, mWidth, mHeight,View.VISIBLE, 0, -1, mWinFrame, mOverscanInsets, mContentInsets,mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,mDisplayCutout, mMergedConfiguration, mSurfaceControl,mInsetsState);} finally {mIsCreating = false;mSurfaceCreated = true;if (redrawNeeded) {mSession.finishDrawing(mWindow);}// step 4, 通知WallPaperManagerService已經(jīng)顯示了mIWallpaperEngine.reportShown();}} catch (RemoteException ex) {}} }

壁紙相關(guān)總結(jié)

  • 1 壁紙服務(wù)相關(guān)的配置需要在配置文件中聲明
  • 2 實(shí)現(xiàn)壁紙服務(wù)相關(guān)的核心是WallpaperService中的Engine類和surface相關(guān)操作
  • 3 靜態(tài)壁紙和動(dòng)態(tài)壁紙都繼承自WallpaperService
  • 4 壁紙窗口WindowToken是通過(guò)WindowPaperManagerService來(lái)向WMS中來(lái)添加和移除操作,和輸入法窗口相似
  • 5 Android中的壁紙實(shí)現(xiàn)采用系統(tǒng)服務(wù)和四大組件中的服務(wù)兩層框架來(lái)實(shí)現(xiàn), 只需要我們實(shí)現(xiàn)自定義的WallpaperService, 就能夠通過(guò)系統(tǒng)服務(wù)來(lái)控制整個(gè)壁紙的顯示,隱藏,切換等, 隱藏服務(wù)之間的接口調(diào)用細(xì)節(jié),能夠很輕松的來(lái)開發(fā)壁紙服務(wù)

總結(jié)

以上是生活随笔為你收集整理的Android WallpaperManager 壁纸分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。