privatevoidensureSubDecor() { if (!mSubDecorInstalled) { mSubDecor = createSubDecor();
// If a title was set before we installed the decor, propagate it now CharSequencetitle= getTitle(); if (!TextUtils.isEmpty(title)) { if (mDecorContentParent != null) { mDecorContentParent.setWindowTitle(title); } elseif (peekSupportActionBar() != null) { peekSupportActionBar().setWindowTitle(title); } elseif (mTitleView != null) { mTitleView.setText(title); } }
applyFixedSizeWindow();
onSubDecorInstalled(mSubDecor);
mSubDecorInstalled = true;
// Invalidate if the panel menu hasn't been created before this. // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu // being called in the middle of onCreate or similar. // A pending invalidation will typically be resolved before the posted message // would run normally in order to satisfy instance state restoration. PanelFeatureStatest= getPanelState(FEATURE_OPTIONS_PANEL, false); if (!mIsDestroyed && (st == null || st.menu == null)) { invalidatePanelMenu(FEATURE_SUPPORT_ACTION_BAR); } } }
if (!a.hasValue(R.styleable.AppCompatTheme_windowActionBar)) { a.recycle(); // 使用了AppCompatActivity但是没有设置一个Theme.AppCompat的主题,则会报这个Exception。 thrownewIllegalStateException( "You need to use a Theme.AppCompat theme (or descendant) with this activity."); } // 给Window设置一些主题属性的逻辑 if (a.getBoolean(R.styleable.AppCompatTheme_windowNoTitle, false)) { requestWindowFeature(Window.FEATURE_NO_TITLE); } elseif (a.getBoolean(R.styleable.AppCompatTheme_windowActionBar, false)) { // Don't allow an action bar if there is no title. requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR); } if (a.getBoolean(R.styleable.AppCompatTheme_windowActionBarOverlay, false)) { requestWindowFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY); } if (a.getBoolean(R.styleable.AppCompatTheme_windowActionModeOverlay, false)) { requestWindowFeature(FEATURE_ACTION_MODE_OVERLAY); } mIsFloating = a.getBoolean(R.styleable.AppCompatTheme_android_windowIsFloating, false); a.recycle();
// 创建DecorView // Now let's make sure that the Window has installed its decor by retrieving it mWindow.getDecorView();
finalLayoutInflaterinflater= LayoutInflater.from(mContext); ViewGroupsubDecor=null; // 根据标记来决定inflate哪个layout if (!mWindowNoTitle) { if (mIsFloating) { // If we're floating, inflate the dialog title decor subDecor = (ViewGroup) inflater.inflate( R.layout.abc_dialog_title_material, null);
// Floating windows can never have an action bar, reset the flags mHasActionBar = mOverlayActionBar = false; } elseif (mHasActionBar) { /** * This needs some explanation. As we can not use the android:theme attribute * pre-L, we emulate it by manually creating a LayoutInflater using a * ContextThemeWrapper pointing to actionBarTheme. */ TypedValueoutValue=newTypedValue(); mContext.getTheme().resolveAttribute(R.attr.actionBarTheme, outValue, true);
// Now inflate the view using the themed context and set it as the content view subDecor = (ViewGroup) LayoutInflater.from(themedContext) .inflate(R.layout.abc_screen_toolbar, null);
/** * Propagate features to DecorContentParent */ if (mOverlayActionBar) { mDecorContentParent.initFeature(FEATURE_SUPPORT_ACTION_BAR_OVERLAY); } if (mFeatureProgress) { mDecorContentParent.initFeature(Window.FEATURE_PROGRESS); } if (mFeatureIndeterminateProgress) { mDecorContentParent.initFeature(Window.FEATURE_INDETERMINATE_PROGRESS); } } } else { if (mOverlayActionMode) { subDecor = (ViewGroup) inflater.inflate( R.layout.abc_screen_simple_overlay_action_mode, null); } else { subDecor = (ViewGroup) inflater.inflate(R.layout.abc_screen_simple, null); }
if (Build.VERSION.SDK_INT >= 21) { // If we're running on L or above, we can rely on ViewCompat's // setOnApplyWindowInsetsListener ViewCompat.setOnApplyWindowInsetsListener(subDecor, newOnApplyWindowInsetsListener() { @Override public WindowInsetsCompat onApplyWindowInsets(View v, WindowInsetsCompat insets) { finalinttop= insets.getSystemWindowInsetTop(); finalintnewTop= updateStatusGuard(top);
// Now apply the insets on our view return ViewCompat.onApplyWindowInsets(v, insets); } }); } else { // Else, we need to use our own FitWindowsViewGroup handling ((FitWindowsViewGroup) subDecor).setOnFitSystemWindowsListener( newFitWindowsViewGroup.OnFitSystemWindowsListener() { @Override publicvoidonFitSystemWindows(Rect insets) { insets.top = updateStatusGuard(insets.top); } }); } }
if (subDecor == null) { thrownewIllegalArgumentException( "AppCompat does not support the current theme features: { " + "windowActionBar: " + mHasActionBar + ", windowActionBarOverlay: "+ mOverlayActionBar + ", android:windowIsFloating: " + mIsFloating + ", windowActionModeOverlay: " + mOverlayActionMode + ", windowNoTitle: " + mWindowNoTitle + " }"); }
if (mDecorContentParent == null) { mTitleView = (TextView) subDecor.findViewById(R.id.title); }
// Make the decor optionally fit system windows, like the window's decor ViewUtils.makeOptionalFitsSystemWindows(subDecor);
finalContentFrameLayoutcontentView= (ContentFrameLayout) subDecor.findViewById( R.id.action_bar_activity_content); // 获取PhoneWindow中的content布局对象 finalViewGroupwindowContentView= (ViewGroup) mWindow.findViewById(android.R.id.content); if (windowContentView != null) { // There might be Views already added to the Window's content view so we need to // migrate them to our content view while (windowContentView.getChildCount() > 0) { finalViewchild= windowContentView.getChildAt(0); windowContentView.removeViewAt(0); contentView.addView(child); }
// Change our content FrameLayout to use the android.R.id.content id. // Useful for fragments. windowContentView.setId(View.NO_ID); contentView.setId(android.R.id.content);
// The decorContent may have a foreground drawable set (windowContentOverlay). // Remove this as we handle it ourselves if (windowContentView instanceof FrameLayout) { ((FrameLayout) windowContentView).setForeground(null); } } // 这个地方我们把subDecor设置给PhoneWindow.这个也就是我们为什么要保证phoneWindows被install的原因。 // Now set the Window's content view with the decor mWindow.setContentView(subDecor);
if (mWindowNoTitle && featureId == FEATURE_SUPPORT_ACTION_BAR) { returnfalse; // Ignore. No title dominates. } if (mHasActionBar && featureId == Window.FEATURE_NO_TITLE) { // Remove the action bar feature if we have no title. No title dominates. mHasActionBar = false; }
switch (featureId) { case FEATURE_SUPPORT_ACTION_BAR: throwFeatureRequestIfSubDecorInstalled(); // 仅仅是对变量赋值 mHasActionBar = true; returntrue; case FEATURE_SUPPORT_ACTION_BAR_OVERLAY: throwFeatureRequestIfSubDecorInstalled(); mOverlayActionBar = true; returntrue; case FEATURE_ACTION_MODE_OVERLAY: throwFeatureRequestIfSubDecorInstalled(); mOverlayActionMode = true; returntrue; case Window.FEATURE_PROGRESS: throwFeatureRequestIfSubDecorInstalled(); mFeatureProgress = true; returntrue; case Window.FEATURE_INDETERMINATE_PROGRESS: throwFeatureRequestIfSubDecorInstalled(); mFeatureIndeterminateProgress = true; returntrue; case Window.FEATURE_NO_TITLE: throwFeatureRequestIfSubDecorInstalled(); mWindowNoTitle = true; returntrue; }
return mWindow.requestFeature(featureId); }
privatevoidthrowFeatureRequestIfSubDecorInstalled() { if (mSubDecorInstalled) { // 这个又解释了一个原因,我们如果在setContentView之后再次去设置requestWindowFeature,会抛出Exception。 // 其实这个问题大家应该也不会陌生 thrownewAndroidRuntimeException( "Window feature must be requested before adding content"); } }
// Invalidate if the panel menu hasn't been created before this. // Panel menu invalidation is deferred avoiding application onCreateOptionsMenu // being called in the middle of onCreate or similar. // A pending invalidation will typically be resolved before the posted message // would run normally in order to satisfy instance state restoration. PanelFeatureStatest= getPanelState(FEATURE_OPTIONS_PANEL, false); if (!isDestroyed() && (st == null || st.menu == null) && !mIsStartingWindow) { invalidatePanelMenu(FEATURE_ACTION_BAR); } } else { mTitleView = findViewById(R.id.title); if (mTitleView != null) { if ((getLocalFeatures() & (1 << FEATURE_NO_TITLE)) != 0) { finalViewtitleContainer= findViewById(R.id.title_container); if (titleContainer != null) { titleContainer.setVisibility(View.GONE); } else { mTitleView.setVisibility(View.GONE); } mContentParent.setForeground(null); } else { mTitleView.setText(mTitle); } } }
// Only inflate or create a new TransitionManager if the caller hasn't // already set a custom one. if (hasFeature(FEATURE_ACTIVITY_TRANSITIONS)) { if (mTransitionManager == null) { finalinttransitionRes= getWindowStyle().getResourceId( R.styleable.Window_windowContentTransitionManager, 0); if (transitionRes != 0) { finalTransitionInflaterinflater= TransitionInflater.from(getContext()); mTransitionManager = inflater.inflateTransitionManager(transitionRes, mContentParent); } else { mTransitionManager = newTransitionManager(); } }
// 这个地方我们把subDecor设置给PhoneWindow.这个也就是我们为什么要保证phoneWindows被install的原因。 // Now set the Window's content view with the decor mWindow.setContentView(subDecor);
@Override publicvoidsetContentView(View view, ViewGroup.LayoutParams params) { // Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window // decor, when theme attributes and the like are crystalized. Do not check the feature // before this happens. if (mContentParent == null) { installDecor(); } elseif (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { mContentParent.removeAllViews(); }