並且在9.0系統上,Google還為這個功能添加了壹項開關,用戶可以強制設置主題背景色:
廢話不多說,從源碼裏來看看根據壁紙的這整套流程是怎麽實現的。
首先簡單介紹下Android如何修改系統壁紙,如果是第三方應用首先要申請系統權限:
然後需要通過WallpaperManager相關的接口進行靜態壁紙的設置。
WallpaperManager提供了setBitmap(bitmap)、setResource(resid)、setStream(inputstream)這三個方法來設置靜態壁紙,下面以setBitmap的源碼為例來說明壹下。
從以上方法來看,設置壁紙的過程有進行寫文件操作,我們知道SystemUI的靜態壁紙是ImageWallpaper,那麽上述過程是如何通知到ImageWallpaper的呢。下面就來介紹WallpaperManagerService裏的壹個重要組件:WallpaperObserver。
WallpaperObserver繼承自FileObserver,而FileObserver類是壹個用於監聽文件訪問、創建、修改、刪除、移動等操作的監聽器,可以監聽壹個文件或者壹個文件夾,並在上述動作發生時回調onEvent()方法。
回到上面講的setBitmap方法,會通過WallpaperManagerService的setWallpaper()方法獲得壹個文件描述符,
再看updateWallpaperBitmapLocked()的實現:
從以上實現可知,文件路徑是用getWallpaperDir()方法獲得的,了解了這點,就方便介紹WallpaperObserver了。在它的構造方法裏,會將getWallpaperDir()取得的路徑傳回給父類的構造方法,從而開始監聽wallpaper的CLOSE_WRITE事件。
下面是用於回調的onEvent()方法的實現:
notifyColorsWhich 是壹個int值,初始時為0,當通過Wallpaper path取到的新壁紙File與之前保存的全局變量不壹致時,即有壁紙更新,notifyColorsWhich 會與FLAG_SYSTEM進行按位或運算;
notifyWallpaperColorsChanged()方法又會將參數傳給notifyColorListeners()方法去處理,這裏就直接跳到notifyColorListeners()的實現:
notifyWallpaperColorsChanged()方法會分別通知系統壁紙和鎖屏壁紙顏色改變的監聽者,我們暫時只先分析系統壁紙相關的流程。在這個方法裏,首先會通過mColorsChangedListeners取得當前userId的壹個RemoteCallbackList,這個類是壹個系統層的容器類,容納的對象是壹些接口mCallbacks ,用於執行列表中對象的回調函數,裏面有幾個比較重要的方法:
看的出WallPaperObserver的currentUserColorListeners裏存放的是壹些IWallpaperManagerCallback對象,之後通過getBroadcastItem()遍歷出所有的callbacks,並分別調用每個callback的onWallpaperColorsChanged()。
StatusBar的onStart()方法中有這麽壹步:
SysuiColorExtractor繼承於ColorExtractor,後者又實現了WallpaperManager.OnColorsChangedListener
在SysuiColorExtractor的構造函數裏,通過WallpaperManager的addOnColorsChangedListener()方法,把自身這個OnColorsChangedListener給註冊過去,最終會調用到WallpaperManager.sGlobals的addOnColorsChangedListener():
然後會把自己這個IWallpaperManagerCallback以及userId,通過WallpaperManagerService的registerWallpaperColorsCallback()方法傳遞過去:
到這壹步就和上壹節的通知過程對應上了,給mColorsChangedListeners添加新的RemoteCallbackList對象,並註冊相應的callback進去(這裏的callback是壹個Globals對象),方便後續通知。
好了,註冊過程講完了,最後再來看看SystemUI是怎麽響應壁紙顏色改變的。回到上壹節的最末尾,我們說到 “通過getBroadcastItem()遍歷出所有的callbacks,並分別調用每個callback的onWallpaperColorsChanged()”,已經知道這壹處的callback是WallpaperManager裏的Globals類的對象了,找到它的實現:
在前面的註釋中已經介紹過,存在listener這個Pair裏的first是壹個ColorExtractor,回到SystemUI,
遍歷mOnColorsChangedListeners裏的所有listener並調用其onColorsChanged()方法,在這壹節的最開始我們有提到StatusBar把自己作為參數通過addOnColorsChangedListener()傳給了ColorExtractor,之後便被加入到mOnColorsChangedListeners裏面,過程很簡單,這裏就不再贅述了。之後自然是調用StatusBar的onColorsChanged()了:
最後在updateTheme()這個方法中修改SystemUI相關的深色和淺色主題。
以上就是整個註冊以及響應的流程了,至於到了updateTheme()之後SystemUI是以怎樣的方式去具體修改那些控件的主題的,後續有時間會繼續再研究壹下。