Android

Android

Android

setContentView Activity Activity getWindow() Window PhoneWindow setContentView( )

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback { ...... public void setContentView(@LayoutRes int layoutResID) { getWindow().setContentView(layoutResID); // ActionBar initWindowDecorActionBar(); } ...... }

getWindow() mWindow Window Activity/Screen Window API

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback { ...... private Window mWindow; ...... public Window getWindow() { return mWindow; } ...... }

mWindow attach( ) PhoneWindow

frameworks/base/core/java/android/app/Activity.java

public class Activity extends ContextThemeWrapper implements LayoutInflater.Factory2, Window.Callback, KeyEvent.Callback, OnCreateContextMenuListener, ComponentCallbacks2, Window.OnWindowDismissedCallback { ...... 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) { attachBaseContext(context); mFragments.attachHost(null /*parent*/); // PhoneWindow mWindow = new PhoneWindow(this); mWindow.setCallback(this); mWindow.setOnWindowDismissedCallback(this); mWindow.getLayoutInflater().setPrivateFactory(this); if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { mWindow.setSoftInputMode(info.softInputMode); } if (info.uiOptions != 0) { mWindow.setUiOptions(info.uiOptions); } ...... // WindowManager WMS 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()); } // WindowManager mWindowManager = mWindow.getWindowManager(); mCurrentConfig = config; } ...... }

tips:

5.0 Activity Fragment Transitions 4.4 transition UI API scenes transitions scenes UI transitions

Transition

View Animator

  1. setContentView getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
  2. xml true

Window.FEATURE_CONTENT_TRANSITIONS setContentView( )

  1. installDecor() Decor
  2. mContentParent
  3. layoutResID

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... @Override public void setContentView(int layoutResID) { // // Window Decor FEATURE_CONTENT_TRANSITIONS // if (mContentParent == null) { //1. Decor installDecor(); } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) { //2. mContentParent mContentParent.removeAllViews(); } if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) { final Scene newScene = Scene.getSceneForLayout(mContentParent, layoutResID, getContext()); transitionTo(newScene); } else { //3. layoutResID mContentParent mLayoutInflater.inflate(layoutResID, mContentParent); } mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); } } ...... }
  1. generateDecor() DecorView
  2. generateLayout( ) mContentParent
  3. DecorView WindowCallback WindowTitle

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... private void installDecor() { if (mDecor == null) { // DecorView mDecor = generateDecor(); // mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS); mDecor.setIsRootNamespace(true); ...... } if (mContentParent == null) { // mContentParent mContentParent = generateLayout(mDecor); // UI Decor fitsSystemWindows mDecor.makeOptionalFitsSystemWindows(); // Decor final DecorContentParent decorContentParent = (DecorContentParent) mDecor.findViewById( R.id.decor_content_parent); if (decorContentParent != null) { mDecorContentParent = decorContentParent; mDecorContentParent.setWindowCallback(getCallback()); if (mDecorContentParent.getTitle() == null) { mDecorContentParent.setWindowTitle(mTitle); } ...... } else { ...... } ...... } } ...... }

generateDecor() DecorView DecorView

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... protected DecorView generateDecor() { return new DecorView(getContext(), -1); } ...... }
  1. mFeatureId -1 DecorView
  2. -
  3. Bar

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... private final class DecorView extends FrameLayout implements RootViewSurfaceTaker { ...... public DecorView(Context context, int featureId) { super(context); // ID DecorView -1 mFeatureId = featureId; // - mShowInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in); // - mHideInterpolator = AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_linear_in); //Bar mBarEnterExitDuration = context.getResources().getInteger( R.integer.dock_enter_exit_duration); } ...... } ...... }

generateLayout( )

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... protected ViewGroup generateLayout(DecorView decor) { ...... //Inflate the window decor. int layoutResource; int features = getLocalFeatures(); //System.out.println("Features: 0x" + Integer.toHexString(features)); if ((features & (1 << FEATURE_SWIPE_TO_DISMISS)) != 0) { ...... } else if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) { ...... } else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0 && (features & (1 << FEATURE_ACTION_BAR)) == 0) { ...... } else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) { ...... } else if ((features & (1 << FEATURE_NO_TITLE)) == 0) { //If no other features and not embedded, only need a title. //If the window is floating, we need a dialog layout if (mIsFloating) { ...... } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) { // ActionBar layoutResource = a.getResourceId( R.styleable.Window_windowActionBarFullscreenDecorLayout, R.layout.screen_action_bar); } else { ...... } } else if ((features & (1 << FEATURE_ACTION_MODE_OVERLAY)) != 0) { ...... } else { ...... } mDecor.startChanging(); // View in = mLayoutInflater.inflate(layoutResource, null); decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)); // mContentRoot = (ViewGroup) in; // ID_ANDROID_CONTENT Window //ID_ANDROID_CONTENT = com.android.internal.R.id.content ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT); if (contentParent == null) { throw new RuntimeException("Window couldn't find content container view"); } ...... mDecor.finishChanging(); return contentParent; } ...... }

screen_action_bar layout ActionBarOverlayLayout mContentRoot FrameLayout android:id="@android:id/content" contentParent

frameworks/base/core/res/res/layout/screen_action_bar.xml

<?xml version="1.0" encoding="utf-8"?> <!-- Action Bar --> <com.android.internal.widget.ActionBarOverlayLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/decor_content_parent" android:layout_width="match_parent" android:layout_height="match_parent" android:splitMotionEvents="false" android:theme="?attr/actionBarTheme"> <FrameLayout android:id="@android:id/content" android:layout_width="match_parent" android:layout_height="match_parent"/> ...... </com.android.internal.widget.ActionBarOverlayLayout>

layoutResID mContentParent inflate xml PULL layout mContentParent FrameLayout

frameworks/base/core/java/android/view/LayoutInflater.java

public abstract class LayoutInflater { ...... public View inflate(@LayoutRes int resource, @Nullable ViewGroup root) { return inflate(resource, root, root != null); } ...... public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot) { final Resources res = getContext().getResources(); if (DEBUG) { Log.d(TAG, "INFLATING from resource:/"" + res.getResourceName(resource) + "\" (" + Integer.toHexString(resource) + ")"); } final XmlResourceParser parser = res.getLayout(resource); try { return inflate(parser, root, attachToRoot); } finally { parser.close(); } } ...... public View inflate(XmlPullParser parser, @Nullable ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate"); final Context inflaterContext = mContext; final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context) mConstructorArgs[0]; mConstructorArgs[0] = inflaterContext; View result = root; try { // int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { //Empty } if (type != XmlPullParser.START_TAG) { throw new InflateException(parser.getPositionDescription() + ": No start tag found!"); } final String name = parser.getName(); ...... //merge if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException("<merge/> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } rInflate(parser, root, inflaterContext, attrs, false); } else { //Temp xml View final View temp = createViewFromTag(root, name, inflaterContext, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // root params = root.generateLayoutParams(attrs); if (!attachToRoot) { temp.setLayoutParams(params); } } ...... // rInflateChildren(parser, temp, attrs, true); ...... // temp View root if (root != null && attachToRoot) { root.addView(temp, params); } ...... } } catch (XmlPullParserException e) { ...... } catch (Exception e) { ...... } finally { ...... } Trace.traceEnd(Trace.TRACE_TAG_VIEW); return result; } } ...... }

Activity Activity ActivityThread handleLaunchActivity handleResumeActivity

  1. Window DecorView
  2. DecorView
  3. WindowManager
  4. DecorView ViewManager

frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread { ...... final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) { ...... // activity onResume(...) ActivityClientRecord r = performResumeActivity(token, clearHide); if (r != null) { final Activity a = r.activity; ...... if (r.window == null && !a.mFinished && willBeVisible) { r.window = r.activity.getWindow(); View decor = r.window.getDecorView(); // DecorView decor.setVisibility(View.INVISIBLE); // WindowManager ViewManager wm = a.getWindowManager(); WindowManager.LayoutParams l = r.window.getAttributes(); a.mDecor = decor; l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION; l.softInputMode |= forwardBit; if (a.mVisibleFromClient) { a.mWindowAdded = true; // DecorView ViewManager wm.addView(decor, l); } } else if (!willBeVisible) { ...... } ...... // AMS if (reallyResume) { try { ActivityManagerNative.getDefault().activityResumed(token); } catch (RemoteException ex) { } } } else { ...... } } ...... }

Window DecorView PhoneWindow mDecor DecorView

frameworks/base/core/java/com/android/internal/policy/PhoneWindow.java

public class PhoneWindow extends Window implements MenuBuilder.Callback { ...... @Override public final View getDecorView() { if (mDecor == null) { installDecor(); } return mDecor; } ...... }

wm WindowManagerImpl WindowManagerImpl addView WindowManagerGlobal addView

frameworks/base/core/java/android/view/WindowManagerImpl.java

public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); ...... @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); mGlobal.addView(view, params, mDisplay, mParentWindow); } ...... }
  1. WindowManager.LayoutParams
  2. mViews DecorView IllegalStateException
  3. mViews panelParentView
  4. ViewRootImpl
  5. DecorView LayoutParams
  6. mViews mRoots mParams
  7. ViewRootImpl DecorView

frameworks/base/core/java/android/view/WindowManagerImpl.java

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) { // if (view == null) { throw new IllegalArgumentException("view must not be null"); } if (display == null) { throw new IllegalArgumentException("display must not be null"); } if (!(params instanceof WindowManager.LayoutParams)) { throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); } // WindowManager.LayoutParams final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params; if (parentWindow != null) { parentWindow.adjustLayoutParamsForSubWindow(wparams); } else { ...... } ViewRootImpl root; View panelParentView = null; synchronized (mLock) { ...... //mViews DecorView int index = findViewLocked(view, false); if (index >= 0) { if (mDyingViews.contains(view)) { ...... } else { // IllegalStateException throw new IllegalStateException("View " + view + " has already been added to the window manager."); } //The previous removeView() had not completed executing. Now it has. } // mViews panelParentView if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW && wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) { final int count = mViews.size(); for (int i = 0; i < count; i++) { if (mRoots.get(i).mWindow.asBinder() == wparams.token) { panelParentView = mViews.get(i); } } } // ViewRootImpl root = new ViewRootImpl(view.getContext(), display); //DecorView LayoutParams view.setLayoutParams(wparams); // mViews.add(view); mRoots.add(root); mParams.add(wparams); } try { //ViewRootImpl DecorView root.setView(view, wparams, panelParentView); } catch (RuntimeException e) { ...... } } ...... }

ViewRootImpl setView( )

  1. requestLayout() layout
  2. Session addToDisplay W W ViewRootImpl

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ...... final W mWindow; ...... //Surface final Surface mSurface = new Surface(); ...... public ViewRootImpl(Context context, Display display) { mContext = context; mWindowSession = WindowManagerGlobal.getWindowSession(); mDisplay = display; mBasePackageName = context.getBasePackageName(); mDisplayAdjustments = display.getDisplayAdjustments(); mThread = Thread.currentThread(); mLocation = new WindowLeaked(null); mLocation.fillInStackTrace(); mWidth = -1; mHeight = -1; mDirty = new Rect(); mTempRect = new Rect(); mVisRect = new Rect(); mWinFrame = new Rect(); mWindow = new W(this); mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion; mViewVisibility = View.GONE; mTransparentRegion = new Region(); mPreviousTransparentRegion = new Region(); mFirst = true; //true for the first time the view is added mAdded = false; mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this); mAccessibilityManager = AccessibilityManager.getInstance(context); mAccessibilityInteractionConnectionManager = new AccessibilityInteractionConnectionManager(); mAccessibilityManager.addAccessibilityStateChangeListener( mAccessibilityInteractionConnectionManager); mHighContrastTextManager = new HighContrastTextManager(); mAccessibilityManager.addHighTextContrastStateChangeListener( mHighContrastTextManager); mViewConfiguration = ViewConfiguration.get(context); mDensity = context.getResources().getDisplayMetrics().densityDpi; mNoncompatDensity = context.getResources().getDisplayMetrics().noncompatDensityDpi; mFallbackEventHandler = new PhoneFallbackEventHandler(context); mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); loadSystemProperties(); } ...... public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { synchronized (this) { if (mView == null) { mView = view; ...... // layout WMS // requestLayout() ...... try { ...... res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { ...... } finally { ...... } ...... } } } ...... static class W extends IWindow.Stub { private final WeakReference<ViewRootImpl> mViewAncestor; private final IWindowSession mWindowSession; W(ViewRootImpl viewAncestor) { mViewAncestor = new WeakReference<ViewRootImpl>(viewAncestor); mWindowSession = viewAncestor.mWindowSession; } ...... } ...... }

requestLayout() scheduleTraversals()

frameworks/base/core/java/android/view/ViewRootImpl.java

public final class ViewRootImpl implements ViewParent, View.AttachInfo.Callbacks, HardwareRenderer.HardwareDrawCallbacks { ...... boolean mHandlingLayoutInLayoutRequest = false; ...... @Override public void requestLayout() { if (!mHandlingLayoutInLayoutRequest) { checkThread(); mLayoutRequested = true; scheduleTraversals(); } } ...... }

Session addToDisplay

Session Session

addToDisplay WindowManagerService addWindow

frameworks/base/services/core/java/com/android/server/wm/Session.java

final class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { final WindowManagerService mService; ...... @Override public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outContentInsets, outStableInsets, outOutsets, outInputChannel); } ...... }

addWindow WindowState attach() mWindowMap attach()

frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java

public class WindowManagerService extends IWindowManager.Stub implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs { ...... // IWindow IBinder Window WindowState final HashMap<IBinder, WindowState> mWindowMap = new HashMap<>(); ...... public int addWindow(Session session, IWindow client, int seq, WindowManager.LayoutParams attrs, int viewVisibility, int displayId, Rect outContentInsets, Rect outStableInsets, Rect outOutsets, InputChannel outInputChannel) { ...... WindowState attachedWindow = null; ...... synchronized(mWindowMap) { ...... WindowState win = new WindowState(this, session, client, token, attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent); ...... //From now on, no exceptions or errors allowed! res = WindowManagerGlobal.ADD_OKAY; ...... win.attach(); mWindowMap.put(client.asBinder(), win); ...... } ...... } ...... }