android Gui系統之WMS(1)----window flags & view flags


SurfaceFlinger 前面說的,就是一個surface的合成。SurfaceFlinger就是一個默默的記錄着,它不會對surface的內容有什么改動。

WMS(WindowsManagerService)就是對surface的管理,或者說是一個大管家。它負責協調各方面資源。

ViewRoot就是一個個演員,負責表演(產生surface)。

從IO系統角度而言,WMS至少要干這幾件事。

全局窗口管理

全局事件派發

鍵盤

觸摸屏

1.WMS綜述

1)WMS將以同AMS等一樣的形式,系統server的一部分。

由SystemServer負責啟動

知道系統關閉才能停止

發生異常的時候,能夠自我恢復

2)SurfaceFlinger 和WMS將有很多交集。

3)有顯示需求的圖層。可以想見,界面顯示是分不同層級的。

4)inputManagerService 當有按鍵或者觸摸事件時,WMS時最好的管理員。

5)AMS 同WMS 也有交互。

6)Bind交互

從WMS窗口的實現來講,主要包含如下子功能

窗口的添加和刪除

啟動窗口

窗口動畫

窗口大小

窗口層級

事件派發

1.1WMS的啟動

 services\java\com\android\server\SystemServer.java

private void startOtherServices() {
            inputManager = new InputManagerService(context);
            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);

            traceBeginAndSlog("StartWindowManagerService");
            wm = WindowManagerService.main(context, inputManager,
                    mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL,
                    !mFirstBoot, mOnlyCore);
            ServiceManager.addService(Context.WINDOW_SERVICE, wm);
            ServiceManager.addService(Context.INPUT_SERVICE, inputManager);
}

1.2 WMS提供的服務

public class IWindowManagerImpl implements IWindowManager 

提供了很多功能,包含屏幕獲取,獲取窗口大小,啟動窗口等

1.3 WMS工作方式

WMS很復雜,以工作方式作為切入點是比較合適的。

 WMS,AMS,Activity之間的關系

WMS 可以和AMS相互調用,Activity有Window的對象。

   public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

可以看到,是windowmanager提供的一個session

當啟動一個activity的時候,AMS會把記錄放到activityRecord。同時WMS會對activity進行記錄,就用WindowState

 

2.窗口屬性

2.1窗口的層級和類型

窗口的類型很多,不過,可以統一划分為3類,Application Window,System Window,Sub Window.

它們全部定義在WindowManager.java

2.1.1 普通窗口

2.1.2 Sub Window

這一類主要就是Dialog 之類的。

2.1.3 系統窗口

系統窗口非常多,主要由系統狀態欄,來電,輸入法等。

具體的取值:

Application Window:1-99

SubWindow:100-1999

SystemWindow:2000-2999

當某個進程向WMS申請一個Window的時候,需要告訴系統窗口的類型。如果有3個app在運行中,則前台有3個窗口,這個時候,需要能調整它們的優先級。

對於Window的顯示,層級越高,顯示越前面。這個顯示的動作,由SurfaceFlinger來處理。

 if ((mAttrs.type >= FIRST_SUB_WINDOW &&
                mAttrs.type <= LAST_SUB_WINDOW)) {
            // The multiplier here is to reserve space for multiple
            // windows in the same type layer.
            mBaseLayer = mPolicy.windowTypeToLayerLw(
                    attachedWindow.mAttrs.type) * WindowManagerService.TYPE_LAYER_MULTIPLIER
                    + WindowManagerService.TYPE_LAYER_OFFSET;
            mSubLayer = mPolicy.subWindowTypeToLayerLw(a.type);
            mAttachedWindow = attachedWindow;
......

所有窗口的mBaseLayer可以分幾步獲得:

@Step1:windowTypeToLayerLw

這個根據不同的窗口類型做了簡單的映射。

@Override
    public int windowTypeToLayerLw(int type) {
        if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
            return 2;
        }
        switch (type) {
        case TYPE_PRIVATE_PRESENTATION:
            return 2;
        case TYPE_WALLPAPER:
            // wallpaper is at the bottom, though the window manager may move it.
            return 2;
        case TYPE_PHONE:
            return 3;
        case TYPE_SEARCH_BAR:
        case TYPE_VOICE_INTERACTION_STARTING:
            return 4;
        case TYPE_VOICE_INTERACTION:
            // voice interaction layer is almost immediately above apps.
            return 5;
        case TYPE_INPUT_CONSUMER:
            return 6;
        case TYPE_SYSTEM_DIALOG:
            return 7;
        case TYPE_TOAST:
            // toasts and the plugged-in battery thing
            return 8;
        case TYPE_PRIORITY_PHONE:
            // SIM errors and unlock.  Not sure if this really should be in a high layer.
            return 9;
        case TYPE_DREAM:
            // used for Dreams (screensavers with TYPE_DREAM windows)
            return 10;
        case TYPE_SYSTEM_ALERT:
            // like the ANR / app crashed dialogs
            return 11;
        case TYPE_INPUT_METHOD:
            // on-screen keyboards and other such input method user interfaces go here.
            return 12;
        case TYPE_INPUT_METHOD_DIALOG:
            // on-screen keyboards and other such input method user interfaces go here.
            return 13;
        case TYPE_KEYGUARD_SCRIM:
            // the safety window that shows behind keyguard while keyguard is starting
            return 14;
        case TYPE_STATUS_BAR_SUB_PANEL:
            return 15;
        case TYPE_STATUS_BAR:
            return 16;
        case TYPE_STATUS_BAR_PANEL:
            return 17;
        case TYPE_KEYGUARD_DIALOG:
            return 18;
        case TYPE_VOLUME_OVERLAY:
            // the on-screen volume indicator and controller shown when the user
            // changes the device volume
            return 19;
        case TYPE_SYSTEM_OVERLAY:
            // the on-screen volume indicator and controller shown when the user
            // changes the device volume
            return 20;
        case TYPE_NAVIGATION_BAR:
            // the navigation bar, if available, shows atop most things
            return 21;
        case TYPE_NAVIGATION_BAR_PANEL:
            // some panels (e.g. search) need to show on top of the navigation bar
            return 22;
        case TYPE_SYSTEM_ERROR:
            // system-level error dialogs
            return 23;
        case TYPE_MAGNIFICATION_OVERLAY:
            // used to highlight the magnified portion of a display
            return 24;
        case TYPE_DISPLAY_OVERLAY:
            // used to simulate secondary display devices
            return 25;
        case TYPE_DRAG:
            // the drag layer: input for drag-and-drop is associated with this window,
            // which sits above all other focusable windows
            return 26;
        case TYPE_ACCESSIBILITY_OVERLAY:
            // overlay put by accessibility services to intercept user interaction
            return 27;
        case TYPE_SECURE_SYSTEM_OVERLAY:
            return 28;
        case TYPE_BOOT_PROGRESS:
            return 29;
        case TYPE_POINTER:
            // the (mouse) pointer layer
            return 30;
        }
        Log.e(TAG, "Unknown window type: " + type);
        return 2;
    }
windowTypeToLayerLw

對於sub window而言,窗口類型取決於父窗口類型。

@Step2. 上一步獲得的值*TYPE_LAYER_MULTIPLIER(10000)+TYPE_LAYER_OFFSET(1000)

同一類型的窗口可能由很多。1000.是為了移動一組window而設計的。

@Step3.subWindowTypeToLayerLw 計算子窗口的layer。偏移量在1,或者-2都有可能。所以子窗口現在在父窗口的上面。或者下面,都可能。

 

2.2窗口屬性

windowmanagerprolicy。android顯示的同一的規則。手機有StatusBar,而平板有CombinedBar。類似,但是功能不一樣。

/**
 * WindowManagerPolicy implementation for the Android phone UI.  This
 * introduces a new method suffix, Lp, for an internal lock of the
 * PhoneWindowManager.  This is used to protect some internal state, and
 * can be acquired with either the Lw and Li lock held, so has the restrictions
 * of both of those when held.
 */
public class PhoneWindowManager implements WindowManagerPolicy

PhoneWindowManager 和call沒有關系,它表述andorid phone的UI顯示規則。

2.3 layoutParams

1)Type

窗口類型,不再說明。

2)Flags

最典型的就是,保持屏幕常亮。這個可以使用FLAG_KEEP_SCREEN_ON。

在activity下使用這個方法就可以:

getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

FLAG_ALLOW_LOCK_WHILE_SCREEN_ON:只要此窗口可見,即使屏幕點亮,也允許鎖屏。 從現實來講,有這個需求嗎? 測驗后,實際效果,會半暗屏,但不會上鎖。

FLAG_DIM_BEHIND:在窗口后面的東西,都將變暗。 dialog之類的比較常用。一個非常有用的flag,尤其是需要做蒙層的時候。

public class DimDialog extends Dialog {
    private static final float DIMDIALOG_TRANTANT = 0.3f;
    private static final float DIMDIALOG_BG_TRANTANT = 0.8f;
    public DimDialog(Context context) {
        super(context);
        setAttributes();
    }

    private void setAttributes() {
        WindowManager.LayoutParams lp=getWindow().getAttributes();
        lp.alpha=DIMDIALOG_TRANTANT;
        lp.dimAmount = DIMDIALOG_BG_TRANTANT;
        getWindow().setAttributes(lp);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
    }

    public DimDialog(Context context, int themeResId) {
        super(context, themeResId);
        setAttributes();
    }

    protected DimDialog(Context context, boolean cancelable, OnCancelListener cancelListener) {
        super(context, cancelable, cancelListener);
        setAttributes();
    }
}
DimDialog

FLAG_BLUR_BEHIND:高斯模糊,目前已經廢棄,對性能的影響巨大,不建議使用。

FLAG_NOT_FOCUSABLE:窗口不處理事件,將會傳遞到后面的其他窗口。同時FLAG_NOT_TOUCH_MODAL也會被設置。

FLAG_NOT_TOUCHABLE:touch 事件傳遞到后面的窗口使用。

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE|WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
        |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);

FLAG_KEEP_SCREEN_ON:最常用,最經典的模式,屏幕常量

FLAG_FULLSCREEN:全屏,沒有狀態欄。

getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

動態調整全屏狀態:

    private void full(boolean enable) {
        if (enable) {
            WindowManager.LayoutParams lp = getWindow().getAttributes();
            lp.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN;
            getWindow().setAttributes(lp);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
        } else {
            WindowManager.LayoutParams attr = getWindow().getAttributes();
            attr.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN);
            getWindow().setAttributes(attr);
            getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
        }
    }
full

FLAG_FORCE_NOT_FULLSCREEN:同FLAG_FULLSCREEN相反

FLAG_SECURE:窗口無法被截屏。不安全的應用也無法顯示等。

FLAG_SCALED:按用戶的要求調整窗口

FLAG_IGNORE_CHEEK_PRESSES: 當屏幕有可能貼着臉時,這一選項可防止面頰對屏幕造成誤操作。 

FLAG_LAYOUT_INSET_DECOR:只能和FLAG_LAYOUT_IN_SCREEN一起使用,充分考慮各種情況

FLAG_SHOW_WHEN_LOCKED:在鎖屏的時候,可以顯示該頁面,也是非常重要的flag。關於鎖屏的問題可以參考 鎖屏上顯示Activity 這篇博客,此處不再敘述。

FLAG_SHOW_WALLPAPER:當前activity為透明或者半透明的時候,讓壁紙作為背景。

        WindowManager.LayoutParams lp=getWindow().getAttributes();
        lp.alpha = 0.5f;
        getWindow().setAttributes(lp);//設置透明度
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);//設置壁紙

FLAG_TURN_SCREEN_ON:把屏幕點亮

FLAG_DISMISS_KEYGUARD:解鎖。是指普通鎖屏,但是安全鎖(圖案或者密碼鎖屏界面)是無效的。 在電話界面,可以直接解鎖,而不需進入鎖屏界面。

FLAG_HARDWARE_ACCELERATED:硬件加速,具體取決於硬件條件。

3)systemUiVisibilty

這個flag,定義在View中,

這里先明確,這些flag起作用,首先這個view必須是可見的。而window的flag是全局的。

View.SYSTEM_UI_FLAG_VISIBLE:顯示狀態欄 View.INVISIBLE 對應屬性,隱藏狀態欄。

View.SYSTEM_UI_FLAG_FULLSCREEN 和上節講到的FLAG_FULLSCREEN具有相同的效果,具體的細微差距,請參考http://www.360doc.com/content/15/0204/18/20385871_446270224.shtml 這篇文章。此處不做詳細討論。

根據經驗,View可以是臨時的,而FLAG_FULLSCREEN 可以是長期的。

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 可以是navigationbar隱藏。

View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN activity全屏顯示,但是statusbar不會隱藏,會把activity上面的部分,覆蓋。

View.SYSTEM_UI_FLAG_IMMERSIVE ,在5.1上測試的結果同SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 類似,activity全屏,但statusbar仍然存在。半透明的狀態,但是狀態欄點擊會有反映。

View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY 在statusbar隱藏后,過幾秒會自動出現。

這里還要注意getWindow().getDecorView().setSystemUiVisibility();同setContentView(layout.activity_wall_layout);的順序問題。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM