Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《一》

转载 http://blog.csdn.net/yanbober/article/details/46361191

1 背景

之所以写这一篇博客的原因是因为之前有写过一篇《Android应用setContentView与LayoutInflater加载解析机制源码分析》,然后有人在文章下面评论和微博私信中问我关于Android应用Activity、Dialog、PopWindow加载显示机制是咋回事,所以我就写一篇文章来分析分析吧(本文以Android5.1.1 (API 22)源码为基础分析),以便大家在应用层开发时不再迷糊。

PS一句:不仅有人微博私信我这个问题,还有人问博客插图这些是用啥画的,这里告诉大家。就是我,快来猛戳我

还记得之前《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇文章的最后分析结果吗?就是如下这幅图:

这里写图片描述

在那篇文章里我们当时重点是Activity的View加载解析xml机制分析,当时说到了Window的东西,但只是皮毛的分析了Activity相关的一些逻辑。(PS:看到这不清楚上面啥意思的建议先移步到《Android应用setContentView与LayoutInflater加载解析机制源码分析》,完事再回头继续看这篇文章。)当时给大家承诺过我们要从应用控件一点一点往下慢慢深入分析,所以现在开始深入,但是本篇的深入也只是仅限Window相关的东东,之后文章还会继续慢慢深入。

【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重劳动成果】
2 浅析Window与WindowManager相关关系及源码

通过上面那幅图可以很直观的看见,Android屏幕显示的就是Window和各种View,Activity在其中的作用主要是管理生命周期、建立窗口等。也就是说Window相关的东西对于Android屏幕来说是至关重要的(虽然前面分析Activity的setContentView等原理时说过一点Window,但那只是皮毛。),所以有必要在分析Android应用Activity、Dialog、PopWindow加载显示机制前再看看Window相关的一些东西。
2-1 Window与WindowManager基础关系

在分析Window与WindowManager之前我们先看一张图:

这里写图片描述

接下来看一点代码,如下:

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

可以看见,ViewManager接口定义了一组规则,也就是add、update、remove的操作View接口。也就是说ViewManager是用来添加和移除activity中View的接口。继续往下看:

public interface WindowManager extends ViewManager {
    ......
    public Display getDefaultDisplay();
    public void removeViewImmediate(View view);
    ......
    public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {
        ......
    }
}

看见没有,WindowManager继承自ViewManager,然后自己还是一个接口,同时又定义了一个静态内部类LayoutParams(这个类比较重要,后面会分析。提前透漏下,如果你在APP做过类似360助手屏幕的那个悬浮窗或者做过那种类似IOS的小白圆点,点击展开菜单功能,你或多或少就能猜到这个类的重要性。)。WindowManager用来在应用与Window之间的接口、窗口顺序、消息等的管理。继续看下ViewManager的另一个实现子类ViewGroup,如下:

public abstract class ViewGroup extends View implements ViewParent, ViewManager {
    //protected ViewParent mParent;
    //这个成员是View定义的,ViewGroup继承自View,所以也可以拥有。
    //这个变量就是前面我们一系列文章分析View向上传递的父节点,类似于一个链表Node的next一样
    //最终指向了ViewRoot
    ......
    public void addView(View child, LayoutParams params) {
        addView(child, -1, params);
    }

    ......

    public void addView(View child, int index, LayoutParams params) {
        ......
        // addViewInner() will call child.requestLayout() when setting the new LayoutParams
        // therefore, we call requestLayout() on ourselves before, so that the child's request
        // will be blocked at our level
        requestLayout();
        invalidate(true);
        addViewInner(child, index, params, false);
    }
    ......
}

这下理解上面那幅图了吧,所以说View通过ViewGroup的addView方法添加到ViewGroup中,而ViewGroup层层嵌套到最顶级都会显示在在一个窗口Window中(正如上面背景介绍中《Android应用setContentView与LayoutInflater加载解析机制源码分析》的示意图一样),其中每个View都有一个ViewParent类型的父节点mParent,最顶上的节点也是一个viewGroup,也即前面文章分析的Window的内部类DecorView(从《Android应用setContentView与LayoutInflater加载解析机制源码分析》的总结部分或者《Android应用层View绘制流程与源码分析》的5-1小节都可以验证这个结论)对象。同时通过上面背景中那幅图可以看出来,对于一个Activity只有一个DecorView(ViewRoot),也只有一个Window。

2-2 Activity窗口添加流程拓展

前面文章说过,ActivityThread类的performLaunchActivity方法中调运了activity.attach(…)方法进行初始化。如下是Activity的attach方法源码:

  final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
        ......
        //创建Window类型的mWindow对象,实际为PhoneWindow类实现了抽象Window类
        mWindow = PolicyManager.makeNewWindow(this);
        ......
        //通过抽象Window类的setWindowManager方法给Window类的成员变量WindowManager赋值实例化
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ......
        //把抽象Window类相关的WindowManager对象拿出来关联到Activity的WindowManager类型成员变量mWindowManager
        mWindowManager = mWindow.getWindowManager();
        ......
    }

看见没有,Activity类中的attach方法又创建了Window类型的新成员变量mWindow(PhoneWindow实现类)与Activity相关联,接着在Activity类的attach方法最后又通过mWindow.setWindowManager(…)方法创建了与Window相关联的WindowManager对象,最后又通过mWindow.getWindowManager()将Window的WindowManager成员变量赋值给Activity的WindowManager成员变量mWindowManager。

接下来我们看下上面代码中的mWindow.setWindowManager(…)方法源码(PhoneWindow没有重写抽象Window的setWindowManager方法,所以直接看Window类的该方法源码),如下:

public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        ......
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //实例化Window类的WindowManager类型成员mWindowManager
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

可以看见,Window的setWindowManager方法中通过WindowManagerImpl实例的createLocalWindowManager方法获取了WindowManager实例,如下:

public final class WindowManagerImpl implements WindowManager {
    ......
    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }
    ......
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }
    ......
}

看见没有?这样就把Activity的Window与WindowManager关联起来了。Activity类的Window类型成员变量mWindow及WindowManager类型成员变量mWindowManager就是这么来的。

回过头继续看上面刚刚贴的Activity的attach方法代码,看见mWindow.setWindowManager方法传递的第一个参数没?有人会想(WindowManager)context.getSystemService(Context.WINDOW_SERVICE)这行代码是什么意思,现在告诉你。

《Android应用Context详解及源码解析》一文中第三部分曾经说过ActivityThread中创建了Acitivty(执行attach等方法)等东东,在创建这个Activity之前得到了Context的实例。记不记得当时说Context的实现类就是ContextImpl吗?下面我们看下ContextImpl类的静态方法块,如下:

class ContextImpl extends Context {
    ......
    //静态代码块,类加载时执行一次
    static {
        ......
        //这里有一堆类似的XXX_SERVICE的注册
        ......
        registerService(WINDOW_SERVICE, new ServiceFetcher() {
                Display mDefaultDisplay;
                public Object getService(ContextImpl ctx) {
                    //搞一个Display实例
                    Display display = ctx.mDisplay;
                    if (display == null) {
                        if (mDefaultDisplay == null) {
                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                                    getSystemService(Context.DISPLAY_SERVICE);
                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
                        }
                        display = mDefaultDisplay;
                    }
                    //返回一个WindowManagerImpl实例
                    return new WindowManagerImpl(display);
                }});
        ......
    }
    //这就是你在外面调运Context的getSystemService获取到的WindowManagerImpl实例
    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }
    //上面static代码块创建WindowManagerImpl实例用到的方法
    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }
}

看见没有,我们都知道Java的静态代码块是类加载是执行一次的,也就相当于一个全局的,这样就相当于每个Application只有一个WindowManagerImpl(display)实例。

还记不记得《Android应用setContentView与LayoutInflater加载解析机制源码分析》一文2-6小节中说的,setContentView的实质显示是触发了Activity的resume状态,也就是触发了makeVisible方法,那我们再来看下这个方法,如下:

 void makeVisible() {
        if (!mWindowAdded) {
            //也就是获取Activity的mWindowManager
            //这个mWindowManager是在Activity的attach中通过mWindow.getWindowManager()获得
            ViewManager wm = getWindowManager();
            //调运的实质就是ViewManager接口的addView方法,传入的是mDecorView
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }

特别注意,看见makeVisible方法的wm变量没,这个变量就是Window类中通过调运WindowManagerImpl的createLocalWindowManager创建的实例,也就是说每一个Activity都会新创建这么一个WindowManager实例来显示Activity的界面的,有点和上面分析的ContextImpl中static块创建的WindowManager不太一样的地方就在于Context的WindowManager对每个APP来说是一个全局单例的,而Activity的WindowManager是每个Activity都会新创建一个的(其实你从上面分析的两个实例化WindowManagerImpl的构造函数参数传递就可以看出来,Activity中Window的WindowManager成员在构造实例化时传入给WindowManagerImpl中mParentWindow成员的是当前Window对象,而ContextImpl的static块中单例实例化WindowManagerImpl时传入给WindowManagerImpl中mParentWindow成员的是null值)。

继续看makeVisible中调运的WindowManagerImpl的addView方法如下:

public final class WindowManagerImpl implements WindowManager {
    //继承自Object的单例类
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ......
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //mParentWindow是上面分析的在Activity中获取WindowManagerImpl实例化时传入的当前Window
        //view是Activity中最顶层的mDecor
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    ......
}

这里当前传入的view是mDecor,LayoutParams呢?可以看见是getWindow().getAttributes(),那我们进去看看Window类的这个属性,如下:

// The current window attributes.
    private final WindowManager.LayoutParams mWindowAttributes = new WindowManager.LayoutParams();

原来是WindowManager的静态内部类LayoutParams的默认构造函数:

public LayoutParams() {
    super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    type = TYPE_APPLICATION;
    format = PixelFormat.OPAQUE;
}

看见没有,Activity窗体的WindowManager.LayoutParams类型是TYPE_APPLICATION的。

继续回到WindowManagerImpl的addView方法,分析可以看见WindowManagerImpl中有一个单例模式的WindowManagerGlobal成员mGlobal,addView最终调运了WindowManagerGlobal的addView,源码如下:

public final class WindowManagerGlobal {
    ......
    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

    ......
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ......
        //获取Activity的Window的getWindow().getAttributes()的LayoutParams 
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        //如果是Activity中调运的,parentWindow=Window,如果不是Activity的,譬如是Context的静态代码块的实例化则parentWindow为null
        if (parentWindow != null) {
            //依据当前Activity的Window调节sub Window的LayoutParams
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            ......
        }

        ViewRootImpl root;
        ......
        synchronized (mLock) {
            ......
            //为当前Window创建ViewRoot
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            //把当前Window相关的东西存入各自的List中,在remove中会删掉
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            //把View和ViewRoot关联起来,很重要!!!
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ......
        }
    }
    ......
}

可以看见,在addView方法中会利用LayoutParams获得Window的属性,然后为每个Window创建ViewRootImpl,最后通过ViewRootImpl的setView方法通过mSession向WindowManagerService发送添加窗口请求把窗口添加到WindowManager中,并且由WindowManager来管理窗口的view、事件、消息收集处理等(ViewRootImpl的这一添加过程后面会写文章分析,这里先记住这个概念即可)。

至此我们对上面背景中那幅图,也就是《Android应用setContentView与LayoutInflater加载解析机制源码分析》这篇文章总结部分的那幅图又进行了更深入的一点分析,其目的也就是为了下面分析Android应用Dialog、PopWindow、Toast加载显示机制做铺垫准备。

2-3 继续顺藤摸瓜WindowManager.LayoutParams类的源码

上面2-1分析Window与WindowManager基础关系时提到了WindowManager有一个静态内部类LayoutParams,它继承于ViewGroup.LayoutParams,用于向WindowManager描述Window的管理策略。现在我们来看下这个类(PS:在AD上也可以看见,自备梯子点我看AD的),如下:

public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {
        //窗口的绝对XY位置,需要考虑gravity属性
        public int x;
        public int y;
        //在横纵方向上为相关的View预留多少扩展像素,如果是0则此view不能被拉伸,其他情况下扩展像素被widget均分
        public float horizontalWeight;
        public float verticalWeight;
        //窗口类型
        //有3种主要类型如下:
        //ApplicationWindows取值在FIRST_APPLICATION_WINDOW与LAST_APPLICATION_WINDOW之间,是常用的顶层应用程序窗口,须将token设置成Activity的token;
        //SubWindows取值在FIRST_SUB_WINDOW和LAST_SUB_WINDOW之间,与顶层窗口相关联,需将token设置成它所附着宿主窗口的token;
        //SystemWindows取值在FIRST_SYSTEM_WINDOW和LAST_SYSTEM_WINDOW之间,不能用于应用程序,使用时需要有特殊权限,它是特定的系统功能才能使用;
        public int type;

        //WindowType:开始应用程序窗口
        public static final int FIRST_APPLICATION_WINDOW = 1;
        //WindowType:所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
        public static final int TYPE_BASE_APPLICATION   = 1;
        //WindowType:普通应用程序窗口,token必须设置为Activity的token来指定窗口属于谁
        public static final int TYPE_APPLICATION        = 2;
        //WindowType:应用程序启动时所显示的窗口,应用自己不要使用这种类型,它被系统用来显示一些信息,直到应用程序可以开启自己的窗口为止
        public static final int TYPE_APPLICATION_STARTING = 3;
        //WindowType:结束应用程序窗口
        public static final int LAST_APPLICATION_WINDOW = 99;

        //WindowType:SubWindows子窗口,子窗口的Z序和坐标空间都依赖于他们的宿主窗口
        public static final int FIRST_SUB_WINDOW        = 1000;
        //WindowType: 面板窗口,显示于宿主窗口的上层
        public static final int TYPE_APPLICATION_PANEL  = FIRST_SUB_WINDOW;
        //WindowType:媒体窗口(例如视频),显示于宿主窗口下层
        public static final int TYPE_APPLICATION_MEDIA  = FIRST_SUB_WINDOW+1;
        //WindowType:应用程序窗口的子面板,显示于所有面板窗口的上层
        public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2;
        //WindowType:对话框,类似于面板窗口,绘制类似于顶层窗口,而不是宿主的子窗口
        public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3;
        //WindowType:媒体信息,显示在媒体层和程序窗口之间,需要实现半透明效果
        public static final int TYPE_APPLICATION_MEDIA_OVERLAY  = FIRST_SUB_WINDOW+4;
        //WindowType:子窗口结束
        public static final int LAST_SUB_WINDOW         = 1999;

        //WindowType:系统窗口,非应用程序创建
        public static final int FIRST_SYSTEM_WINDOW     = 2000;
        //WindowType:状态栏,只能有一个状态栏,位于屏幕顶端,其他窗口都位于它下方
        public static final int TYPE_STATUS_BAR         = FIRST_SYSTEM_WINDOW;
        //WindowType:搜索栏,只能有一个搜索栏,位于屏幕上方
        public static final int TYPE_SEARCH_BAR         = FIRST_SYSTEM_WINDOW+1;
        //WindowType:电话窗口,它用于电话交互(特别是呼入),置于所有应用程序之上,状态栏之下
        public static final int TYPE_PHONE              = FIRST_SYSTEM_WINDOW+2;
        //WindowType:系统提示,出现在应用程序窗口之上
        public static final int TYPE_SYSTEM_ALERT       = FIRST_SYSTEM_WINDOW+3;
        //WindowType:锁屏窗口
        public static final int TYPE_KEYGUARD           = FIRST_SYSTEM_WINDOW+4;
        //WindowType:信息窗口,用于显示Toast
        public static final int TYPE_TOAST              = FIRST_SYSTEM_WINDOW+5;
        //WindowType:系统顶层窗口,显示在其他一切内容之上,此窗口不能获得输入焦点,否则影响锁屏
        public static final int TYPE_SYSTEM_OVERLAY     = FIRST_SYSTEM_WINDOW+6;
        //WindowType:电话优先,当锁屏时显示,此窗口不能获得输入焦点,否则影响锁屏
        public static final int TYPE_PRIORITY_PHONE     = FIRST_SYSTEM_WINDOW+7;
        //WindowType:系统对话框
        public static final int TYPE_SYSTEM_DIALOG      = FIRST_SYSTEM_WINDOW+8;
        //WindowType:锁屏时显示的对话框
        public static final int TYPE_KEYGUARD_DIALOG    = FIRST_SYSTEM_WINDOW+9;
        //WindowType:系统内部错误提示,显示于所有内容之上
        public static final int TYPE_SYSTEM_ERROR       = FIRST_SYSTEM_WINDOW+10;
        //WindowType:内部输入法窗口,显示于普通UI之上,应用程序可重新布局以免被此窗口覆盖
        public static final int TYPE_INPUT_METHOD       = FIRST_SYSTEM_WINDOW+11;
        //WindowType:内部输入法对话框,显示于当前输入法窗口之上
        public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;
        //WindowType:墙纸窗口
        public static final int TYPE_WALLPAPER          = FIRST_SYSTEM_WINDOW+13;
        //WindowType:状态栏的滑动面板
        public static final int TYPE_STATUS_BAR_PANEL   = FIRST_SYSTEM_WINDOW+14;
        //WindowType:安全系统覆盖窗口,这些窗户必须不带输入焦点,否则会干扰键盘
        public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;
        //WindowType:拖放伪窗口,只有一个阻力层(最多),它被放置在所有其他窗口上面
        public static final int TYPE_DRAG               = FIRST_SYSTEM_WINDOW+16;
        //WindowType:状态栏下拉面板
        public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;
        //WindowType:鼠标指针
        public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;
        //WindowType:导航栏(有别于状态栏时)
        public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;
        //WindowType:音量级别的覆盖对话框,显示当用户更改系统音量大小
        public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;
        //WindowType:起机进度框,在一切之上
        public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;
        //WindowType:假窗,消费导航栏隐藏时触摸事件
        public static final int TYPE_HIDDEN_NAV_CONSUMER = FIRST_SYSTEM_WINDOW+22;
        //WindowType:梦想(屏保)窗口,略高于键盘
        public static final int TYPE_DREAM = FIRST_SYSTEM_WINDOW+23;
        //WindowType:导航栏面板(不同于状态栏的导航栏)
        public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;
        //WindowType:universe背后真正的窗户
        public static final int TYPE_UNIVERSE_BACKGROUND = FIRST_SYSTEM_WINDOW+25;
        //WindowType:显示窗口覆盖,用于模拟辅助显示设备
        public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;
        //WindowType:放大窗口覆盖,用于突出显示的放大部分可访问性放大时启用
        public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;
        //WindowType:......
        public static final int TYPE_KEYGUARD_SCRIM           = FIRST_SYSTEM_WINDOW+29;
        public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;
        public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;
        public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;
        //WindowType:系统窗口结束
        public static final int LAST_SYSTEM_WINDOW      = 2999;

        //MemoryType:窗口缓冲位于主内存
        public static final int MEMORY_TYPE_NORMAL = 0;
        //MemoryType:窗口缓冲位于可以被DMA访问,或者硬件加速的内存区域
        public static final int MEMORY_TYPE_HARDWARE = 1;
        //MemoryType:窗口缓冲位于可被图形加速器访问的区域
        public static final int MEMORY_TYPE_GPU = 2;
        //MemoryType:窗口缓冲不拥有自己的缓冲区,不能被锁定,缓冲区由本地方法提供
        public static final int MEMORY_TYPE_PUSH_BUFFERS = 3;

        //指出窗口所使用的内存缓冲类型,默认为NORMAL 
        public int memoryType;

        //Flag:当该window对用户可见的时候,允许锁屏
        public static final int FLAG_ALLOW_LOCK_WHILE_SCREEN_ON     = 0x00000001;
        //Flag:让该window后所有的东西都成暗淡
        public static final int FLAG_DIM_BEHIND        = 0x00000002;
        //Flag:让该window后所有东西都模糊(4.0以上已经放弃这种毛玻璃效果)
        public static final int FLAG_BLUR_BEHIND        = 0x00000004;
        //Flag:让window不能获得焦点,这样用户快就不能向该window发送按键事
        public static final int FLAG_NOT_FOCUSABLE      = 0x00000008;
        //Flag:让该window不接受触摸屏事件
        public static final int FLAG_NOT_TOUCHABLE      = 0x00000010;
        //Flag:即使在该window在可获得焦点情况下,依旧把该window之外的任何event发送到该window之后的其他window
        public static final int FLAG_NOT_TOUCH_MODAL    = 0x00000020;
        //Flag:当手机处于睡眠状态时,如果屏幕被按下,那么该window将第一个收到
        public static final int FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040;
        //Flag:当该window对用户可见时,让设备屏幕处于高亮(bright)状态
        public static final int FLAG_KEEP_SCREEN_ON     = 0x00000080;
        //Flag:让window占满整个手机屏幕,不留任何边界
        public static final int FLAG_LAYOUT_IN_SCREEN   = 0x00000100;
        //Flag:window大小不再不受手机屏幕大小限制,即window可能超出屏幕之外
        public static final int FLAG_LAYOUT_NO_LIMITS   = 0x00000200;
        //Flag:window全屏显示
        public static final int FLAG_FULLSCREEN      = 0x00000400;
        //Flag:恢复window非全屏显示
        public static final int FLAG_FORCE_NOT_FULLSCREEN   = 0x00000800;
        //Flag:开启抖动(dithering)
        public static final int FLAG_DITHER             = 0x00001000;
        //Flag:当该window在进行显示的时候,不允许截屏
        public static final int FLAG_SECURE             = 0x00002000;
        //Flag:一个特殊模式的布局参数用于执行扩展表面合成时到屏幕上
        public static final int FLAG_SCALED             = 0x00004000;
        //Flag:用于windows时,经常会使用屏幕用户持有反对他们的脸,它将积极过滤事件流,以防止意外按在这种情况下,可能不需要为特定的窗口,在检测到这样一个事件流时,应用程序将接收取消运动事件表明,这样应用程序可以处理这相应地采取任何行动的事件,直到手指释放
        public static final int FLAG_IGNORE_CHEEK_PRESSES    = 0x00008000;
        //Flag:一个特殊的选项只用于结合FLAG_LAYOUT_IN_SC
        public static final int FLAG_LAYOUT_INSET_DECOR = 0x00010000;
        //Flag:转化的状态FLAG_NOT_FOCUSABLE对这个窗口当前如何进行交互的方法
        public static final int FLAG_ALT_FOCUSABLE_IM = 0x00020000;
        //Flag:如果你设置了该flag,那么在你FLAG_NOT_TOUNCH_MODAL的情况下,即使触摸屏事件发送在该window之外,其事件被发送到了后面的window,那么该window仍然将以MotionEvent.ACTION_OUTSIDE形式收到该触摸屏事件
        public static final int FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000;
        //Flag:当锁屏的时候,显示该window
        public static final int FLAG_SHOW_WHEN_LOCKED = 0x00080000;
        //Flag:在该window后显示系统的墙纸
        public static final int FLAG_SHOW_WALLPAPER = 0x00100000;
        //Flag:当window被显示的时候,系统将把它当做一个用户活动事件,以点亮手机屏幕
        public static final int FLAG_TURN_SCREEN_ON = 0x00200000;
        //Flag:消失键盘
        public static final int FLAG_DISMISS_KEYGUARD = 0x00400000;
        //Flag:当该window在可以接受触摸屏情况下,让因在该window之外,而发送到后面的window的触摸屏可以支持split touch
        public static final int FLAG_SPLIT_TOUCH = 0x00800000;
        //Flag:对该window进行硬件加速,该flag必须在Activity或Dialog的Content View之前进行设置
        public static final int FLAG_HARDWARE_ACCELERATED = 0x01000000;
        //Flag:让window占满整个手机屏幕,不留任何边界
        public static final int FLAG_LAYOUT_IN_OVERSCAN = 0x02000000;
        //Flag:请求一个半透明的状态栏背景以最小的系统提供保护
        public static final int FLAG_TRANSLUCENT_STATUS = 0x04000000;
        //Flag:请求一个半透明的导航栏背景以最小的系统提供保护
        public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000;
        //Flag:......
        public static final int FLAG_LOCAL_FOCUS_MODE = 0x10000000;
        public static final int FLAG_SLIPPERY = 0x20000000;
        public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000;
        public static final int FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS = 0x80000000;

        //行为选项标记
        public int flags;

        //PrivateFlags:......
        public static final int PRIVATE_FLAG_FAKE_HARDWARE_ACCELERATED = 0x00000001;
        public static final int PRIVATE_FLAG_FORCE_HARDWARE_ACCELERATED = 0x00000002;
        public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004;
        public static final int PRIVATE_FLAG_SHOW_FOR_ALL_USERS = 0x00000010;
        public static final int PRIVATE_FLAG_NO_MOVE_ANIMATION = 0x00000040;
        public static final int PRIVATE_FLAG_COMPATIBLE_WINDOW = 0x00000080;
        public static final int PRIVATE_FLAG_SYSTEM_ERROR = 0x00000100;
        public static final int PRIVATE_FLAG_INHERIT_TRANSLUCENT_DECOR = 0x00000200;
        public static final int PRIVATE_FLAG_KEYGUARD = 0x00000400;
        public static final int PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS = 0x00000800;

        //私有的行为选项标记
        public int privateFlags;

        public static final int NEEDS_MENU_UNSET = 0;
        public static final int NEEDS_MENU_SET_TRUE = 1;
        public static final int NEEDS_MENU_SET_FALSE = 2;
        public int needsMenuKey = NEEDS_MENU_UNSET;

        public static boolean mayUseInputMethod(int flags) {
            ......
        }

        //SOFT_INPUT:用于描述软键盘显示规则的bite的mask
        public static final int SOFT_INPUT_MASK_STATE = 0x0f;
        //SOFT_INPUT:没有软键盘显示的约定规则
        public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0;
        //SOFT_INPUT:可见性状态softInputMode,请不要改变软输入区域的状态
        public static final int SOFT_INPUT_STATE_UNCHANGED = 1;
        //SOFT_INPUT:用户导航(navigate)到你的窗口时隐藏软键盘
        public static final int SOFT_INPUT_STATE_HIDDEN = 2;
        //SOFT_INPUT:总是隐藏软键盘
        public static final int SOFT_INPUT_STATE_ALWAYS_HIDDEN = 3;
        //SOFT_INPUT:用户导航(navigate)到你的窗口时显示软键盘
        public static final int SOFT_INPUT_STATE_VISIBLE = 4;
        //SOFT_INPUT:总是显示软键盘
        public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;
        //SOFT_INPUT:显示软键盘时用于表示window调整方式的bite的mask
        public static final int SOFT_INPUT_MASK_ADJUST = 0xf0;
        //SOFT_INPUT:不指定显示软件盘时,window的调整方式
        public static final int SOFT_INPUT_ADJUST_UNSPECIFIED = 0x00;
        //SOFT_INPUT:当显示软键盘时,调整window内的控件大小以便显示软键盘
        public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
        //SOFT_INPUT:当显示软键盘时,调整window的空白区域来显示软键盘,即使调整空白区域,软键盘还是有可能遮挡一些有内容区域,这时用户就只有退出软键盘才能看到这些被遮挡区域并进行
        public static final int SOFT_INPUT_ADJUST_PAN = 0x20;
        //SOFT_INPUT:当显示软键盘时,不调整window的布局
        public static final int SOFT_INPUT_ADJUST_NOTHING = 0x30;
        //SOFT_INPUT:用户导航(navigate)到了你的window
        public static final int SOFT_INPUT_IS_FORWARD_NAVIGATION = 0x100;

        //软输入法模式选项
        public int softInputMode;

        //窗口如何停靠
        public int gravity;
        //水平边距,容器与widget之间的距离,占容器宽度的百分率
        public float horizontalMargin;
        //纵向边距
        public float verticalMargin;
        //积极的insets绘图表面和窗口之间的内容
        public final Rect surfaceInsets = new Rect();
        //期望的位图格式,默认为不透明,参考android.graphics.PixelFormat
        public int format;
        //窗口所使用的动画设置,它必须是一个系统资源而不是应用程序资源,因为窗口管理器不能访问应用程序
        public int windowAnimations;
        //整个窗口的半透明值,1.0表示不透明,0.0表示全透明
        public float alpha = 1.0f;
        //当FLAG_DIM_BEHIND设置后生效,该变量指示后面的窗口变暗的程度,1.0表示完全不透明,0.0表示没有变暗
        public float dimAmount = 1.0f;

        public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f;
        public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f;
        public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f;
        public float screenBrightness = BRIGHTNESS_OVERRIDE_NONE;
        //用来覆盖用户设置的屏幕亮度,表示应用用户设置的屏幕亮度,从0到1调整亮度从暗到最亮发生变化
        public float buttonBrightness = BRIGHTNESS_OVERRIDE_NONE;

        public static final int ROTATION_ANIMATION_ROTATE = 0;
        public static final int ROTATION_ANIMATION_CROSSFADE = 1;
        public static final int ROTATION_ANIMATION_JUMPCUT = 2;
        //定义出入境动画在这个窗口旋转设备时使用
        public int rotationAnimation = ROTATION_ANIMATION_ROTATE;

        //窗口的标示符
        public IBinder token = null;
        //此窗口所在的包名
        public String packageName = null;
        //屏幕方向
        public int screenOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
        //首选的刷新率的窗口
        public float preferredRefreshRate;
        //控制status bar是否显示
        public int systemUiVisibility;
        //ui能见度所请求的视图层次结构
        public int subtreeSystemUiVisibility;
        //得到关于系统ui能见度变化的回调
        public boolean hasSystemUiListeners;

        public static final int INPUT_FEATURE_DISABLE_POINTER_GESTURES = 0x00000001;
        public static final int INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002;
        public static final int INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004;
        public int inputFeatures;
        public long userActivityTimeout = -1;

        ......
        public final int copyFrom(LayoutParams o) {
            ......
        }

        ......
        public void scale(float scale) {
            ......
        }

        ......
    }

看见没有,从上面类可以看出,Android窗口类型主要分成了三大类:

应用程序窗口。一般应用程序的窗口,比如我们应用程序的Activity的窗口。
子窗口。一般在Activity里面的窗口,比如对话框等。
系统窗口。系统的窗口,比如输入法,Toast,墙纸等。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明 YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明YOLO高分设计资源源码,详情请查看资源内容中使用说明

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值