• 前言

参考博客

-

  本文中的所有内容大部分来源于网络资料,如有侵权请联系本人修改或删除,请大家多多支持原创!非常感谢!

WindowManagerService

Activity与Window相关概念

  • Activity只负责生命周期和事件处理
  • window只控制视图
  • 一个Activity包含一个Window,如果Activity没有Window,那就相当于Service
  • AMS统一调度所有应用程序的Activity
  • WMS控制所有Window的显示与隐藏以及要显示的位置

Window

  “Window” 表明它是和窗口相关的,”窗口“是一个抽象的概念,从用户的角度来讲,它是一个”界面“;从SurfaceFlinger的角度来看,它是一个Layer,承载着和界面有关的数据和属性;从WMS角度来看,它是一个WindowState,用于管理和界面有关的状态。

  • 表示一个窗口的概念,是所有View的直接管理者,任何视图都通过Window呈现(点击事件由Window->DecorView->View;Activity的setContentView底层是通过Window完成)
  • Window是一个抽象类,具体实现是PhoneWindow
  • 创建Window需要通过WindowManager创建
  • WindowManager是外界访问Window的入口
  • Window具体实现位于WindowManagerService中
  • WindowManager和WindowMangerService的交互是通过IPC完成
  • 定义窗口样式和行为的抽象基类,用于作为顶层的view加到WindowManger中,其实现类是PhoneWindow。
  • 每个Window都需要指定一个Type(应用窗口、子窗口、系统窗口)。Activity对应的窗口是应用窗口;PopupWindow,ContextMenu,OptionMenu是常用的子窗口;像Toast和系统警告提示框(如ANR)就是系统窗口,还有很多应用的悬浮框也属于系统窗口类型。

WindowManager

  用来在应用与window之间的管理接口,管理窗口顺序,消息等

WindowManagerService

  简称WMS,我indowManagerService管理窗口的创建、更新和删除,显示顺序等,是WindowManager这个管理器的实现类。它运行在system_server进程,作为服务端,客户端(应用程序)通过IPC调用和它进行交互。

Token

  Token主要是指窗口令牌(Window Token),是一种特殊的Binder令牌,WMS用它唯一标识系统中的一个窗口。

Window的Type

  • 应用窗口:层级范围是1~99
  • 子窗口: 层级范围是1000~1999
  • 系统窗口:层级范围是2000~2999
  • 各级别Type值在WindowManager中的定义分别为(frameworks/base/core/java/android/view/WindowManager.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455

/**
* Start of window types that represent normal application windows.
* 第一个应用窗口
*/
public static final int FIRST_APPLICATION_WINDOW = 1;

/**
* Window type: an application window that serves as the "base" window
* of the overall application; all other application windows will
* appear on top of it.
* In multiuser systems shows only on the owning user's window.
* 所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
*/
public static final int TYPE_BASE_APPLICATION = 1;

/**
* Window type: a normal application window. The {@link #token} must be
* an Activity token identifying who the window belongs to.
* In multiuser systems shows only on the owning user's window.
* 所有程序窗口的Base窗口,只能配合Activity在当前App使用
*/
public static final int TYPE_APPLICATION = 2;

/**
* Window type: special application window that is displayed while the
* application is starting. Not for use by applications themselves;
* this is used by the system to display something until the
* application can show its own windows.
* In multiuser systems shows on all users' windows.
* 目标应用窗口未启动之前的那个窗口
*/
public static final int TYPE_APPLICATION_STARTING = 3;

/**
* Window type: a variation on TYPE_APPLICATION that ensures the window
* manager will wait for this window to be drawn before the app is shown.
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_DRAWN_APPLICATION = 4;

/**
* End of types of application windows.
* 最后一个应用窗口
*/
public static final int LAST_APPLICATION_WINDOW = 99;

/**
* Start of types of sub-windows. The {@link #token} of these windows
* must be set to the window they are attached to. These types of
* windows are kept next to their attached window in Z-order, and their
* coordinate space is relative to their attached window.
* 第一个子窗口
*/
public static final int FIRST_SUB_WINDOW = 1000;

/**
* Window type: a panel on top of an application window. These windows
* appear on top of their attached window.
* 面板窗口,显示于宿主窗口的上层,只能配合Activity在当前App使用
*/
public static final int TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW;

/**
* Window type: window for showing media (such as video). These windows
* are displayed behind their attached window.
* 媒体窗口(如视频),显示于宿主窗口下层
*/
public static final int TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW + 1;

/**
* Window type: a sub-panel on top of an application window. These
* windows are displayed on top their attached window and any
* {@link #TYPE_APPLICATION_PANEL} panels.
* 应用程序窗口的子面板,只能配合Activity在当前APP使用(PopupWindow默认就是这个Type)
*/
public static final int TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW + 2;

/** Window type: like {@link #TYPE_APPLICATION_PANEL}, but layout
* of the window happens as that of a top-level window, <em>not</em>
* as a child of its container.
* 对话框窗口,只能配合Activity在当前APP使用
*/
public static final int TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW + 3;

/**
* Window type: window for showing overlays on top of media windows.
* These windows are displayed between TYPE_APPLICATION_MEDIA and the
* application window. They should be translucent to be useful. This
* is a big ugly hack so:
* @hide
*/
@UnsupportedAppUsage
public static final int TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW + 4;

/**
* Window type: a above sub-panel on top of an application window and it's
* sub-panel windows. These windows are displayed on top of their attached window
* and any {@link #TYPE_APPLICATION_SUB_PANEL} panels.
* @hide
*/
public static final int TYPE_APPLICATION_ABOVE_SUB_PANEL = FIRST_SUB_WINDOW + 5;

/**
* End of types of sub-windows.
* 最后一个子窗口
*/
public static final int LAST_SUB_WINDOW = 1999;

/**
* Start of system-specific window types. These are not normally
* created by applications.
* 系统窗口,非应用程序创建
*/
public static final int FIRST_SYSTEM_WINDOW = 2000;

/**
* Window type: the status bar. There can be only one status bar
* window; it is placed at the top of the screen, and all other
* windows are shifted down so they are below it.
* In multiuser systems shows on all users' windows.
* 状态栏,只能有一个状态栏,位于屏幕顶端,其他窗口都位于它下方
*/
public static final int TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW;

/**
* Window type: the search bar. There can be only one search bar
* window; it is placed at the top of the screen.
* In multiuser systems shows on all users' windows.
* 搜索栏。只能有一个搜索栏,位于屏幕上方
*/
public static final int TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1;

/**
* Window type: phone. These are non-application windows providing
* user interaction with the phone (in particular incoming calls).
* These windows are normally placed above all applications, but behind
* the status bar.
* In multiuser systems shows on all users' windows.
* 电话窗口,它用于电话交互(特别是呼入),置于所有应用程序之上,状态栏之下,属于悬浮窗(并且给一个Activity的话按下HOME键会出现看不到桌面上的图标异常情况)
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;

/**
* Window type: system window, such as low power alert. These windows
* In multiuser systems shows only on the owning user's window.
* 系统警告提示窗口,出现在应用程序窗口之上,属于悬浮窗,但是会被禁止
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;

/**
* Window type: keyguard window.
* 锁屏窗口
* In multiuser systems shows on all users' windows.
* @removed
*/
public static final int TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4;

/**
* Window type: transient notifications.
* In multiuser systems shows only on the owning user's window.
* 信息窗口,用于显示Toast,不属于悬浮窗,但有悬浮窗的功能,缺点是在Andoid 2.3上无法接受点击事件
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_TOAST = FIRST_SYSTEM_WINDOW+5;

/**
* Window type: system overlay windows, which need to be displayed
* on top of everything else. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows only on the owning user's window.
* 系统顶层窗口,显示在其他一切内容之上,此窗口不能获得输入焦点,否则影响锁屏
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6;

/**
* Window type: priority phone UI, which needs to be displayed even if
* the keyguard is active. These windows must not take input
* focus, or they will interfere with the keyguard.
* In multiuser systems shows on all users' windows.
* 电话优先,当锁屏时显示,此窗口不能获得输入焦点,否则影响锁屏
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7;

/**
* Window type: panel that slides out from the status bar
* In multiuser systems shows on all users' windows.
* 系统对话框窗口
*/
public static final int TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8;

/**
* Window type: dialogs that the keyguard shows
* In multiuser systems shows on all users' windows.
* 锁屏时显示的对话框
*/
public static final int TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9;

/**
* Window type: internal system error windows, appear on top of
* everything they can.
* In multiuser systems shows only on the owning user's window.
* 系统内部错误提示,显示在任何窗口之上
* @deprecated for non-system apps. Use {@link #TYPE_APPLICATION_OVERLAY} instead.
*/
@Deprecated
public static final int TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10;

/**
* Window type: internal input methods windows, which appear above
* the normal UI. Application windows may be resized or panned to keep
* the input focus visible while this window is displayed.
* 内部输入法窗口,显示于普通UI之上,应用程序可重新布局以免被此窗口覆盖
* In multiuser systems shows only on the owning user's window.
*/
public static final int TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11;

/**
* Window type: internal input methods dialog windows, which appear above
* the current input method window.
* In multiuser systems shows only on the owning user's window.
* 内部输入法对话框,显示于当前输入法窗口之上
*/
public static final int TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12;

/**
* Window type: wallpaper window, placed behind any window that wants
* to sit on top of the wallpaper.
* In multiuser systems shows only on the owning user's window.
* 墙纸窗口
*/
public static final int TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13;

/**
* Window type: panel that slides out from over the status bar
* In multiuser systems shows on all users' windows.
* 状态栏的滑动面板
* @removed
*/
public static final int TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14;

/**
* Window type: secure system overlay windows, which need to be displayed
* on top of everything else. These windows must not take input
* focus, or they will interfere with the keyguard.
*
* This is exactly like {@link #TYPE_SYSTEM_OVERLAY} except that only the
* system itself is allowed to create these overlays. Applications cannot
* obtain permission to create secure system overlays.
*
* In multiuser systems shows only on the owning user's window.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15;

/**
* Window type: the drag-and-drop pseudowindow. There is only one
* drag layer (at most), and it is placed on top of all other windows.
* In multiuser systems shows only on the owning user's window.
* @hide
*/
public static final int TYPE_DRAG = FIRST_SYSTEM_WINDOW+16;

/**
* Window type: panel that slides out from over the status bar
* In multiuser systems shows on all users' windows. These windows
* are displayed on top of the stauts bar and any {@link #TYPE_STATUS_BAR_PANEL}
* windows.
* @hide
*/
public static final int TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17;

/**
* Window type: (mouse) pointer
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_POINTER = FIRST_SYSTEM_WINDOW+18;

/**
* Window type: Navigation bar (when distinct from status bar)
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19;

/**
* Window type: The volume level overlay/dialog shown when the user
* changes the system volume.
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20;

/**
* Window type: The boot progress dialog, goes on top of everything
* in the world.
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21;

/**
* Window type to consume input events when the systemUI bars are hidden.
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_INPUT_CONSUMER = FIRST_SYSTEM_WINDOW+22;

/**
* Window type: Navigation bar panel (when navigation bar is distinct from status bar)
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_NAVIGATION_BAR_PANEL = FIRST_SYSTEM_WINDOW+24;

/**
* Window type: Display overlay window. Used to simulate secondary display devices.
* In multiuser systems shows on all users' windows.
* @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int TYPE_DISPLAY_OVERLAY = FIRST_SYSTEM_WINDOW+26;

/**
* Window type: Magnification overlay window. Used to highlight the magnified
* portion of a display when accessibility magnification is enabled.
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27;

/**
* Window type: Window for Presentation on top of private
* virtual display.
*/
public static final int TYPE_PRIVATE_PRESENTATION = FIRST_SYSTEM_WINDOW+30;

/**
* Window type: Windows in the voice interaction layer.
* @hide
*/
public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31;

/**
* Window type: Windows that are overlaid <em>only</em> by a connected {@link
* android.accessibilityservice.AccessibilityService} for interception of
* user interactions without changing the windows an accessibility service
* can introspect. In particular, an accessibility service can introspect
* only windows that a sighted user can interact with which is they can touch
* these windows or can type into these windows. For example, if there
* is a full screen accessibility overlay that is touchable, the windows
* below it will be introspectable by an accessibility service even though
* they are covered by a touchable window.
*/
public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32;

/**
* Window type: Starting window for voice interaction layer.
* @hide
*/
public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;

/**
* Window for displaying a handle used for resizing docked stacks. This window is owned
* by the system process.
* @hide
*/
public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;

/**
* Window type: like {@link #TYPE_APPLICATION_ATTACHED_DIALOG}, but used
* by Quick Settings Tiles.
* @hide
*/
public static final int TYPE_QS_DIALOG = FIRST_SYSTEM_WINDOW+35;

/**
* Window type: shows directly above the keyguard. The layer is
* reserved for screenshot animation, region selection and UI.
* In multiuser systems shows only on the owning user's window.
* @hide
*/
public static final int TYPE_SCREENSHOT = FIRST_SYSTEM_WINDOW + 36;

/**
* Window type: Window for Presentation on an external display.
* @see android.app.Presentation
* @hide
*/
public static final int TYPE_PRESENTATION = FIRST_SYSTEM_WINDOW + 37;

/**
* Window type: Application overlay windows are displayed above all activity windows
* (types between {@link #FIRST_APPLICATION_WINDOW} and {@link #LAST_APPLICATION_WINDOW})
* but below critical system windows like the status bar or IME.
* <p>
* The system may change the position, size, or visibility of these windows at anytime
* to reduce visual clutter to the user and also manage resources.
* <p>
* Requires {@link android.Manifest.permission#SYSTEM_ALERT_WINDOW} permission.
* <p>
* The system will adjust the importance of processes with this window type to reduce the
* chance of the low-memory-killer killing them.
* <p>
* In multi-user systems shows only on the owning user's screen.
*/
public static final int TYPE_APPLICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 38;

/**
* Window type: Window for adding accessibility window magnification above other windows.
* This will place the window in the overlay windows.
* @hide
*/
public static final int TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW + 39;

/**
* Window type: the notification shade and keyguard. There can be only one status bar
* window; it is placed at the top of the screen, and all other
* windows are shifted down so they are below it.
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_NOTIFICATION_SHADE = FIRST_SYSTEM_WINDOW + 40;

/**
* Window type: used to show the status bar in non conventional parts of the screen (i.e.
* the left or the bottom of the screen).
* In multiuser systems shows on all users' windows.
* @hide
*/
public static final int TYPE_STATUS_BAR_ADDITIONAL = FIRST_SYSTEM_WINDOW + 41;

/**
* End of types of system windows.
* 最后一个系统窗口
*/
public static final int LAST_SYSTEM_WINDOW = 2999;

/**
* @hide
* Used internally when there is no suitable type available.
*/
public static final int INVALID_WINDOW_TYPE = -1;

Activity窗口管理服务WindowManagerService计算Activity窗口大小的过程分析

  在Android系统中,Activity窗口的大小是由WindowManagerService服务来计算的。WindowManagerService服务会根据屏幕及其装饰区的大小来决定Activity窗口的大小。一个Activity窗口只有知道自己的大小之后,才能对它里面的UI元素进行测量、布局以及绘制。

  一般来说,Activity窗口的大小等于整个屏幕的大小,但是它并不占据着整块屏幕。为了理解这一点,我们首先分析一下Activity窗口的区域是如何划分的。Activity窗口的上方一般会有一个状态栏,用来显示3G信号、电量使用等图标。

  从Activity窗口剔除状态栏所占用的区域之后,所得到的区域就称为内容区域(Content Region)。顾名思义,内容区域就是用来显示Activity窗口的内容的。

Activity窗口大小的计算过程

  这个过程可以分为11个步骤

  • Step 1. ViewRootImpl.performTraversals

  这个函数定义在文件framework/base/core/java/android/view/ViewRootImpl.java#performTraversals实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952

public final class ViewRootImpl implements ViewParent,
View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks,
AttachedSurfaceControl {

// Line 3090
private void performTraversals() {
mLastPerformTraversalsSkipDrawReason = null;

// cache mView since it is used so much below...
final View host = mView;
if (DBG) {
System.out.println("======================================");
System.out.println("performTraversals");
host.debug();
}

if (host == null || !mAdded) {
mLastPerformTraversalsSkipDrawReason = host == null ? "no_host" : "not_added";
return;
}

if (mNumPausedForSync > 0) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.instant(Trace.TRACE_TAG_VIEW,
TextUtils.formatSimple("performTraversals#mNumPausedForSync=%d",
mNumPausedForSync));
}
if (DEBUG_BLAST) {
Log.d(mTag, "Skipping traversal due to sync " + mNumPausedForSync);
}
mLastPerformTraversalsSkipDrawReason = "paused_for_sync";
return;
}

mIsInTraversal = true;
mWillDrawSoon = true;
boolean cancelDraw = false;
String cancelReason = null;
boolean isSyncRequest = false;

boolean windowSizeMayChange = false;
WindowManager.LayoutParams lp = mWindowAttributes;

int desiredWindowWidth;
int desiredWindowHeight;

final int viewVisibility = getHostVisibility();
final boolean viewVisibilityChanged = !mFirst
&& (mViewVisibility != viewVisibility || mNewSurfaceNeeded
// Also check for possible double visibility update, which will make current
// viewVisibility value equal to mViewVisibility and we may miss it.
|| mAppVisibilityChanged);
mAppVisibilityChanged = false;
final boolean viewUserVisibilityChanged = !mFirst &&
((mViewVisibility == View.VISIBLE) != (viewVisibility == View.VISIBLE));
final boolean shouldOptimizeMeasure = shouldOptimizeMeasure(lp);

WindowManager.LayoutParams params = null;
CompatibilityInfo compatibilityInfo =
mDisplay.getDisplayAdjustments().getCompatibilityInfo();
if (compatibilityInfo.supportsScreen() == mLastInCompatMode) {
params = lp;
mFullRedrawNeeded = true;
mLayoutRequested = true;
if (mLastInCompatMode) {
params.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
mLastInCompatMode = false;
} else {
params.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
mLastInCompatMode = true;
}
}

Rect frame = mWinFrame;
if (mFirst) {
mFullRedrawNeeded = true;
mLayoutRequested = true;

final Configuration config = getConfiguration();
if (shouldUseDisplaySize(lp)) {
// NOTE -- system code, won't try to do compat mode.
Point size = new Point();
mDisplay.getRealSize(size);
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
// For wrap content, we have to remeasure later on anyways. Use size consistent with
// below so we get best use of the measure cache.
final Rect bounds = getWindowBoundsInsetSystemBars();
desiredWindowWidth = bounds.width();
desiredWindowHeight = bounds.height();
} else {
// After addToDisplay, the frame contains the frameHint from window manager, which
// for most windows is going to be the same size as the result of relayoutWindow.
// Using this here allows us to avoid remeasuring after relayoutWindow
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
}

// We used to use the following condition to choose 32 bits drawing caches:
// PixelFormat.hasAlpha(lp.format) || lp.format == PixelFormat.RGBX_8888
// However, windows are now always 32 bits by default, so choose 32 bits
mAttachInfo.mUse32BitDrawingCache = true;
mAttachInfo.mWindowVisibility = viewVisibility;
mAttachInfo.mRecomputeGlobalAttributes = false;
mLastConfigurationFromResources.setTo(config);
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
// Set the layout direction if it has not been set before (inherit is the default)
if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
host.setLayoutDirection(config.getLayoutDirection());
}
host.dispatchAttachedToWindow(mAttachInfo, 0);
mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true);
dispatchApplyInsets(host);
if (!mOnBackInvokedDispatcher.isOnBackInvokedCallbackEnabled()) {
// For apps requesting legacy back behavior, we add a compat callback that
// dispatches {@link KeyEvent#KEYCODE_BACK} to their root views.
// This way from system point of view, these apps are providing custom
// {@link OnBackInvokedCallback}s, and will not play system back animations
// for them.
registerCompatOnBackInvokedCallback();
}
} else {
desiredWindowWidth = frame.width();
desiredWindowHeight = frame.height();
if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) {
if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame);
mFullRedrawNeeded = true;
mLayoutRequested = true;
windowSizeMayChange = true;
}
}

if (viewVisibilityChanged) {
mAttachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
mAttachInfo.mTreeObserver.dispatchOnWindowVisibilityChange(viewVisibility);
if (viewUserVisibilityChanged) {
host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
}
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
endDragResizing();
destroyHardwareResources();
}
}

// Non-visible windows can't hold accessibility focus.
if (mAttachInfo.mWindowVisibility != View.VISIBLE) {
host.clearAccessibilityFocus();
}

// Execute enqueued actions on every traversal in case a detached view enqueued an action
getRunQueue().executeActions(mAttachInfo.mHandler);

if (mFirst) {
// make sure touch mode code executes by setting cached value
// to opposite of the added touch mode.
mAttachInfo.mInTouchMode = !mAddedTouchMode;
ensureTouchModeLocally(mAddedTouchMode);
}

boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
if (layoutRequested) {
if (!mFirst) {
if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT
|| lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) {
windowSizeMayChange = true;

if (shouldUseDisplaySize(lp)) {
// NOTE -- system code, won't try to do compat mode.
Point size = new Point();
mDisplay.getRealSize(size);
desiredWindowWidth = size.x;
desiredWindowHeight = size.y;
} else {
final Rect bounds = getWindowBoundsInsetSystemBars();
desiredWindowWidth = bounds.width();
desiredWindowHeight = bounds.height();
}
}
}

// Ask host how big it wants to be
windowSizeMayChange |= measureHierarchy(host, lp, mView.getContext().getResources(),
desiredWindowWidth, desiredWindowHeight, shouldOptimizeMeasure);
}

if (collectViewAttributes()) {
params = lp;
}
if (mAttachInfo.mForceReportNewAttributes) {
mAttachInfo.mForceReportNewAttributes = false;
params = lp;
}

if (mFirst || mAttachInfo.mViewVisibilityChanged) {
mAttachInfo.mViewVisibilityChanged = false;
int resizeMode = mSoftInputMode & SOFT_INPUT_MASK_ADJUST;
// If we are in auto resize mode, then we need to determine
// what mode to use now.
if (resizeMode == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) {
final int N = mAttachInfo.mScrollContainers.size();
for (int i=0; i<N; i++) {
if (mAttachInfo.mScrollContainers.get(i).isShown()) {
resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
}
}
if (resizeMode == 0) {
resizeMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
}
if ((lp.softInputMode & SOFT_INPUT_MASK_ADJUST) != resizeMode) {
lp.softInputMode = (lp.softInputMode & ~SOFT_INPUT_MASK_ADJUST) | resizeMode;
params = lp;
}
}
}

if (mApplyInsetsRequested) {
dispatchApplyInsets(host);
if (mLayoutRequested) {
// Short-circuit catching a new layout request here, so
// we don't need to go through two layout passes when things
// change due to fitting system windows, which can happen a lot.
windowSizeMayChange |= measureHierarchy(host, lp,
mView.getContext().getResources(), desiredWindowWidth, desiredWindowHeight,
shouldOptimizeMeasure);
}
}

if (layoutRequested) {
// Clear this now, so that if anything requests a layout in the
// rest of this function we will catch it and re-run a full
// layout pass.
mLayoutRequested = false;
}

boolean windowShouldResize = layoutRequested && windowSizeMayChange
&& ((mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight())
|| (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.width() < desiredWindowWidth && frame.width() != mWidth)
|| (lp.height == ViewGroup.LayoutParams.WRAP_CONTENT &&
frame.height() < desiredWindowHeight && frame.height() != mHeight));
windowShouldResize |= mDragResizing && mPendingDragResizing;

// Determine whether to compute insets.
// If there are no inset listeners remaining then we may still need to compute
// insets in case the old insets were non-empty and must be reset.
final boolean computesInternalInsets =
mAttachInfo.mTreeObserver.hasComputeInternalInsetsListeners()
|| mAttachInfo.mHasNonEmptyGivenInternalInsets;

boolean insetsPending = false;
int relayoutResult = 0;
boolean updatedConfiguration = false;

final int surfaceGenerationId = mSurface.getGenerationId();

final boolean isViewVisible = viewVisibility == View.VISIBLE;
boolean surfaceSizeChanged = false;
boolean surfaceCreated = false;
boolean surfaceDestroyed = false;
// True if surface generation id changes or relayout result is RELAYOUT_RES_SURFACE_CHANGED.
boolean surfaceReplaced = false;

final boolean windowAttributesChanged = mWindowAttributesChanged;
if (windowAttributesChanged) {
mWindowAttributesChanged = false;
params = lp;
}

if (params != null) {
if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0
&& !PixelFormat.formatHasAlpha(params.format)) {
params.format = PixelFormat.TRANSLUCENT;
}
adjustLayoutParamsForCompatibility(params);
controlInsetsForCompatibility(params);
if (mDispatchedSystemBarAppearance != params.insetsFlags.appearance) {
mDispatchedSystemBarAppearance = params.insetsFlags.appearance;
mView.onSystemBarAppearanceChanged(mDispatchedSystemBarAppearance);
}
}

if (mFirst || windowShouldResize || viewVisibilityChanged || params != null
|| mForceNextWindowRelayout) {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceBegin(Trace.TRACE_TAG_VIEW,
TextUtils.formatSimple("relayoutWindow#"
+ "first=%b/resize=%b/vis=%b/params=%b/force=%b",
mFirst, windowShouldResize, viewVisibilityChanged, params != null,
mForceNextWindowRelayout));
}

mForceNextWindowRelayout = false;

// If this window is giving internal insets to the window manager, then we want to first
// make the provided insets unchanged during layout. This avoids it briefly causing
// other windows to resize/move based on the raw frame of the window, waiting until we
// can finish laying out this window and get back to the window manager with the
// ultimately computed insets.
insetsPending = computesInternalInsets;

if (mSurfaceHolder != null) {
mSurfaceHolder.mSurfaceLock.lock();
mDrawingAllowed = true;
}

boolean hwInitialized = false;
boolean dispatchApplyInsets = false;
boolean hadSurface = mSurface.isValid();

try {
if (DEBUG_LAYOUT) {
Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" +
host.getMeasuredHeight() + ", params=" + params);
}

if (mFirst || viewVisibilityChanged) {
mViewFrameInfo.flags |= FrameInfo.FLAG_WINDOW_VISIBILITY_CHANGED;
}
relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
cancelDraw = (relayoutResult & RELAYOUT_RES_CANCEL_AND_REDRAW)
== RELAYOUT_RES_CANCEL_AND_REDRAW;
cancelReason = "relayout";
final boolean dragResizing = mPendingDragResizing;
if (mSyncSeqId > mLastSyncSeqId) {
mLastSyncSeqId = mSyncSeqId;
if (DEBUG_BLAST) {
Log.d(mTag, "Relayout called with blastSync");
}
reportNextDraw("relayout");
mSyncBuffer = true;
isSyncRequest = true;
if (!cancelDraw) {
mDrewOnceForSync = false;
}
}

final boolean surfaceControlChanged =
(relayoutResult & RELAYOUT_RES_SURFACE_CHANGED)
== RELAYOUT_RES_SURFACE_CHANGED;

if (mSurfaceControl.isValid()) {
updateOpacity(mWindowAttributes, dragResizing,
surfaceControlChanged /*forceUpdate */);
// No need to updateDisplayDecoration if it's a new SurfaceControl and
// mDisplayDecorationCached is false, since that's the default for a new
// SurfaceControl.
if (surfaceControlChanged && mDisplayDecorationCached) {
updateDisplayDecoration();
}
if (surfaceControlChanged
&& mWindowAttributes.type
== WindowManager.LayoutParams.TYPE_STATUS_BAR) {
mTransaction.setDefaultFrameRateCompatibility(mSurfaceControl,
Surface.FRAME_RATE_COMPATIBILITY_NO_VOTE).apply();
}
}

if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString()
+ " surface=" + mSurface);

// If the pending {@link MergedConfiguration} handed back from
// {@link #relayoutWindow} does not match the one last reported,
// WindowManagerService has reported back a frame from a configuration not yet
// handled by the client. In this case, we need to accept the configuration so we
// do not lay out and draw with the wrong configuration.
if (mRelayoutRequested
&& !mPendingMergedConfiguration.equals(mLastReportedMergedConfiguration)) {
if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: "
+ mPendingMergedConfiguration.getMergedConfiguration());
performConfigurationChange(new MergedConfiguration(mPendingMergedConfiguration),
!mFirst, INVALID_DISPLAY /* same display */);
updatedConfiguration = true;
}
final boolean updateSurfaceNeeded = mUpdateSurfaceNeeded;
mUpdateSurfaceNeeded = false;

surfaceSizeChanged = false;
if (!mLastSurfaceSize.equals(mSurfaceSize)) {
surfaceSizeChanged = true;
mLastSurfaceSize.set(mSurfaceSize.x, mSurfaceSize.y);
}
final boolean alwaysConsumeSystemBarsChanged =
mPendingAlwaysConsumeSystemBars != mAttachInfo.mAlwaysConsumeSystemBars;
updateColorModeIfNeeded(lp.getColorMode());
surfaceCreated = !hadSurface && mSurface.isValid();
surfaceDestroyed = hadSurface && !mSurface.isValid();

// When using Blast, the surface generation id may not change when there's a new
// SurfaceControl. In that case, we also check relayout flag
// RELAYOUT_RES_SURFACE_CHANGED since it should indicate that WMS created a new
// SurfaceControl.
surfaceReplaced = (surfaceGenerationId != mSurface.getGenerationId()
|| surfaceControlChanged) && mSurface.isValid();
if (surfaceReplaced) {
mSurfaceSequenceId++;
}
if (alwaysConsumeSystemBarsChanged) {
mAttachInfo.mAlwaysConsumeSystemBars = mPendingAlwaysConsumeSystemBars;
dispatchApplyInsets = true;
}
if (updateCaptionInsets()) {
dispatchApplyInsets = true;
}
if (dispatchApplyInsets || mLastSystemUiVisibility !=
mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested) {
mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
dispatchApplyInsets(host);
// We applied insets so force contentInsetsChanged to ensure the
// hierarchy is measured below.
dispatchApplyInsets = true;
}

if (surfaceCreated) {
// If we are creating a new surface, then we need to
// completely redraw it.
mFullRedrawNeeded = true;
mPreviousTransparentRegion.setEmpty();

// Only initialize up-front if transparent regions are not
// requested, otherwise defer to see if the entire window
// will be transparent
if (mAttachInfo.mThreadedRenderer != null) {
try {
hwInitialized = mAttachInfo.mThreadedRenderer.initialize(mSurface);
if (hwInitialized && (host.mPrivateFlags
& View.PFLAG_REQUEST_TRANSPARENT_REGIONS) == 0) {
// Don't pre-allocate if transparent regions
// are requested as they may not be needed
mAttachInfo.mThreadedRenderer.allocateBuffers();
}
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
mLastPerformTraversalsSkipDrawReason = "oom_initialize_renderer";
return;
}
}
} else if (surfaceDestroyed) {
// If the surface has been removed, then reset the scroll
// positions.
if (mLastScrolledFocus != null) {
mLastScrolledFocus.clear();
}
mScrollY = mCurScrollY = 0;
if (mView instanceof RootViewSurfaceTaker) {
((RootViewSurfaceTaker) mView).onRootViewScrollYChanged(mCurScrollY);
}
if (mScroller != null) {
mScroller.abortAnimation();
}
// Our surface is gone
if (isHardwareEnabled()) {
mAttachInfo.mThreadedRenderer.destroy();
}
} else if ((surfaceReplaced || surfaceSizeChanged || updateSurfaceNeeded)
&& mSurfaceHolder == null
&& mAttachInfo.mThreadedRenderer != null
&& mSurface.isValid()) {
mFullRedrawNeeded = true;
try {
// Need to do updateSurface (which leads to CanvasContext::setSurface and
// re-create the EGLSurface) if either the Surface changed (as indicated by
// generation id), or WindowManager changed the surface size. The latter is
// because on some chips, changing the consumer side's BufferQueue size may
// not take effect immediately unless we create a new EGLSurface.
// Note that frame size change doesn't always imply surface size change (eg.
// drag resizing uses fullscreen surface), need to check surfaceSizeChanged
// flag from WindowManager.
mAttachInfo.mThreadedRenderer.updateSurface(mSurface);
} catch (OutOfResourcesException e) {
handleOutOfResourcesException(e);
mLastPerformTraversalsSkipDrawReason = "oom_update_surface";
return;
}
}

if (mDragResizing != dragResizing) {
if (dragResizing) {
final boolean backdropSizeMatchesFrame =
mWinFrame.width() == mPendingBackDropFrame.width()
&& mWinFrame.height() == mPendingBackDropFrame.height();
// TODO: Need cutout?
startDragResizing(mPendingBackDropFrame, !backdropSizeMatchesFrame,
mAttachInfo.mContentInsets, mAttachInfo.mStableInsets);
} else {
// We shouldn't come here, but if we come we should end the resize.
endDragResizing();
}
}
if (!mUseMTRenderer) {
if (dragResizing) {
mCanvasOffsetX = mWinFrame.left;
mCanvasOffsetY = mWinFrame.top;
} else {
mCanvasOffsetX = mCanvasOffsetY = 0;
}
}
} catch (RemoteException e) {
} finally {
if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}

if (DEBUG_ORIENTATION) Log.v(
TAG, "Relayout returned: frame=" + frame + ", surface=" + mSurface);

mAttachInfo.mWindowLeft = frame.left;
mAttachInfo.mWindowTop = frame.top;

// !!FIXME!! This next section handles the case where we did not get the
// window size we asked for. We should avoid this by getting a maximum size from
// the window session beforehand.
if (mWidth != frame.width() || mHeight != frame.height()) {
mWidth = frame.width();
mHeight = frame.height();
}

if (mSurfaceHolder != null) {
// The app owns the surface; tell it about what is going on.
if (mSurface.isValid()) {
// XXX .copyFrom() doesn't work!
//mSurfaceHolder.mSurface.copyFrom(mSurface);
mSurfaceHolder.mSurface = mSurface;
}
mSurfaceHolder.setSurfaceFrameSize(mWidth, mHeight);
mSurfaceHolder.mSurfaceLock.unlock();
if (surfaceCreated) {
mSurfaceHolder.ungetCallbacks();

mIsCreating = true;
SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceCreated(mSurfaceHolder);
}
}
}

if ((surfaceCreated || surfaceReplaced || surfaceSizeChanged
|| windowAttributesChanged) && mSurface.isValid()) {
SurfaceHolder.Callback[] callbacks = mSurfaceHolder.getCallbacks();
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
c.surfaceChanged(mSurfaceHolder, lp.format,
mWidth, mHeight);
}
}
mIsCreating = false;
}

if (surfaceDestroyed) {
notifyHolderSurfaceDestroyed();
mSurfaceHolder.mSurfaceLock.lock();
try {
mSurfaceHolder.mSurface = new Surface();
} finally {
mSurfaceHolder.mSurfaceLock.unlock();
}
}
}

final ThreadedRenderer threadedRenderer = mAttachInfo.mThreadedRenderer;
if (threadedRenderer != null && threadedRenderer.isEnabled()) {
if (hwInitialized
|| mWidth != threadedRenderer.getWidth()
|| mHeight != threadedRenderer.getHeight()
|| mNeedsRendererSetup) {
threadedRenderer.setup(mWidth, mHeight, mAttachInfo,
mWindowAttributes.surfaceInsets);
mNeedsRendererSetup = false;
}
}

// TODO: In the CL "ViewRootImpl: Fix issue with early draw report in
// seamless rotation". We moved processing of RELAYOUT_RES_BLAST_SYNC
// earlier in the function, potentially triggering a call to
// reportNextDraw(). That same CL changed this and the next reference
// to wasReportNextDraw, such that this logic would remain undisturbed
// (it continues to operate as if the code was never moved). This was
// done to achieve a more hermetic fix for S, but it's entirely
// possible that checking the most recent value is actually more
// correct here.
if (!mStopped || mReportNextDraw) {
if (mWidth != host.getMeasuredWidth() || mHeight != host.getMeasuredHeight()
|| dispatchApplyInsets || updatedConfiguration) {
int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width,
lp.privateFlags);
int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height,
lp.privateFlags);

if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth="
+ mWidth + " measuredWidth=" + host.getMeasuredWidth()
+ " mHeight=" + mHeight
+ " measuredHeight=" + host.getMeasuredHeight()
+ " dispatchApplyInsets=" + dispatchApplyInsets);

// Ask host how big it wants to be
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);

// Implementation of weights from WindowManager.LayoutParams
// We just grow the dimensions as needed and re-measure if
// needs be
int width = host.getMeasuredWidth();
int height = host.getMeasuredHeight();
boolean measureAgain = false;

if (lp.horizontalWeight > 0.0f) {
width += (int) ((mWidth - width) * lp.horizontalWeight);
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(width,
MeasureSpec.EXACTLY);
measureAgain = true;
}
if (lp.verticalWeight > 0.0f) {
height += (int) ((mHeight - height) * lp.verticalWeight);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
measureAgain = true;
}

if (measureAgain) {
if (DEBUG_LAYOUT) Log.v(mTag,
"And hey let's measure once more: width=" + width
+ " height=" + height);
performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
}

layoutRequested = true;
}
}
} else {
// Not the first pass and no window/insets/visibility change but the window
// may have moved and we need check that and if so to update the left and right
// in the attach info. We translate only the window frame since on window move
// the window manager tells us only for the new frame but the insets are the
// same and we do not want to translate them more than once.
maybeHandleWindowMove(frame);
}

if (mViewMeasureDeferred) {
// It's time to measure the views since we are going to layout them.
performMeasure(
MeasureSpec.makeMeasureSpec(frame.width(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(frame.height(), MeasureSpec.EXACTLY));
}

if (!mRelayoutRequested && mCheckIfCanDraw) {
// We had a sync previously, but we didn't call IWindowSession#relayout in this
// traversal. So we don't know if the sync is complete that we can continue to draw.
// Here invokes cancelDraw to obtain the information.
try {
cancelDraw = mWindowSession.cancelDraw(mWindow);
cancelReason = "wm_sync";
if (DEBUG_BLAST) {
Log.d(mTag, "cancelDraw returned " + cancelDraw);
}
} catch (RemoteException e) {
}
}

if (surfaceSizeChanged || surfaceReplaced || surfaceCreated ||
windowAttributesChanged || mChildBoundingInsetsChanged) {
// If the surface has been replaced, there's a chance the bounds layer is not parented
// to the new layer. When updating bounds layer, also reparent to the main VRI
// SurfaceControl to ensure it's correctly placed in the hierarchy.
//
// This needs to be done on the client side since WMS won't reparent the children to the
// new surface if it thinks the app is closing. WMS gets the signal that the app is
// stopping, but on the client side it doesn't get stopped since it's restarted quick
// enough. WMS doesn't want to keep around old children since they will leak when the
// client creates new children.
prepareSurfaces();
mChildBoundingInsetsChanged = false;
}

final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
boolean triggerGlobalLayoutListener = didLayout
|| mAttachInfo.mRecomputeGlobalAttributes;
if (didLayout) {
performLayout(lp, mWidth, mHeight);

// By this point all views have been sized and positioned
// We can compute the transparent area

if ((host.mPrivateFlags & View.PFLAG_REQUEST_TRANSPARENT_REGIONS) != 0) {
// start out transparent
// TODO: AVOID THAT CALL BY CACHING THE RESULT?
host.getLocationInWindow(mTmpLocation);
mTransparentRegion.set(mTmpLocation[0], mTmpLocation[1],
mTmpLocation[0] + host.mRight - host.mLeft,
mTmpLocation[1] + host.mBottom - host.mTop);

host.gatherTransparentRegion(mTransparentRegion);
if (mTranslator != null) {
mTranslator.translateRegionInWindowToScreen(mTransparentRegion);
}

if (!mTransparentRegion.equals(mPreviousTransparentRegion)) {
mPreviousTransparentRegion.set(mTransparentRegion);
mFullRedrawNeeded = true;
// TODO: Ideally we would do this in prepareSurfaces,
// but prepareSurfaces is currently working under
// the assumption that we paused the render thread
// via the WM relayout code path. We probably eventually
// want to synchronize transparent region hint changes
// with draws.
SurfaceControl sc = getSurfaceControl();
if (sc.isValid()) {
mTransaction.setTransparentRegionHint(sc, mTransparentRegion).apply();
}
}
}

if (DBG) {
System.out.println("======================================");
System.out.println("performTraversals -- after setFrame");
host.debug();
}
}

boolean didUseTransaction = false;
// These callbacks will trigger SurfaceView SurfaceHolder.Callbacks and must be invoked
// after the measure pass. If its invoked before the measure pass and the app modifies
// the view hierarchy in the callbacks, we could leave the views in a broken state.
if (surfaceCreated) {
notifySurfaceCreated(mTransaction);
didUseTransaction = true;
} else if (surfaceReplaced) {
notifySurfaceReplaced(mTransaction);
didUseTransaction = true;
} else if (surfaceDestroyed) {
notifySurfaceDestroyed();
}

if (didUseTransaction) {
applyTransactionOnDraw(mTransaction);
}

if (triggerGlobalLayoutListener) {
mAttachInfo.mRecomputeGlobalAttributes = false;
mAttachInfo.mTreeObserver.dispatchOnGlobalLayout();
}

Rect contentInsets = null;
Rect visibleInsets = null;
Region touchableRegion = null;
int touchableInsetMode = TOUCHABLE_INSETS_REGION;
boolean computedInternalInsets = false;
if (computesInternalInsets) {
final ViewTreeObserver.InternalInsetsInfo insets = mAttachInfo.mGivenInternalInsets;

// Clear the original insets.
insets.reset();

// Compute new insets in place.
mAttachInfo.mTreeObserver.dispatchOnComputeInternalInsets(insets);
mAttachInfo.mHasNonEmptyGivenInternalInsets = !insets.isEmpty();

// Tell the window manager.
if (insetsPending || !mLastGivenInsets.equals(insets)) {
mLastGivenInsets.set(insets);

// Translate insets to screen coordinates if needed.
if (mTranslator != null) {
contentInsets = mTranslator.getTranslatedContentInsets(insets.contentInsets);
visibleInsets = mTranslator.getTranslatedVisibleInsets(insets.visibleInsets);
touchableRegion = mTranslator.getTranslatedTouchableArea(insets.touchableRegion);
} else {
contentInsets = insets.contentInsets;
visibleInsets = insets.visibleInsets;
touchableRegion = insets.touchableRegion;
}
computedInternalInsets = true;
}
touchableInsetMode = insets.mTouchableInsets;
}
boolean needsSetInsets = computedInternalInsets;
needsSetInsets |= !Objects.equals(mPreviousTouchableRegion, mTouchableRegion) &&
(mTouchableRegion != null);
if (needsSetInsets) {
if (mTouchableRegion != null) {
if (mPreviousTouchableRegion == null) {
mPreviousTouchableRegion = new Region();
}
mPreviousTouchableRegion.set(mTouchableRegion);
if (touchableInsetMode != TOUCHABLE_INSETS_REGION) {
Log.e(mTag, "Setting touchableInsetMode to non TOUCHABLE_INSETS_REGION" +
" from OnComputeInternalInsets, while also using setTouchableRegion" +
" causes setTouchableRegion to be ignored");
}
} else {
mPreviousTouchableRegion = null;
}
if (contentInsets == null) contentInsets = new Rect(0,0,0,0);
if (visibleInsets == null) visibleInsets = new Rect(0,0,0,0);
if (touchableRegion == null) {
touchableRegion = mTouchableRegion;
} else if (touchableRegion != null && mTouchableRegion != null) {
touchableRegion.op(touchableRegion, mTouchableRegion, Region.Op.UNION);
}
try {
mWindowSession.setInsets(mWindow, touchableInsetMode,
contentInsets, visibleInsets, touchableRegion);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
} else if (mTouchableRegion == null && mPreviousTouchableRegion != null) {
mPreviousTouchableRegion = null;
try {
mWindowSession.clearTouchableRegion(mWindow);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

if (mFirst) {
if (sAlwaysAssignFocus || !isInTouchMode()) {
// handle first focus request
if (DEBUG_INPUT_RESIZE) {
Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus());
}
if (mView != null) {
if (!mView.hasFocus()) {
mView.restoreDefaultFocus();
if (DEBUG_INPUT_RESIZE) {
Log.v(mTag, "First: requested focused view=" + mView.findFocus());
}
} else {
if (DEBUG_INPUT_RESIZE) {
Log.v(mTag, "First: existing focused view=" + mView.findFocus());
}
}
}
} else {
// Some views (like ScrollView) won't hand focus to descendants that aren't within
// their viewport. Before layout, there's a good change these views are size 0
// which means no children can get focus. After layout, this view now has size, but
// is not guaranteed to hand-off focus to a focusable child (specifically, the edge-
// case where the child has a size prior to layout and thus won't trigger
// focusableViewAvailable).
View focused = mView.findFocus();
if (focused instanceof ViewGroup
&& ((ViewGroup) focused).getDescendantFocusability()
== ViewGroup.FOCUS_AFTER_DESCENDANTS) {
focused.restoreDefaultFocus();
}
}
}

final boolean changedVisibility = (viewVisibilityChanged || mFirst) && isViewVisible;
if (changedVisibility) {
maybeFireAccessibilityWindowStateChangedEvent();
}

mFirst = false;
mWillDrawSoon = false;
mNewSurfaceNeeded = false;
mViewVisibility = viewVisibility;

final boolean hasWindowFocus = mAttachInfo.mHasWindowFocus && isViewVisible;
mImeFocusController.onTraversal(hasWindowFocus, mWindowAttributes);

if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
reportNextDraw("first_relayout");
}

mCheckIfCanDraw = isSyncRequest || cancelDraw;

boolean cancelDueToPreDrawListener = mAttachInfo.mTreeObserver.dispatchOnPreDraw();
boolean cancelAndRedraw = cancelDueToPreDrawListener
|| (cancelDraw && mDrewOnceForSync);
if (cancelAndRedraw) {
Log.d(mTag, "Cancelling draw."
+ " cancelDueToPreDrawListener=" + cancelDueToPreDrawListener
+ " cancelDueToSync=" + (cancelDraw && mDrewOnceForSync));
}
if (!cancelAndRedraw) {
// A sync was already requested before the WMS requested sync. This means we need to
// sync the buffer, regardless if WMS wants to sync the buffer.
if (mActiveSurfaceSyncGroup != null) {
mSyncBuffer = true;
}

createSyncIfNeeded();
notifyDrawStarted(isInWMSRequestedSync());
mDrewOnceForSync = true;

// If the active SSG is also requesting to sync a buffer, the following needs to happen
// 1. Ensure we keep track of the number of active syncs to know when to disable RT
// RT animations that conflict with syncing a buffer.
// 2. Add a safeguard SSG to prevent multiple SSG that sync buffers from being submitted
// out of order.
if (mActiveSurfaceSyncGroup != null && mSyncBuffer) {
updateSyncInProgressCount(mActiveSurfaceSyncGroup);
safeguardOverlappingSyncs(mActiveSurfaceSyncGroup);
}
}

if (!isViewVisible) {
mLastPerformTraversalsSkipDrawReason = "view_not_visible";
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).endChangingAnimations();
}
mPendingTransitions.clear();
}

if (mActiveSurfaceSyncGroup != null) {
mActiveSurfaceSyncGroup.markSyncReady();
}
} else if (cancelAndRedraw) {
mLastPerformTraversalsSkipDrawReason = cancelDueToPreDrawListener
? "predraw_" + mAttachInfo.mTreeObserver.getLastDispatchOnPreDrawCanceledReason()
: "cancel_" + cancelReason;
// Try again
scheduleTraversals();
} else {
if (mPendingTransitions != null && mPendingTransitions.size() > 0) {
for (int i = 0; i < mPendingTransitions.size(); ++i) {
mPendingTransitions.get(i).startChangingAnimations();
}
mPendingTransitions.clear();
}
if (!performDraw(mActiveSurfaceSyncGroup) && mActiveSurfaceSyncGroup != null) {
mActiveSurfaceSyncGroup.markSyncReady();
}
}

if (mAttachInfo.mContentCaptureEvents != null) {
notifyContentCaptureEvents();
}

mIsInTraversal = false;
mRelayoutRequested = false;

if (!cancelAndRedraw) {
mReportNextDraw = false;
mLastReportNextDrawReason = null;
mActiveSurfaceSyncGroup = null;
mSyncBuffer = false;
if (isInWMSRequestedSync()) {
mWmsRequestSyncGroup.markSyncReady();
mWmsRequestSyncGroup = null;
mWmsRequestSyncGroupState = WMS_SYNC_NONE;
}
}
}

}

  desiredWindowWidth和desiredWindowHeight是当前宽度和高度。Activity窗口当前的宽度和高度是保存在mWinFrame中,另外mWidth和mHeight也是用来描述Activity窗口当前的宽度和高度,但是它们的值是由应用程序进程上一次主动请求WindowManagerService服务计算得到,并且会一直保持不变到应用程序进程下一次再请求WindowManagerService服务来重新计算。Activity窗口的当前高度和宽度有时候被WindowManagerService修改后保存在mWinFrame中,可能会mWidth和mHeight的值不同。

  如果Activity窗口是第一次被请求进行测量、布局和绘制操作,即成员变量mFirst的值为true,那么它的当前宽度desiredWindowWidth和desiredWindowHeight就等于屏幕的宽度和高度,否则的话,它的当前宽度desiredWindowWidth和desiredWindowHeight就等于保存在mWinFrame中的值。

  如果Activity窗口不是第一次测量、布局、绘制操作,并且Activity窗口主动上一次请求WindowManagerService服务计算得到的宽度mWidth和高度mHeight不等于Activity窗口的当前宽度desiredWindowWidth和desiredWindowHeight,那么说明Activity窗口的大小发生了变化,这时候会重新将mWinFrame的值更新过去并重新绘制。