美文网首页
Android源码 windowManager

Android源码 windowManager

作者: 妖怪青同学 | 来源:发表于2018-07-18 14:36 被阅读0次

    前言

    嗯嗯 windowManager是用来干嘛的?
    从名字上可以看出windowManger是窗口管理的意思, 主要

    window

    /**
     * Abstract base class for a top-level window look and behavior policy.  An
     * instance of this class should be used as the top-level view added to the
     * window manager. It provides standard UI policies such as a background,   title
     * area, default key processing, etc.
     *
     * <p>The only existing implementation of this abstract class is
     * android.view.PhoneWindow, which you should instantiate when needing a
     * Window.
     */
    public abstract class Window {
    /** Flag for the "options panel" feature.  This is enabled by default. */
    public static final int FEATURE_OPTIONS_PANEL = 0;
    /** Flag for the "no title" feature, turning off the title at the top
     *  of the screen. */
    public static final int FEATURE_NO_TITLE = 1;
    
       //....
    
     }
    

    看下类的解释 :一个顶级窗口和行为策略的抽象基类, 实例作为顶级view添加到windowManager,提供了标准UI,唯一实现类是PhoneWindow .

    哪些地方用到了windowManager
    windowManager什么时候创建的

    • IWindowSession mWindowSession;
    image.png

    Activity中的windowManager的创建
    在dialog中调用

     mWindowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
    


    在Activity中

    @Override
    public Object getSystemService(@ServiceName @NonNull String name) {
        if (getBaseContext() == null) {
            throw new IllegalStateException(
                    "System services not available to Activities before onCreate()");
        }
    
        if (WINDOW_SERVICE.equals(name)) {
            return mWindowManager;
        } else if (SEARCH_SERVICE.equals(name)) {
            ensureSearchManager();
            return mSearchManager;
        }
        return super.getSystemService(name);
    }
    

    attach时

     final void attach(...) {
         //....
        "1.创建window"
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        "2.设置window回调"
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        //....
        "4.创建windowManger并关联window和windowManger"
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    
      //...
    }
    

    在服务中获取windowManager
    下图是输入法InputMethodService创建输入法dialog的过程
    softInputWindow实际就是输入法的视图区


    image.png

    断点继续走到dialog的创建过程


    用户

    此时用户获取windowManger的上下文是service

    image.png image.png image.png
    image.png
    image.png

    =========================================================

    可以看到最终是通过了 SystemServiceRegistry 这个类获取windowManager

     "管理所有可以通过Context的getSystemService()获取的系统服务"
     /**
     * Manages all of the system services that can be returned by {@link         Context#getSystemService}.
     * Used by {@link ContextImpl}.
     * 
     */
    final class SystemServiceRegistry {
    private static final String TAG = "SystemServiceRegistry";
    
    // Service registry information.
    // This information is never changed once static initialization has completed.
    "保存了所有的系统服务的名字"
    private static final HashMap<Class<?>, String> SYSTEM_SERVICE_NAMES =
            new HashMap<Class<?>, String>();
    "保存了所有的系统服务的ServiceFetcher  "
    "getSystemService时 是通过服务的名字先获取ServiceFetcher ,然后通过fetcher.getService(ctx) 获取注册了的服务"
    private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
    private static int sServiceCacheSize;
    
    // Not instantiable.
    private SystemServiceRegistry() { }
    
    //类加载时注册所有的服务
    static {
        registerService(Context.ACCESSIBILITY_SERVICE, AccessibilityManager.class,
                new CachedServiceFetcher<AccessibilityManager>() {
            @Override
            public AccessibilityManager createService(ContextImpl ctx) {
                return AccessibilityManager.getInstance(ctx);
            }});
        //太多服务了  这里先忽略..........
        //WINDOW_SERVICE 在这里注册的
        registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
    
       //太多服务了  这里先忽略..........
    
    }
    
    /**
     * Creates an array which is used to cache per-Context service instances.
     */
    public static Object[] createServiceCache() {
        return new Object[sServiceCacheSize];
    }
     "here  通过contextImpl 和Context中的服务名(如Context.WINDOW_SERVICE) 获取服务"
    "getSystemService时 是通过服务的名字先获取ServiceFetcher ,然后通过fetcher.getService(ctx) 获取注册了的服务"
    /**
     * Gets a system service from a given context.
     */
    public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }
    
    /**
     * Gets the name of the system-level service that is represented by the specified class.
     */
    public static String getSystemServiceName(Class<?> serviceClass) {
        return SYSTEM_SERVICE_NAMES.get(serviceClass);
    }
      "类加载时调用 注册系统服务"
    /**
     * Statically registers a system service with the context.
     * This method must be called during static initialization only
     */
    private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
    "系统服务获取的接口"
    /**
     * Base interface for classes that fetch services.
     * These objects must only be created during static initialization.
     */
    static abstract interface ServiceFetcher<T> {
        T getService(ContextImpl ctx);
    }
    "当system service需要 context时使用这个"
    /**
     * Override this class when the system service constructor needs a
     * ContextImpl and should be cached and retained by that context.
     */
    static abstract class CachedServiceFetcher<T> implements ServiceFetcher<T> {
        private final int mCacheIndex;
    
        public CachedServiceFetcher() {
            mCacheIndex = sServiceCacheSize++;
        }
    
        @Override
        @SuppressWarnings("unchecked")
        public final T getService(ContextImpl ctx) {
            final Object[] cache = ctx.mServiceCache;
            synchronized (cache) {
                // Fetch or create the service.
                Object service = cache[mCacheIndex];
                "如果服务为空通过 ContextImpl create 并保存到缓存中"
                if (service == null) {
                    try {
                        service = createService(ctx);
                        "把ServiceFetcher create的服务加到缓存中,下次可以直接从缓存中获取"
                        cache[mCacheIndex] = service;
                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);
                    }
                }
                return (T)service;
            }
        }
    
        public abstract T createService(ContextImpl ctx) throws ServiceNotFoundException;
    }
       "当system service不需要 context时使用这个"
    /**
     * Override this class when the system service does not need a ContextImpl
     * and should be cached and retained process-wide.
     */
    static abstract class StaticServiceFetcher<T> implements ServiceFetcher<T> {
        private T mCachedInstance;
    
        @Override
        public final T getService(ContextImpl ctx) {
            synchronized (StaticServiceFetcher.this) {
                if (mCachedInstance == null) {
                    try {
                        mCachedInstance = createService();
                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);
                    }
                }
                return mCachedInstance;
            }
        }
    
        public abstract T createService() throws ServiceNotFoundException;
    }
    "每个进程只有一个实例的system service使用这个StaticApplicationContextServiceFetcher注册   ==>只有ConnectivityManager用到  "
    /**
     * Like StaticServiceFetcher, creates only one instance of the service per application, but when
     * creating the service for the first time, passes it the application context of the creating
     * application.
     *
     * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
     * case where multiple application components each have their own ConnectivityManager object.
     */
    static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
        private T mCachedInstance;
    
        @Override
        public final T getService(ContextImpl ctx) {
            synchronized (StaticApplicationContextServiceFetcher.this) {
                if (mCachedInstance == null) {
                    Context appContext = ctx.getApplicationContext();
                    // If the application context is null, we're either in the system process or
                    // it's the application context very early in app initialization. In both these
                    // cases, the passed-in ContextImpl will not be freed, so it's safe to pass it
                    // to the service. http://b/27532714 .
                    try {
                        mCachedInstance = createService(appContext != null ? appContext : ctx);
                    } catch (ServiceNotFoundException e) {
                        onServiceNotFound(e);
                    }
                }
                return mCachedInstance;
            }
        }
    
        public abstract T createService(Context applicationContext) throws ServiceNotFoundException;
    }
    
    public static void onServiceNotFound(ServiceNotFoundException e) {
        // We're mostly interested in tracking down long-lived core system
        // components that might stumble if they obtain bad references; just
        // emit a tidy log message for normal apps
        if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
            Log.wtf(TAG, e.getMessage(), e);
        } else {
            Log.w(TAG, e.getMessage());
        }
    }
    }
    

    ========================================================

    image.png
      /**
       * Context for decor views which can be seeded with pure application 
      context and not depend on the
     * activity, but still provide some of the facilities that Activity has,
     * e.g. themes, activity-based resources, etc.
     *
     * @hide
     */
    class DecorContext extends ContextThemeWrapper {
    private PhoneWindow mPhoneWindow;
    private WindowManager mWindowManager;
    private Resources mActivityResources;
    
    public DecorContext(Context context, Resources activityResources) {
        super(context, null);
        mActivityResources = activityResources;
    }
    
    void setPhoneWindow(PhoneWindow phoneWindow) {
        mPhoneWindow = phoneWindow;
        mWindowManager = null;
    }
    
    @Override
    public Object getSystemService(String name) {
        if (Context.WINDOW_SERVICE.equals(name)) {
            if (mWindowManager == null) {
                WindowManagerImpl wm =
                        (WindowManagerImpl) super.getSystemService(Context.WINDOW_SERVICE);
                mWindowManager = wm.createLocalWindowManager(mPhoneWindow);
            }
            return mWindowManager;
        }
        return super.getSystemService(name);
    }
    
    @Override
    public Resources getResources() {
        return mActivityResources;
    }
    
    @Override
    public AssetManager getAssets() {
        return mActivityResources.getAssets();
    }
    

    }

    Dialog

    public class Dialog implements DialogInterface, Window.Callback,
        KeyEvent.Callback, OnCreateContextMenuListener, Window.OnWindowDismissedCallback {
     //...
    "qtip:  look here!!!   dialog 中的windowManger "
    private final WindowManager mWindowManager;
    
    final Context mContext;
    "qtip:  look here!!!   dialog 中的Window "
    final Window mWindow;
    
    View mDecor;
    
     //....
    
    /**
     * Creates a dialog window that uses the default dialog theme.
     * <p>
     * The supplied {@code context} is used to obtain the window manager and
     * base theme used to present the dialog.
     *
     * @param context the context in which the dialog should run
     * @see android.R.styleable#Theme_dialogTheme
     */
    public Dialog(@NonNull Context context) {
        this(context, 0, true);
    }
    //....... 以下略
    
    
    }
    
    
      //dialog的创建
    
      Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == ResourceId.ID_NULL) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }
        "1.获取windowManager  "
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        "2 创建window"
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        "3.设置window回调"
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
       " 4 给window设置windowManger "
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
    
        mListenersHandler = new ListenersHandler(this);
    }
    

    PopupWindow

    public class PopupWindow {
    
    
     //...
    
    private Context mContext;
    " PopupWindow 中的windowManager ..."
    private WindowManager mWindowManager;
    
    //...
    
    /** View that handles event dispatch and content transitions. */
    private PopupDecorView mDecorView;
    
    // ...... 以下 略
    
    
    }
    
    popupWindow的显示
    
    /**
     * Display the content view in a popup window at the specified location.
     *
     * @param token Window token to use for creating the new window
     * @param gravity the gravity which controls the placement of the popup window
     * @param x the popup's x location offset
     * @param y the popup's y location offset
     *
     * @hide Internal use only. Applications should use
     *       {@link #showAtLocation(View, int, int, int)} instead.
     */
        public void showAtLocation(IBinder token, int gravity, int x, int y) {
        if (isShowing() || mContentView == null) {
            return;
        }
    
        TransitionManager.endTransitions(mDecorView);
    
        detachFromAnchor();
    
        mIsShowing = true;
        mIsDropdown = false;
        mGravity = gravity;
    
        final WindowManager.LayoutParams p = createPopupLayoutParams(token);
        preparePopup(p);
    
        p.x = x;
        p.y = y;
    
        invokePopup(p);
    }
     "继续看invokePopup()"
    
        private void invokePopup(WindowManager.LayoutParams p) {
        if (mContext != null) {
            p.packageName = mContext.getPackageName();
        }
    
        final PopupDecorView decorView = mDecorView;
        decorView.setFitsSystemWindows(mLayoutInsetDecor);
    
        setLayoutDirectionFromAnchor();
        "向windowManger中添加View 显示popupWindow "
        mWindowManager.addView(decorView, p);
    
        if (mEnterTransition != null) {
            decorView.requestEnterTransition(mEnterTransition);
        }
    }
    
    "popupWindow的隐藏"
    /**
     * Disposes of the popup window. This method can be invoked only after
     * {@link #showAsDropDown(android.view.View)} has been executed. Failing
     * that, calling this method will have no effect.
     *
     * @see #showAsDropDown(android.view.View)
     */
    public void dismiss() {
        //如果没有显示或者正在消失 return
        if (!isShowing() || isTransitioningToDismiss()) {
            return;
        }
    
        final PopupDecorView decorView = mDecorView;
        final View contentView = mContentView;
    
        final ViewGroup contentHolder;
        final ViewParent contentParent = contentView.getParent();
        if (contentParent instanceof ViewGroup) {
            contentHolder = ((ViewGroup) contentParent);
        } else {
            contentHolder = null;
        }
    
        // Ensure any ongoing or pending transitions are canceled.
        decorView.cancelTransitions();
    
        mIsShowing = false;
        mIsTransitioningToDismiss = true;
    
        // This method may be called as part of window detachment, in which
        // case the anchor view (and its root) will still return true from
        // isAttachedToWindow() during execution of this method; however, we
        // can expect the OnAttachStateChangeListener to have been called prior
        // to executing this method, so we can rely on that instead.
        final Transition exitTransition = mExitTransition;
        if (exitTransition != null && decorView.isLaidOut()
                && (mIsAnchorRootAttached || mAnchorRoot == null)) {
            // The decor view is non-interactive and non-IME-focusable during exit transitions.
            final LayoutParams p = (LayoutParams) decorView.getLayoutParams();
            p.flags |= LayoutParams.FLAG_NOT_TOUCHABLE;
            p.flags |= LayoutParams.FLAG_NOT_FOCUSABLE;
            p.flags &= ~LayoutParams.FLAG_ALT_FOCUSABLE_IM;
            mWindowManager.updateViewLayout(decorView, p);
    
            final View anchorRoot = mAnchorRoot != null ? mAnchorRoot.get() : null;
            final Rect epicenter = getTransitionEpicenter();
    
            // Once we start dismissing the decor view, all state (including
            // the anchor root) needs to be moved to the decor view since we
            // may open another popup while it's busy exiting.
            decorView.startExitTransition(exitTransition, anchorRoot, epicenter,
                    new TransitionListenerAdapter() {
                        @Override
                        public void onTransitionEnd(Transition transition) {
                            dismissImmediate(decorView, contentHolder, contentView);
                        }
                    });
        } else {
        "立即消失   ==============="
            dismissImmediate(decorView, contentHolder, contentView);
        }
    
        // Clears the anchor view.
        detachFromAnchor();
    
        if (mOnDismissListener != null) {
            mOnDismissListener.onDismiss();
        }
    }
    
    
     "再来看看是怎么立即消失的"
    /**
     * Removes the popup from the window manager and tears down the supporting
     * view hierarchy, if necessary.
     */
    private void dismissImmediate(View decorView, ViewGroup contentHolder, View contentView) {
        // If this method gets called and the decor view doesn't have a parent,
        // then it was either never added or was already removed. That should
        // never happen, but it's worth checking to avoid potential crashes.
        if (decorView.getParent() != null) {
    
            //qtip: 移除decorView 
            mWindowManager.removeViewImmediate(decorView);
    
        }
    
        if (contentHolder != null) {
            contentHolder.removeView(contentView);
        }
    
        // This needs to stay until after all transitions have ended since we
        // need the reference to cancel transitions in preparePopup().
        mDecorView = null;
        mBackgroundView = null;
        mIsTransitioningToDismiss = false;
    }
    

    看看decorView是啥
    从windowManager中移除的decorView就是PopupWindow中的一个成员变量 :mDecorView
    popupWindow 调用showAtLocation()时会先调用preparePopup(),在preparePopup()中完成decorView 和 mBackgroundView的创建

    private void preparePopup(WindowManager.LayoutParams p) {
        if (mContentView == null || mContext == null || mWindowManager == null) {
            throw new IllegalStateException("You must specify a valid content view by "
                    + "calling setContentView() before attempting to show the popup.");
        }
    
        if (p.accessibilityTitle == null) {
            p.accessibilityTitle = mContext.getString(R.string.popup_window_default_title);
        }
    
        // The old decor view may be transitioning out. Make sure it finishes
        // and cleans up before we try to create another one.
        if (mDecorView != null) {
            mDecorView.cancelTransitions();
        }
    
        // When a background is available, we embed the content view within
        // another view that owns the background drawable.
        if (mBackground != null) {
         "qtip: 通过popupWindow设置的contentView创建一个背景PopupBackgroundView,PopupBackgroundView继承于FramLayout"
            mBackgroundView = createBackgroundView(mContentView);
            mBackgroundView.setBackground(mBackground);
        } else {
            mBackgroundView = mContentView;
        }
        "qtip: 再通过背景创建一个装饰视图 mDecorView"
        mDecorView = createDecorView(mBackgroundView);
    
        // The background owner should be elevated so that it casts a shadow.
        mBackgroundView.setElevation(mElevation);
    
        // We may wrap that in another view, so we'll need to manually specify
        // the surface insets.
        p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
    
        mPopupViewInitialLayoutDirectionInherited =
                (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
    }
    
    
    /**
     * Wraps a content view in a FrameLayout.
     *
     * @param contentView the content view to wrap
     * @return a FrameLayout that wraps the content view
     */
    private PopupDecorView createDecorView(View contentView) {
        final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams();
        final int height;
        if (layoutParams != null && layoutParams.height == WRAP_CONTENT) {
            height = WRAP_CONTENT;
        } else {
            height = MATCH_PARENT;
        }
    
        final PopupDecorView decorView = new PopupDecorView(mContext);
        decorView.addView(contentView, MATCH_PARENT, height);
        decorView.setClipChildren(false);
        decorView.setClipToPadding(false);
    
        return decorView;
    }
    

    PopupDecorView是popupWindow的一个内部类 继承于FramLayout ,重新处理了点击和按键等事件以控制popupWindow返回键和touch消失

    是不是对比PopupWindow 和dialog 好像有些不一样

    image.png image.png

    Toast

    public class Toast {
    static final String TAG = "Toast";
    static final boolean localLOGV = false;
    
    /** @hide */
    @IntDef({LENGTH_SHORT, LENGTH_LONG})
    @Retention(RetentionPolicy.SOURCE)
    public @interface Duration {}
    
    /**
     * Show the view or text notification for a short period of time.  This time
     * could be user-definable.  This is the default.
     * @see #setDuration
     */
    public static final int LENGTH_SHORT = 0;
    
    /**
     * Show the view or text notification for a long period of time.  This time
     * could be user-definable.
     * @see #setDuration
     */
    public static final int LENGTH_LONG = 1;
    
    final Context mContext;
    " look here !!   TN是什么 "
    final TN mTN;
    int mDuration;
    View mNextView;
    
    //...... 以下略
    }
    
    
    
    private static class TN extends ITransientNotification.Stub {
        private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
    
        private static final int SHOW = 0;
        private static final int HIDE = 1;
        private static final int CANCEL = 2;
        final Handler mHandler;
    
        int mGravity;
        int mX, mY;
        float mHorizontalMargin;
        float mVerticalMargin;
    
    
        View mView;
        View mNextView;
        int mDuration;
        "look here !!!   windowManager  "
        WindowManager mWM;
    
        String mPackageName;
    
        static final long SHORT_DURATION_TIMEOUT = 4000;
        static final long LONG_DURATION_TIMEOUT = 7000;
    
        TN(String packageName, @Nullable Looper looper) {
            // XXX This should be changed to use a Dialog, with a Theme.Toast
            // defined that sets up the layout params appropriately.
            final WindowManager.LayoutParams params = mParams;
            params.height = WindowManager.LayoutParams.WRAP_CONTENT;
            params.width = WindowManager.LayoutParams.WRAP_CONTENT;
            params.format = PixelFormat.TRANSLUCENT;
            params.windowAnimations = com.android.internal.R.style.Animation_Toast;
            params.type = WindowManager.LayoutParams.TYPE_TOAST;
            params.setTitle("Toast");
            params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
    
            mPackageName = packageName;
    
            if (looper == null) {
                // Use Looper.myLooper() if looper is not specified.
                looper = Looper.myLooper();
                if (looper == null) {
                    throw new RuntimeException(
                            "Can't toast on a thread that has not called Looper.prepare()");
                }
            }
            mHandler = new Handler(looper, null) {
                @Override
                public void handleMessage(Message msg) {
                    switch (msg.what) {
                        case SHOW: {
                            IBinder token = (IBinder) msg.obj;
                            handleShow(token);
                            break;
                        }
                        case HIDE: {
                            handleHide();
                            // Don't do this in handleHide() because it is also invoked by
                            // handleShow()
                            mNextView = null;
                            break;
                        }
                        case CANCEL: {
                            handleHide();
                            // Don't do this in handleHide() because it is also invoked by
                            // handleShow()
                            mNextView = null;
                            try {
                                getService().cancelToast(mPackageName, TN.this);
                            } catch (RemoteException e) {
                            }
                            break;
                        }
                    }
                }
            };
        }
    

    相关文章

      网友评论

          本文标题:Android源码 windowManager

          本文链接:https://www.haomeiwen.com/subject/dvywpftx.html