欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

目錄

Android Framework “系統(tǒng)的UI”——SystemUI

SystemUI的實(shí)現(xiàn)

以StatusBar為例,來分析下Android系統(tǒng)具體是如何實(shí)現(xiàn)它們的。 相關(guān)代碼分為兩部分,即:

Service部分

代碼路徑:frameworks/base/services/java/com/android/server。

應(yīng)用部分

代碼路徑:frameworks/base/packages/SystemUI。

下面來看看SystemUI的“目錄”:

android:allowBackup="false"android:hardwareAccelerated="true"android:label="@string/app_ label" android:icon="@*android:drawable/platlogo"android:supportsRtl="true" >

/*SystemUIService是我們分析的重點(diǎn),狀態(tài)欄等系統(tǒng)UI實(shí)現(xiàn)都是在這里完成的*/

android:process=":screenshot" android:exported="false" />/*由此可知,SystemUI提供了

截屏操作。有興趣的讀者可以自己研究下是如何實(shí)現(xiàn)的*/

/*開機(jī)自啟動(dòng),

不過這里啟動(dòng)的是LoadAverageService,而不是SystemUIService*/

通過AndroidManfiest我們知道SystemUIService是整個(gè)系統(tǒng)UI的“載體”,所以接下來將根據(jù)這一線索來把整個(gè)代碼流程“串”起來。和其他很多系統(tǒng)服務(wù)一樣,SystemUIService也是在SystemServer中啟動(dòng)的。具體而言,SystemServer會(huì)在適當(dāng)?shù)臅r(shí)機(jī)通知ActivityManagerService“系統(tǒng)已經(jīng)就緒(systemReady),可以進(jìn)一步運(yùn)行第三方模塊了”——這其中就包括將由startServiceAsUser啟動(dòng)的SystemUIService。

SystemUIService繼承了標(biāo)準(zhǔn)的Service組件,因而必須重載onCreate接口:

/*frameworks/base/packages/systemui/src/com/android/systemui/SystemUIService.java*/

public void onCreate() {…

IWindowManager wm = WindowManagerGlobal.getWindowManagerService();//獲取WMS服務(wù)

try {

SERVICES[0] = wm.hasSystemNavBar()? R.string.config_systemBarComponent

: R.string.config_statusBarComponent;//是StatusBar還是SystemBar?

} catch (RemoteException e) {

Slog.w(TAG, "Failing checking whether status bar can hide", e);

}

final int N = SERVICES.length;

mServices = new SystemUI[N];

for (int i=0; i

Class cl = chooseClass(SERVICES[i]);

Slog.d(TAG, "loading: " + cl);

try {

mServices[i] = (SystemUI)cl.newInstance();

} …

mServices[i].mContext = this;

Slog.d(TAG, "running: " + mServices[i]);

mServices[i].start();//mServices中的每個(gè)元素都繼承自SystemUI

}

}

SERVICES是一個(gè)object數(shù)組,它的初始值如下所示:

final Object[] SERVICES = new Object[] {

0, // system bar or status bar, filled in below.

com.android.systemui.power.PowerUI.class,

com.android.systemui.media.RingtonePlayer.class,

com.android.systemui.settings.SettingsUI.class,

};

其中,SERVICES[0]在初始化時(shí)沒有賦值。它將根據(jù)hasSystemNavBar的執(zhí)行結(jié)果來決定是用systemBar還是statusBar。上面這段代碼首先取出SERVICES數(shù)組中的class名,然后分別實(shí)例化它們,最后調(diào)用start接口統(tǒng)一啟動(dòng)。因此,每一個(gè)系統(tǒng)ui元素(包括statusBar,PowerUI等)都必須繼承自SystemUI這個(gè)抽象類,并重載其中的start方法。

函數(shù)hasSystemNavBar做了哪些判斷來對(duì)statusBar和systemBar進(jìn)行取舍呢?WindowManager的真正實(shí)現(xiàn)體是WindowManagerService。

/*frameworks/base/services/java/com/android/server/wm/WindowManagerService.java*/

public boolean hasSystemNavBar() {

return mPolicy.hasSystemNavBar();

}

**Policy是Android中定義UI行為的一個(gè)“規(guī)范”。**比如有沒有Navigation Bar,WindowLayer如何排布等。以PhoneWindowManager為例,它判斷當(dāng)前系統(tǒng)是否需要導(dǎo)航條。

我們假設(shè)設(shè)備的分辨率是800*480,屏幕密度為ldpi:

/*frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java*/

int shortSizeDp = shortSize*DisplayMetrics.DENSITY_DEFAULT/ density;

/*在這個(gè)場(chǎng)景中,shortSize=480,DENSITY_DEFAULT=160,density =120, 所以最終

shortSizeDp = 640*/

if (shortSizeDp < 600) {//在這個(gè)場(chǎng)景中不成立

mHasSystemNavBar = false;

mNavigationBarCanMove = true;

} else if (shortSizeDp < 720) {/*本場(chǎng)景屬于這一分支*/

mHasSystemNavBar = false;

mNavigationBarCanMove = false;

}

if (!mHasSystemNavBar) {//進(jìn)一步判斷是否有Navigation Bar

} else {

mHasNavigationBar = false;

}

所以在這個(gè)場(chǎng)景中,經(jīng)過上面的判決后mHasSystemNavBar為false。換句話說,對(duì)于分辨率800*480且密度為ldpi的屏幕,它的SERVICES[0]對(duì)應(yīng)的class類名是R.string.config_statusBar Component即“com.android.systemui.statusbar.phone.PhoneStatusBar”。下面以PhoneStatusBar為例來看看它的創(chuàng)建過程及具體樣式:

/*frameworks/base/packages/systemui/src/com/android/systemui/statusbar/phone/

PhoneStatusBar.java*/

public void start() {

mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))

.getDefaultDisplay();/*mDisplay記錄了當(dāng)前默認(rèn)顯示屏的大小,密度等等信息*/

super.start();// 關(guān)鍵語句,下面我們會(huì)重點(diǎn)介紹

addNavigationBar();/*不是所有Phone都需要Navigation Bar。比如設(shè)備本身已經(jīng)配備了物理按

鍵,這種情況下如果一直在屏幕上顯示導(dǎo)航條反而是一種累贅*/

}

PhoneStatusBar的“父類”是BaseStatusBar,很多框架性的操作都是在這里面完成的(但UI界面的具體描述還是會(huì)通過回調(diào)PhoneStatusBar中的方法來確定):

/*frameworks/base/packages/systemui/src/com/android/systemui/statusbar/BaseStatusBar.java*/

public void start() {…

mBarService = IStatusBarService.Stub.asInterface(

ServiceManager.getService(Context.STATUS_BAR_SERVICE));

// Connect in to the status bar manager service

StatusBarIconList iconList = new StatusBarIconList();//狀態(tài)欄圖標(biāo)列表

ArrayList notificationKeys = new ArrayList();

ArrayList notifications = new ArrayList();

mCommandQueue = new CommandQueue(this, iconList);

int[] switches = new int[7];

ArrayList binders = new ArrayList();

try {

mBarService.registerStatusBar(mCommandQueue,iconList,notificationKeys,

notifications,switches, binders); /*經(jīng)過一系列對(duì)象的創(chuàng)建與初始化后,開始向

StatusBarService進(jìn)行注冊(cè)。這里涉及跨進(jìn)程操作,因而傳遞的

參數(shù)都是繼承自Parcelable的*/

} catch (RemoteException ex) {

// If the system process isn't there we're doomed anyway.

}

createAndAddWindows(); /*這是真正將Status Bar顯示出來的地方*/

}

好不容易快到“水落石出”的時(shí)候了,但是上面這段代碼卻又殺出一個(gè)“程咬金”——StatusBarService。

既然SystemUI這個(gè)應(yīng)用程序中已經(jīng)有StatusBar了,為什么又需要StatusBarService?

先來看看StatusBarService是在哪里啟動(dòng)的。

/*frameworks/base/services/java/com/android/server/SystemServer.java*/

try {

Slog.i(TAG, "Status Bar");

statusBar = new StatusBarManagerService(context, wm); /*確實(shí)在這里。而且具體的實(shí)現(xiàn)類叫做StatusBarManagerService*/

ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);

} catch (Throwable e) {

reportWtf("starting StatusBarManagerService", e);

}

現(xiàn)在可以進(jìn)一步分析StatusBarManagerService的實(shí)現(xiàn)了。針對(duì)上面BaseStatusBar中調(diào)用的注冊(cè)操作:

public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList,List

notificationKeys,List notifications,

int switches[], List binders) {

enforceStatusBarService();

mBar = bar;

synchronized (mIcons) {

iconList.copyFrom(mIcons); /*復(fù)制Icon列表,注意方向是從StatusBarManager->

BaseStatusBar*/

}

synchronized (mNotifications) {

for (Map.Entry e: mNotifications.entrySet())

{

notificationKeys.add(e.getKey());

notifications.add(e.getValue());/*和Icon列表類似,方向也是從StatusBarManager

到BaseStatusBar*/

}

}

}

由上面這段代碼可以看出,registerStatusBar有兩個(gè)作用: 其一,為新啟動(dòng)的SystemUI應(yīng)用中的StatusBar賦予當(dāng)前系統(tǒng)的真實(shí)值(比如有多少需要顯示的圖標(biāo))。其二,通過成員變量mBar記錄下IStatusBar對(duì)象——它在SystemUI中對(duì)應(yīng)的是CommandQueue。

我們?cè)倩氐紹aseStatusBar。向StatusBarManagerService注冊(cè)完成后,它會(huì)執(zhí)行如下語句。

createAndAddWindows();

BaseStatusBar中的這個(gè)方法是抽象的,因而其子類PhoneStatusBar必須要重載它:

/*frameworks/base/packages/systemui/src/com/android/systemui/statusbar/phone/Ph-

oneStatusBar.java*/

public void createAndAddWindows() {

addStatusBarWindow();

}

private void addStatusBarWindow() {

final int height = getStatusBarHeight();/*首先獲取StatusBar的高度。默認(rèn)的高度值是通

過com.android.internal.R.dimen.status_bar_height來指定的,因而

開發(fā)人員如果需要更改StatusBar高度的話,可以考慮修改這個(gè)值*/

final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(

ViewGroup.LayoutParams.MATCH_PARENT, /*寬度是MATCH_PARENT*/

height, //高度值是可定制的

WindowManager.LayoutParams.TYPE_STATUS_BAR, /*指定窗口類型*/

WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|

WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING

| WindowManager.LayoutParams.FLAG_SPLIT_TOUCH,

/*設(shè)置flag, 下面還會(huì)加上硬件加速屬性*/

PixelFormat.TRANSLUCENT/*半透明的*/);

lp.flags |=windowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;

lp.gravity = getStatusBarGravity();/*設(shè)置Gravity屬性,默認(rèn)值為Gravity.TOP

|Gravity.FILL_HORIZONTAL,所以StatusBar是在屏幕上方*/

lp.setTitle("StatusBar"); //標(biāo)題

lp.packageName = mContext.getPackageName();

makeStatusBarView(); //下面會(huì)詳細(xì)介紹

mWindowManager.addView(mStatusBarWindow, lp); /*將一切就緒的mStatusBarWindow加入

WindowManager中。請(qǐng)參見本書顯示系統(tǒng)章節(jié)的講解*/

}

從makeStatusBarView這個(gè)函數(shù)名可以推斷出,StatusBarView會(huì)被創(chuàng)建并且初始化。先來了解下兩個(gè)重要的變量。

mStatusBarWindow 這是一個(gè)StatusBarWindowView類對(duì)象,同時(shí)我們通過addView傳給WindowManager的也是這個(gè)變量——說明它很可能包含了StatusBarView。 mStatusBarView 這就是makeStatusBarView需要操作的對(duì)象。

/*frameworks/base/packages/systemui/src/com/android/systemui/statusbar/phone/Ph-one

StatusBar.java*/

protected PhoneStatusBarView makeStatusBarView() {…

mStatusBarWindow = (StatusBarWindowView) View.inflate(context, R.layout.super_

status_bar, null);

mStatusBarWindow.mService = this; //mService其實(shí)指的是PhoneStatusBar

mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {//設(shè)置觸摸事件

@Override

public boolean onTouch(View v, MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_DOWN) {//支持下拉手勢(shì)

if (mExpandedVisible) {

animateCollapsePanels ();//通知欄的“下拉展開”需要?jiǎng)赢嬓Ч蝗粫?huì)很突兀

}

}

return mStatusBarWindow.onTouchEvent(event);

}});

mStatusBarView =(PhoneStatusBarView)mStatusBarWindow.findViewById(R.id.status_ bar);

mStatusBarView.setBar(this); /*狀態(tài)欄出場(chǎng)了*/

mNotificationPanel = (NotificationPanelView) mStatusBarWindow.

findViewById(R.id. notification_panel);

mNotificationPanel.setStatusBar(this); /*通知欄也很關(guān)鍵,只不過它只有在下拉后才會(huì)出現(xiàn)*/

/*從下面開始將利用mStatusBarView為PhoneStatusBar中的眾多內(nèi)部變量賦值*/

try {

boolean showNav = mWindowManagerService.hasNavigationBar();/*決定是否需要導(dǎo)航條*/

if (showNav) {

mNavigationBarView = (NavigationBarView) View.inflate(context,

R.layout. navigation_ bar, null);

/*Navigation Bar對(duì)應(yīng)的layout。有興趣的讀者可以自己看一下*/

}

} catch (RemoteException ex) {

/*Android中的不少代碼在捕捉異常時(shí),很常見的一種處理就是“聽天由命”…*/

}

/*接下來通過findViewById從mStatusBarView中獲取StatusIcons、NotificationIcons、

ClearButton等一系列按鍵。我們將會(huì)在StatusBar布局文件中做統(tǒng)一分析。這里暫時(shí)略過*/

/*最后動(dòng)態(tài)注冊(cè)需要接收的廣播,比如系統(tǒng)設(shè)置改變,屏幕關(guān)閉等*/

IntentFilter filter = new IntentFilter();

filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);

filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);

context.registerReceiver(mBroadcastReceiver, filter);…

return mStatusBarView;//注意最終返回值是mStatusBarWindow的子View

}

變量mStatuBarWindow來源于super_status_bar布局。它本質(zhì)上還是一個(gè)FrameLayout,包含的元素也很簡(jiǎn)單,就是status_bar和status_bar_expanded兩個(gè)布局,前者對(duì)應(yīng)的是狀態(tài)欄mStatusBarView,后者其實(shí)就是通知欄mNotificationPanel。為status_bar中的眾多元素(按鍵、背景等)進(jìn)行初始化。

最終的返回值是mStatusBarView。然后利用WindowManager的addView接口將mStatus- BarWindow(注意:不是mStatusBarView)添加進(jìn)窗口系統(tǒng)中。接下來的主動(dòng)權(quán)就轉(zhuǎn)交給WindowManager。

這樣我們就把StatusBar,Notification和NavigationBar的調(diào)用流程“串”起來了。

Android壁紙資源——WallpaperService

除了前面講解的狀態(tài)欄、通知欄外,壁紙也屬于SystemUI管理的一個(gè)重點(diǎn)。在Android系統(tǒng)中,用戶可以從設(shè)備內(nèi)部或者外存儲(chǔ)器(比如SD卡中)中選取圖片資源作為壁紙。另外,系統(tǒng)還支持動(dòng)態(tài)壁紙的顯示。

壁紙管理系統(tǒng)主要包括以下幾個(gè)方面。

WallpaperManagerService(WPMS) 它是壁紙機(jī)制的“大總管”,靜態(tài)、動(dòng)態(tài)壁紙都是在這里統(tǒng)一調(diào)度的。 WallpaperService(WPS) WPS繼承了標(biāo)準(zhǔn)的Service組件,因而它一定會(huì)實(shí)現(xiàn)onCreate、onDestroy、onBind等一系列方法。此外它還包含了一個(gè)重要的嵌套類engine,我們?cè)诤竺鏁?huì)做詳細(xì)講解。WPS是靜態(tài)、動(dòng)態(tài)壁紙的基類,代表了作為“壁紙”所應(yīng)該具有的一切屬性。 ImageWallpaper(IWP) 從名稱可以看出,它是靜態(tài)壁紙的實(shí)現(xiàn)類,而且一定是繼承自上面的WPS。

WallPaperManagerService

WPMS既然是基于AIDL實(shí)現(xiàn)的,我們來看看它的接口描述:

/*frameworks/base/core/java/android/app/IWallpaperManager.aidl*/

interface IWallpaperManager {

ParcelFileDescriptor setWallpaper(String name); /*設(shè)置壁紙*/

void setWallpaperComponent(in ComponentName name); /*設(shè)置動(dòng)態(tài)壁紙*/

ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,out Bundle outParams);

WallpaperInfo getWallpaperInfo();

}

從上面的接口定義可以看出,WPMS的工作并不復(fù)雜——它提供了全局的壁紙注冊(cè)、取消和查詢功能,并在接收到事件時(shí)進(jìn)行合理分配。

和其他系統(tǒng)服務(wù)一樣,WPMS是在SystemServer.java中啟動(dòng)并注冊(cè)進(jìn)ServiceManager中的,如下所示:

/*frameworks/base/services/java/com/android/server/SystemServer.java*/

try {

Slog.i(TAG, "Wallpaper Service");

if (!headless) {

wallpaper = new WallpaperManagerService(context);

ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper);

}

} catch (Throwable e) {

reportWtf("starting Wallpaper Service", e);

}

接下來的一個(gè)問題是:既然系統(tǒng)同時(shí)支持靜態(tài)壁紙和動(dòng)態(tài)壁紙,而且每種類型中還包含了N個(gè)實(shí)例(比如原生態(tài)系統(tǒng)就自帶多個(gè)動(dòng)態(tài)壁紙供用戶選擇),那么系統(tǒng)在顯示時(shí)是如何選擇的呢?我們很自然地會(huì)想到,在WPMS啟動(dòng)時(shí)它應(yīng)該會(huì)去讀取某個(gè)“配置文件”,這個(gè)文件記錄了用戶最近一次的選擇:

public WallpaperManagerService(Context context) {

loadSettingsLocked(UserHandle.USER_OWNER);//加載配置

}

當(dāng)WPMS構(gòu)造時(shí),它調(diào)用了loadSettingsLocked:

private void loadSettingsLocked(int userId) {//這里傳進(jìn)來的userId=0

try {

stream = new FileInputStream(file);

XmlPullParser parser = Xml.newPullParser();

parser.setInput(stream, null);

int type;

do {

type = parser.next();

if (type == XmlPullParser.START_TAG) {

String tag = parser.getName();

if ("wp".equals(tag)) {…

wallpaper.name = parser.getAttributeValue(null, "name");

String comp = parser.getAttributeValue(null, "component");

}

}

} while (type != XmlPullParser.END_DOCUMENT);

success = true;

}

}

上面這段代碼會(huì)按照寫入時(shí)的格式將wallpaper的配置信息讀出來,并保存在WallpaperData結(jié)構(gòu)中——專門用于描述壁紙信息的通用數(shù)據(jù)結(jié)構(gòu)。不過這時(shí)壁紙還沒有真正顯示出來,而是要等到系統(tǒng)進(jìn)入Ready狀態(tài)(此時(shí)系統(tǒng)會(huì)回調(diào)SystemReady接口)后才會(huì)通知具體的壁紙程序進(jìn)行繪制:

public void systemReady() {

WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_OWNER);

switchWallpaper(wallpaper, null);

}

接著進(jìn)入Wallpaper的具體處理中:

void switchWallpaper(WallpaperData wallpaper, IRemoteCallback reply) {

synchronized (mLock) {…

try {

ComponentName cname = wallpaper.wallpaperComponent != null ?

wallpaper.wallpaperComponent : wallpaper.nextWallpaperComponent;

if (bindWallpaperComponentLocked(cname, true, false, wallpaper,reply)) {

return;

}

} …

}

系統(tǒng)開機(jī)后,wallpaper.wallpaperComponent為空(除非上一次用戶選擇了其他方式);而wallpaper.nextWallpaperComponent則在loadSettingsLocked中被設(shè)置為wallpaper.imageWallpaper Component,即我們前面提到的ImageWallpaper這個(gè)Service。所以當(dāng)調(diào)用bindWallpaperComponentLocked時(shí),傳入的cname就代表了ImageWallpaper。從bindWallpaperComponentLocked的函數(shù)名稱可以看出,它將會(huì)以bindService的方式來啟動(dòng)目標(biāo)壁紙Service(所以后期如果確認(rèn)已經(jīng)不再使用這個(gè)Service,還要主動(dòng)執(zhí)行unbind,然后這個(gè)壁紙服務(wù)就會(huì)自動(dòng)銷毀)。

WPMS啟動(dòng)后就可以接收客戶端的請(qǐng)求了,因?yàn)樗鼘儆趯?shí)名的BinderServer,意味著所有人都可以自由地使用它所提供的服務(wù)。比如我們既可以在系統(tǒng)自帶的Launcher應(yīng)用程序中選擇壁紙,也完全可以自己編寫一個(gè)更改壁紙的應(yīng)用程序。

下面我們以設(shè)置壁紙這一場(chǎng)景為例來分析WPMS的內(nèi)部實(shí)現(xiàn):

/*frameworks/base/services/java/com/android/server/WallpaperManagerService.java*/

public ParcelFileDescriptor setWallpaper(String name) {

checkPermission(android.Manifest.permission.SET_WALLPAPER);

synchronized (mLock) {

int userId = UserHandle.getCallingUserId();

WallpaperData wallpaper = mWallpaperMap.get(userId);

final long ident = Binder.clearCallingIdentity();

try {

ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper);

return pfd;

} finally {

Binder.restoreCallingIdentity(ident);

}

}

}

首先系統(tǒng)會(huì)做下權(quán)限檢查,所以提供壁紙?jiān)O(shè)置功能的應(yīng)用程序一定要在AndroidManifest.xml中顯式寫上如下權(quán)限聲明:

變量wallpaper是從mWallpaperMap取出來的,代表UserId為0時(shí)的壁紙——如果不為空就進(jìn)入以下函數(shù):

ParcelFileDescriptor updateWallpaperBitmapLocked(String name, WallpaperData wallpaper) {

if (name == null) name = "";

try {

File dir = getWallpaperDir(wallpaper.userId);//wallpaper的路徑

if (!dir.exists()) {//指定的路徑不存在,需要?jiǎng)?chuàng)建

dir.mkdir();

FileUtils.setPermissions(dir.getPath(),

FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IXOTH, -1, -1);

}

File file = new File(dir, WALLPAPER);

ParcelFileDescriptor=ParcelFileDescriptor.open(file,

MODE_CREATE|MODE_READ_WRITE);

if (!SELinux.restorecon(file)) {

return null;

}

wallpaper.name = name;

return fd;

} catch (FileNotFoundException e) {

Slog.w(TAG, "Error setting wallpaper", e);

}

return null;

}

上面getWallpaperDir將得到一個(gè)WALLPAPER_BASE_DIR+“/”+userId的路徑,其中WALLPAPER_BASE_DIR默認(rèn)值是"/data/system/users"。

ImageWallpaper

前面講過,當(dāng)WPMS開機(jī)啟動(dòng)時(shí),默認(rèn)情況下會(huì)選擇ImageWallpaper這個(gè)壁紙實(shí)現(xiàn),并且以bindService的方式來啟動(dòng)它。在bindService中,WPMS同時(shí)傳入名為newConn的Binder對(duì)象(WallpaperConnection)來使ImageWallpaper(其他WallpaperService也是一樣的)可以訪問到WPMS。而ImageWallpaper則響應(yīng)onBind返回一個(gè)IWallpaperServiceWrapper的Binder對(duì)象,如圖所示。

我們來看看當(dāng)綁定成功后WPMS中的操作:

public void onServiceConnected(ComponentName name, IBinder service) {

synchronized (mLock) {

if (mWallpaper.connection == this) {…

attachServiceLocked(this, mWallpaper);

saveSettingsLocked(mWallpaper);

}

}

}

WPMS除了要保存當(dāng)前所選的壁紙外,還要調(diào)用attachServiceLocked(間接調(diào)用Iwallpaper ServiceWrapper.attach)來執(zhí)行實(shí)際的工作。

WPS這邊的attach函數(shù)將生成一個(gè)IWallpaperEngineWrapper對(duì)象并給它發(fā)送一個(gè)DO_ATTACH,這個(gè)消息最終由IWallpaperEngineWrapper. executeMessage來處理:

public void executeMessage(Message message) {

switch (message.what) {

case DO_ATTACH: {

try {

mConnection.attachEngine(this);

} catch (RemoteException e) {

Log.w(TAG, "Wallpaper host disappeared", e);

return;

}

Engine engine = onCreateEngine();

mEngine = engine;

mActiveEngines.add(engine);

engine.attach(this);

return;

}

上述代碼段通過onCreateEngine生成了一個(gè)壁紙引擎——這也是各壁紙應(yīng)用間最核心的差異。所以系統(tǒng)要求每一個(gè)WallpaperService實(shí)例必須要重載onCreateEngine來實(shí)現(xiàn)自己的engine。在ImageWallpaper中,它將產(chǎn)生一個(gè)DrawableEngine——這個(gè)engine隨后會(huì)被加入mActiveEngines的全局list中,然后調(diào)用它提供的attach接口。如下所示:

/*frameworks/base/core/java/android/service/wallpaper/WallpaperService.java*/

public class Engine {…

void attach(IWallpaperEngineWrapper wrapper) {…

mSession = WindowManagerGlobal.getWindowSession();

mWindow.setSession(mSession);

IntentFilter filter = new IntentFilter();

filter.addAction(Intent.ACTION_SCREEN_ON);

filter.addAction(Intent.ACTION_SCREEN_OFF);

registerReceiver(mReceiver, filter);

updateSurface(false, false, false);//更新Surface

}…

Engine內(nèi)部首先需要進(jìn)行各重要變量的初始化,然后注冊(cè)監(jiān)聽屏幕的開/關(guān)事件,最后調(diào)用updateSurface。

相關(guān)閱讀

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://m.gantiao.com.cn/post/18938410.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄