Windows and WindowManager
Windows are the unit of z-order, focus and input routing. WindowManager decides where they go, what they contain, and which one gets the touch — and the answer is not always the one on top.
An Activity feels like a screen, and a window feels like a rectangle. In the system's model it is the reverse: the window is the object that owns a rectangle on the display, and the Activity merely asks for one. Understanding that inversion explains z-order, focus, insets, dialogs and the "app is behind the keyboard" problem.
TL;DR#
- A window is the unit of display surface, input routing and z-order. An Activity has at least one.
- WindowManagerService (in
system_server) owns the window list, the layers and the focus. - A window has a type that places it in a layer band, and a token that ties it to an Activity or an app.
- Focus is not the same as topmost: a window can be visible and not focusable, or focusable and not touchable in parts.
- The Shell (WMShell) implements the window-management UI — the recents gesture, split screen — outside
system_server.
Mental model#
Think of a theatre stage with a fly system.
Each window is a flat scenery panel. Panels are hung in a fixed order, and each has a track it slides along.
The fly operator is WindowManagerService: it decides which panels are down, in what order, and how big they are.
The lighting is SurfaceFlinger: it illuminates whatever panels are down.
The usher is InputDispatcher: when someone in the audience points at the stage, the usher works out which panel they are pointing at — which is not necessarily the frontmost one, if that panel is transparent to touch.
Where the analogy breaks#
Panels do not move relative to the audience or change size; windows do, constantly, and often during an animation. A window's frame, crop, alpha and layer can all change in a single transaction. And a window can exist without being visible at all — created, measured and laid out but not yet shown, which is how an Activity prepares its first frame.
The big picture#
Text description of this diagram
The window stack from bottom to top: wallpaper, app base windows, a dialog, the IME, the status and navigation bars, and a toast. Each window has a type; the type determines a band, and the band determines z-order and which window is asked first for input. The diagram shows that the keyboard is an ordinary window from another app, and that a toast is above everything but never receives touch.
The bands in that diagram are the reason a dialog from app A can appear above app B's window, and the reason the keyboard covers your content rather than the other way around.
Deep dive#
Windows are objects, Activities are clients#
WindowManagerService holds a list of WindowState objects.1 Each has a frame, a layer, a visibility state, an input
channel and a token.
An Activity gets a window through Window (usually PhoneWindow), and the window's DecorView is the root of the
view hierarchy. When you call setContentView, you are populating the content view inside that window.
// Every Activity already has a window; this is the object behind it.
window.setLayout(
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.WRAP_CONTENT
)Types and layer bands#
Each window has a WindowManager.LayoutParams.type. The type is not arbitrary: it selects a band, and the band
selects a z-order range.
| Band | Typical types | Owner |
|---|---|---|
| Wallpaper | TYPE_WALLPAPER | SystemUI / wallpaper service |
| Application | TYPE_BASE_APPLICATION, TYPE_APPLICATION | any app |
| Sub-window | TYPE_APPLICATION_ATTACHED_DIALOG, TYPE_APPLICATION_PANEL | an app, attached to a parent |
| IME | TYPE_INPUT_METHOD | the current input method |
| System | TYPE_STATUS_BAR, TYPE_NAVIGATION_BAR | SystemUI |
| Top | TYPE_TOAST, overlays | any app with permission |
Apps cannot normally create system-band windows; TYPE_APPLICATION_OVERLAY requires the draw-over-apps permission
and is placed below the system bars. That restriction exists because a window above the status bar could spoof it.
Tokens: what a window belongs to#
A window carries a token that identifies its owner — an Activity token, or an application token for windows that are not tied to an Activity.2 The token is what makes these work:
- Dialogs. A dialog window attached to an Activity's token moves with the Activity, is dismissed with it, and is placed above it.
- Focus. The system can move focus to the correct window when the Activity comes forward, because it knows which windows belong to it.
- Security. A window without the right token cannot be placed above another app's window.
Focus versus touchability#
These are three separate properties:
- Visible: the window is drawn.
- Focusable: the window can receive key events.
- Touchable: the window can receive touch events, within its touchable region.
A toast is visible and neither focusable nor touchable. A status bar is visible, not focusable, and touchable only in
parts. A dialog is all three. The FLAG_NOT_FOCUSABLE and FLAG_NOT_TOUCHABLE flags control the latter two.
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL is the one that most often surprises: without it, a non-fullscreen
window blocks touches to everything behind it even outside its own bounds. With it, touches outside its frame go to
the window below.
Insets: the window's obligations#
A window does not own the whole display. The system bars, the cutout and the IME reserve space, and the window is told about that space through insets. Whether the window is laid out inside those bounds or behind them is a choice — one that changed by default in recent releases. See Insets and edge-to-edge.
The Shell#
The window-management policy is no longer all in system_server. The Shell (WMShell) is a separate process that
implements the interactive parts3: the recents gesture, split-screen and freeform transitions, and the transition
animations. It talks to WindowManagerService through a stable interface rather than living inside it.
That split is why the recents animation can be updated independently of the platform, and why a Shell crash does not take down window management itself.
Transitions#
A transition is a coordinated animation between window states: app A fading out while app B fades in, or a window
resizing while its contents reflow. The Transitions infrastructure in system_server coordinates the animation,
collecting the participating windows and running the animation as a single transaction so no intermediate state is
shown.
This is the mechanism that makes a "shared element" transition look continuous: the system knows both windows and animates their surfaces together, rather than the app animating one and the system cutting to the other.
Why focus is a system decision, not an app one#
An app cannot simply take focus. It requests it — through requestFocus, or implicitly by showing a focusable
window — and WindowManagerService decides whether the request wins.
The decision uses the window's type, its layer, whether it is focusable and whether it is visible. A window that is
not focusable never takes focus, regardless of what the app asks. That is why a FLAG_NOT_FOCUSABLE overlay cannot
steal the keyboard from the app beneath it, and why the rule is enforced centrally rather than by convention.
The window's insets are the window's obligations#
A window is told what the system reserves around it. A full-screen app gets a content inset for the status and navigation bars; a floating window may get none, because it does not overlap them.
The framework applies these insets to the window's layout by default. Whether it does is a property of the window's
LayoutParams, which is why an app that sets FLAG_LAYOUT_NO_LIMITS gets a window extending under everything — and
why that flag is almost always a mistake.
Transitions are transactions with a clock#
A transition is not only an animation; it is a coordinated state change. The Transitions infrastructure in
system_server collects the participating windows, snapshots their start and end states, and runs an animation that
is applied as a sequence of transactions.
That is why the animation is smooth even when the app is not drawing: the system is animating the window's geometry and alpha, not the app's content. The app's buffer is scaled or faded as a whole.
When an app participates in a transition — a shared element, a custom animation — it registers a participant and supplies start and end values. The system still owns the clock.
What the app can and cannot control#
| The app can | The app cannot |
|---|---|
| choose its window type (within limits) | place a window above a system window |
| set flags for focus and touchability | decide which window is topmost |
| request a size and position (within policy) | override the Shell's split-screen layout |
| provide transition participants | change the transition's timing curve |
The pattern is consistent: the app describes intent, and the system applies policy. That is what makes one app's window behaviour predictable in the presence of every other app.
Why dumpsys window is the first tool#
Almost every window question — why is this on top, why is the keyboard covering it, why is the touch going to the
wrong place — is answered by reading the window list. dumpsys window windows shows the type, frame, visibility and
focus state of each window, and dumpsys input shows which window the dispatcher believes has focus.
Before writing code to work around a window problem, read the list. The system's view of the world is usually correct, and the app's assumption is usually what is wrong.
How it evolved#
| API | Version | What changed |
|---|---|---|
| 1 | 1.0 |
|
| 3 | 1.5 Cupcake |
|
| 9 | 2.3 Gingerbread |
|
| 11 | 3.0 Honeycomb |
|
| 12 | 3.1 Honeycomb |
|
| 16 | 4.1 Jelly Bean |
|
| 20 | 4.4W KitKat (Wear) |
|
| 21 | 5.0 Lollipop |
|
| 24 | 7.0 Nougat |
|
| 26 | 8.0 Oreo |
|
| 28 | 9 Pie |
|
| 29 | 10 |
|
| 30 | 11 |
|
| 31 | 12 |
|
| 33 | 13 Tiramisu |
|
| 36 | 16 Baklava |
|
Under the hood#
- WindowManagerService.javathe window list, layers and focus
- WindowState.javaone window's frame, visibility and input state
- WindowManager.javaLayoutParams, types and flags
- Window.javathe Activity-facing window object
- WMShell: recents, split screen and transitions
Curiosity corner#
- The status bar is an app. SystemUI owns it as an ordinary window with a system type, which is why it can crash and restart without taking the rest of the system with it.
- A window can be bigger than the screen. Freeform and desktop windowing allow windows that extend beyond the display bounds; the visible region is cropped, not resized.
- The navigation bar can be a window or a gesture region, depending on the navigation mode — the same band, a different input story.
Try it#
adb shell dumpsys window windows | grep -E "Window #|mFrame|mHasSurface"Example output
Window #0 Window{9c1f3a u0 com.example.app/com.example.app.MainActivity}:
mDisplayId=0 mFrame=[0,0][1080,2400] mHasSurface=true
mViewVisibility=0x0 mPolicyVisibility=true
Window #1 Window{4b2d11 u0 StatusBar}:
mFrame=[0,0][1080,96] mHasSurface=trueadb shell dumpsys window | grep -E "mCurrentFocus|mFocusedApp"Example output
mCurrentFocus=Window{9c1f3a u0 com.example.app/com.example.app.MainActivity}
mFocusedApp=ActivityRecord{...}adb shell dumpsys window | grep -A5 "mFrame"Example output
mFrame=[0,0][1080,2400]
mContentInsets=Insets{left=0, top=96, right=0, bottom=132}Check yourself#
Check yourself
Why does the system deliver input to an app through a socket pair rather than a Binder call?
Sources#
Sources
Every version number, API level, class name and date on this page is traced to one of these. Pages are re-verified against them; last_verified above says when.
- docsSurfaceFlinger and WindowManagersource.android.comaccessed 2026-10-27↩
- docsLayers and displayssource.android.comaccessed 2026-10-27↩
- docsLarge screens overviewdeveloper.android.comaccessed 2026-10-27↩
- docsInput overviewsource.android.comaccessed 2026-10-27↩
- docsWinscopesource.android.comaccessed 2026-10-27↩
- docsBehavior changes: Apps targeting Android 12developer.android.comaccessed 2026-10-27↩