<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                #### 1.WindowToken的意義 為了搞清楚WindowToken的作用是什么,看一下其位于WindowToken.java中的定義。雖然它沒有定義任何函數,但其成員變量的意義卻很重要。 - WindowToken將屬于同一個應用組件的窗口組織在了一起。所謂的應用組件可以是Activity、InputMethod、Wallpaper以及Dream。在WMS對窗口的管理過程中,用WindowToken指代一個應用組件。例如在進行窗口ZOrder排序時,屬于同一個WindowToken的窗口會被安排在一起,而且在其中定義的一些屬性將會影響所有屬于此WindowToken的窗口。這些都表明了屬于同一個WindowToken的窗口之間的緊密聯系。 - WindowToken具有令牌的作用,是對應用組件的行為進行規范管理的一個手段。WindowToken由應用組件或其管理者負責向WMS聲明并持有。應用組件在需要新的窗口時,必須提供WindowToken以表明自己的身份,并且窗口的類型必須與所持有的WindowToken的類型一致。從上面的代碼可以看到,在創建系統類型的窗口時不需要提供一個有效的Token,WMS會隱式地為其聲明一個WindowToken,看起來誰都可以添加個系統級的窗口。難道Android為了內部使用方便而置安全于不顧嗎?非也,addWindow()函數一開始的mPolicy.checkAddPermission()的目的就是如此。它要求客戶端必須擁有SYSTEM\_ALERT\_WINDOW或INTERNAL\_SYSTEM\_WINDOW權限才能創建系統類型的窗口。 #### 2.向WMS聲明WindowToken 既然應用組件在創建一個窗口時必須指定一個有效的WindowToken才行,那么WindowToken究竟該如何聲明呢? 在SampleWindow應用中,使用wms.addWindowToken()函數聲明mToken作為它的令牌,所以在添加窗口時,通過設置lp.token為mToken向WMS進行出示,從而獲得WMS添加窗口的許可。這說明,只要是一個Binder對象(隨便一個),都可以作為Token向WMS進行聲明。**對于WMS的客戶端來說,Token僅僅是一個Binder對象而已**。 為了驗證這一點,來看一下addWindowToken的代碼,如下所示: **WindowManagerService.java::WindowManagerService.addWindowToken()** ``` @Override publicvoid addWindowToken(IBinder token, int type) { // 需要聲明Token的調用者擁有MANAGE_APP_TOKENS的權限 if(!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "addWindowToken()")) { thrownew SecurityException("Requires MANAGE_APP_TOKENS permission"); } synchronized(mWindowMap){ ...... // 注意其構造函數的參數與addWindow()中不同,最后一個參數為true,表明這個Token // 是顯式申明的 wtoken= new WindowToken(this, token, type, true); mTokenMap.put(token,wtoken); ...... } } ``` 使用addWindowToken()函數聲明Token,將會在WMS中創建一個WindowToken實例,并添加到mTokenMap中,鍵值為客戶端用于聲明Token的Binder實例。與addWindow()函數中隱式地創建WindowToken不同,這里的WindowToken被聲明為顯式的。隱式與顯式的區別在于,當隱式創建的WindowToken的最后一個窗口被移除后,此WindowToken會被一并從mTokenMap中移除。顯式創建的WindowToken只能通過removeWindowToken()顯式地移除。 addWindowToken()這個函數告訴我們,WindowToken其實有兩層含義: - 對于顯示組件(客戶端)而言的Token,是任意一個Binder的實例,對顯示組件(客戶端)來說僅僅是一個創建窗口的令牌,沒有其他的含義。 - 對于WMS而言的WindowToken這是一個WindowToken類的實例,保存了對應于客戶端一側的Token(Binder實例),并以這個Token為鍵,存儲于mTokenMap中。客戶端一側的Token是否已被聲明,取決于其對應的WindowToken是否位于mTokenMap中。 * * * * * **注意** 在一般情況下,稱顯示組件(客戶端)一側Binder的實例為Token,而稱WMS一側的WindowToken對象為WindowToken。但是為了敘述方便,在沒有歧義的前提下不會過分仔細地區分這兩個概念。 * * * * * 接下來,看一下各種顯示組件是如何聲明WindowToken的。 ##### (1) Wallpaper和InputMethod的Token Wallpaper的Token聲明在WallpaperManagerService中。參考以下代碼: **WallpaperManagerService.java::WallpaperManagerService.bindWallpaperComponentLocked()** ``` BooleanbindWallpaperComponentLocked(......) { ...... WallpaperConnection newConn = new WallpaperConnection(wi, wallpaper); ...... mIWindowManager.addWindowToken(newConn.mToken, WindowManager.LayoutParams.TYPE_WALLPAPER); ...... } ``` WallpaperManagerService是Wallpaper管理器,它負責維護系統已安裝的所有的Wallpaper并在它們之間進行切換,而這個函數的目的是準備顯示一個Wallpaper。newConn.mToken與SampleWindow例子一樣,是一個簡單的Binder對象。這個Token將在即將顯示出來的Wallpaper被連接時傳遞給它,之后Wallpaper即可通過這個Token向WMS申請創建繪制壁紙所需的窗口了。 >[info] **注意** :WallpaperManagerService向WMS聲明的Token類型為TYPE\_WALLPAPER,所以,Wallpaper僅能本分地創建TYPE\_WALLPAPER類型的窗口。 相應的,WallpaperManagerService會在detachWallpaperLocked()函數中取消對Token的聲明: **WallpaperManagerService.java::WallpaperManagerService.detachWallpaperLocked()** ``` booleandetachWallpaperLocked(WallpaperData wallpaper){ ...... mIWindowManager.removeWindowToken(wallpaper.connection.mToken); ...... } ``` 再此之后,如果這個被detach的Wallpaper想再要創建窗口便不再可能了。 WallpaperManagerService使用WindowToken對一個特定的Wallpaper做出了如下限制: - Wallpaper只能創建TYPE\_WALLPAPER類型的窗口。 - Wallpaper顯示的生命周期由WallpaperManagerService牢牢地控制著。僅有當前的Wallpaper才能創建窗口并顯示內容。其他的Wallpaper由于沒有有效的Token,而無法創建窗口。 InputMethod的Token的來源與Wallpaper類似,其聲明位于InputMethodManagerService的startInputInnerLocked()函數中,取消聲明的位置在InputmethodManagerService的unbindCurrentMethodLocked()函數。InputMethodManagerService通過Token限制著每一個InputMethod的窗口類型以及顯示生命周期。 ##### (2) Activity的Token Activity的Token的使用方式與Wallpaper和InputMethod類似,但是其包含更多的內容。畢竟,對于Activity,無論是其組成還是操作都比Wallpaper以及InputMethod復雜得多。對此,WMS專為Activity實現了一個WindowToken的子類:AppWindowToken。 既然AppWindowToken是為Activity服務的,那么其聲明自然在ActivityManagerService中。具體位置為ActivityStack.startActivityLocked(),也就是啟動Activity的時候。相關代碼如下: **ActivityStack.java::ActivityStack.startActivityLocked()** ``` private final void startActivityLocked(......) { ...... mService.mWindowManager.addAppToken(addPos,r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); ...... } ``` startActivityLocked()向WMS聲明r.appToken作為此Activity的Token,這個Token是在ActivityRecord的構造函數中創建的。隨然后在realStartActivityLocked()中將此Token交付給即將啟動的Activity。 **ActivityStack.java::ActivityStack.realStartActivityLocked()** ``` final boolean realStartActivityLocked(......) { ...... app.thread.scheduleLaunchActivity(newIntent(r.intent), **r.appToken,** System.identityHashCode(r), r.info, newConfiguration(mService.mConfiguration), r.compat, r.icicle, results, newIntents,!andResume, mService.isNextTransitionForward(),profileFile, profileFd, profileAutoStop); ...... } ``` 啟動后的Activity即可使用此Token創建類型為TYPE\_APPLICATION的窗口了。 取消Token的聲明則位于ActivityStack.removeActivityFromHistoryLocked()函數中。 Activity的Token在客戶端是否和Wallpaper一樣,僅僅是一個基本的Binder實例呢?其實不然。看一下r.appToken的定義可以發現,這個Token的類型是IApplicationToken.Stub。其中定義了一系列和窗口相關的一些通知回調,它們是: - windowsDrawn(),當窗口完成初次繪制后通知AMS。 - windowsVisible(),當窗口可見時通知AMS。 - windowsGone(),當窗口不可見時通知AMS。 - keyDispatchingTimeout(),窗口沒能按時完成輸入事件的處理。這個回調將會導致ANR。 - getKeyDispatchingTimeout(),從AMS處獲取界定ANR的時間。 AMS通過ActivityRecord表示一個Activity。而ActivityRecord的appToken在其構造函數中被創建,所以每個ActivityRecord擁有其各自的appToken。而WMS接受AMS對Token的聲明,并為appToken創建了唯一的一個AppWindowToken。因此,這個類型為IApplicationToken的Binder對象appToken粘結了AMS的ActivityRecord與WMS的AppWindowToken,只要給定一個ActivityRecord,都可以通過appToken在WMS中找到一個對應的AppWindowToken,從而使得AMS擁有了操縱Activity的窗口繪制的能力。例如,當AMS認為一個Activity需要被隱藏時,以Activity對應的ActivityRecord所擁有的appToken作為參數調用WMS的setAppVisibility()函數。此函數通過appToken找到其對應的AppWindowToken,然后將屬于這個Token的所有窗口隱藏。 * * * * * **注意**: 每當AMS因為某些原因(如啟動/結束一個Activity,或將Task移到前臺或后臺)而調整ActivityRecord在mHistory中的順序時,都會調用WMS相關的接口移動AppWindowToken在mAppTokens中的順序,以保證兩者的順序一致。在后面講解窗口排序規則時會介紹到,AppWindowToken的順序對窗口的順序影響非常大。 * * * * *
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看