android /system,Android中SystemUI解析

66b52468c121889b900d4956032f1009.png

8种机械键盘轴体对比

本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?

还未完成,待继续补充.

Android8.1.0 SystemUI代码统计如下:1

2

3

4

5

6

7

8

9

10-------------------------------------------------------------------------------

Language files blank comment code

-------------------------------------------------------------------------------

Java 892 23725 27078 143796

XML 1318 4337 20556 91781

Python 1 25 10 130

Bourne Shell 1 1 0 13

-------------------------------------------------------------------------------

SUM: 2212 28088 47644 235720

-------------------------------------------------------------------------------

从Android7.0开始,把Keyguard模块的代码也一起放到了SystemUI模块中,从代码统计来看,SystemUI中Java代码大概有14万行.

实际SystemUI与Framework有很多的交互,还有很多的代码是在Framework的其他模块里面.

4.4版本SystemUI中SystemBar启动流程如下:

ae83dbc4375d2393495e17e6bcd3ffab.png

主要类功能初步解析

ImmersiveModeConfirmation.java

首次隐藏状态栏和导航栏,进入沉浸模式是的提示

SystemUI包含的服务

SystemUI通过java启动的服务有13个,分别是:

1.TunerService 系统界面调谐器

系统界面调制器是安卓M加入的,当用户长按下拉菜单的齿轮卡3秒中就可以在setting app里加入界面调制器。

可以对状态栏、导航栏、勿扰模式以及锁屏界面进行局部定制.

2.KeyguardViewMediator

锁屏管理

3.Recents

最近应用模块,

4.VolumeUI

音量的调节

5.Divider

6.SystemBars

7.StorageNotification

8.PowerUI

9.RingtonePlayer

10.KeyboardUI

11.PipUI

12.ShortcutKeyDispatcher

13.VendorServices

通过xml启动的服务有6个,分别是:

1.SystemUIService

2.SystemUISecondaryUserService

3.TakeScreenshotService

4.ImageWallpaper

5.RecentsSystemUserService

6.DessertCaseDream

7.KeyguardService

8.DozeService

先以KeyguardViewMediator服务启动流程图为例进行分析,其它服务启动顺序与这个类似,只是功能不同而已。

21a0ac4a9932da237037d0b10b5f5f61.png

SystemBar的启动流程图如下:

69b10381f4c16f5e015367baee167390.png

PhoneStatusBar.java中的createAndAddWindows()会初始化并且加载SystemUI的绝大多数界面,包括statusbar与navigationbar,以及初始化QSHostView。

SystemUI的功能模块

SystemUI的功能模块:

a)Keyguard

锁屏和壁纸

b)StatusBar:电量、时间、SIM卡状态和信号、WIFI、Bluetooth、数据连接状态

通知、

c)NavigationBar

d)Shortcut

截图和录屏

e)Recents

f)PipUI

g)Tuner

h)RingtonePlayer

SystemUI重难点滑动事件的处理

2.

状态栏

锁屏状态栏

状态栏反色

沉浸式状态栏

信号图标的刷新

凹口处理

导航栏 NavigationBar

导航栏中的Back键和HOME键的事件处理:

https://blog.youkuaiyun.com/span76/article/details/48441971

Recent键的处理呢?

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java

中的onRecentsClick函数处理Recent键

导航栏的加载流程基于Android8.1代码

对于NavigationBar的加载从PhoneWindowManager开始讲起,PhoneWindowManager主要用于处理几个实体按键或者虚拟按键(Home/Back/Recent/Power/Volume up/Volume down)等按键事件,包括音量加减,截图,长按Power调出关机界面,长按Home/Back/Recent键,短按Home/Back/Recent/Power键. 显示点击点的位置.BugReport

以及SystemUI的NavigationBar和StatusBar的加载.手势,方向,HDMI,

StatusBar,NavigationBar,Wallpaper,文字输入法和语言输入法等窗口的绘制

显示开机界面中的Android正在启动.

在PhoneWindowManager.java中与StatusBar和NavigationBar相关的代码如下: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

583public class implements WindowManagerPolicy{

static final String TAG = "WindowManager";

...

boolean mSafeMode;

WindowState mStatusBar = null;

int mStatusBarHeight;

WindowState mNavigationBar = null;

boolean mHasNavigationBar = false;

boolean mNavigationBarCanMove = false;

int mNavigationBarPosition = NAV_BAR_BOTTOM;

int[] mNavigationBarHeightForRotationDefault = new int[4];

int[] mNavigationBarWidthForRotationDefault = new int[4];

int[] mNavigationBarHeightForRotationInCarMode = new int[4];

int[] mNavigationBarWidthForRotationInCarMode = new int[4];

...

boolean mForceStatusBar;

boolean mForceStatusBarFromKeyguard;

private boolean mForceStatusBarTransparent;

int mNavBarOpacityMode = NAV_BAR_OPAQUE_WHEN_FREEFORM_OR_DOCKED;

...

private final StatusBarController mStatusBarController = new StatusBarController();

private final BarController mNavigationBarController = new BarController("NavigationBar",

View.NAVIGATION_BAR_TRANSIENT,

View.NAVIGATION_BAR_UNHIDE,

View.NAVIGATION_BAR_TRANSLUCENT,

StatusBarManager.WINDOW_NAVIGATION_BAR,

WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION,

View.NAVIGATION_BAR_TRANSPARENT);

...

private ImmersiveModeConfirmation mImmersiveModeConfirmation;//沉浸模式

...

IStatusBarService getStatusBarService(){

synchronized (mServiceAquireLock) {

if (mStatusBarService == null) {

mStatusBarService = IStatusBarService.Stub.asInterface(

ServiceManager.getService("statusbar"));

}

return mStatusBarService;

}

}

StatusBarManagerInternal getStatusBarManagerInternal(){

synchronized (mServiceAquireLock) {

if (mStatusBarManagerInternal == null) {

mStatusBarManagerInternal =

LocalServices.getService(StatusBarManagerInternal.class);

}

return mStatusBarManagerInternal;

}

}

...

/** {@inheritDoc} */

public void init(Context context, IWindowManager windowManager,

WindowManagerFuncs windowManagerFuncs){

mContext = context;

mWindowManager = windowManager;

mWindowManagerFuncs = windowManagerFuncs;

mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);

mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);

mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);

mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);

mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);

mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);

mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);

mHasFeatureLeanback = mContext.getPackageManager().hasSystemFeature(FEATURE_LEANBACK);

mAccessibilityShortcutController =

new AccessibilityShortcutController(mContext, new Handler(), mCurrentUserId);

// Init display burn-in protection

boolean burnInProtectionEnabled = context.getResources().getBoolean(

com.android.internal.R.bool.config_enableBurnInProtection);

// Allow a system property to override this. Used by developer settings.

boolean burnInProtectionDevMode =

SystemProperties.getBoolean("persist.debug.force_burn_in", false);

...

readConfigurationDependentBehaviors();

...

mImmersiveModeConfirmation = new ImmersiveModeConfirmation(mContext);

...

}

/**

* Read values from config.xml that may be overridden depending on

* the configuration of the device.

* eg. Disable long press on home goes to recents on sw600dp.

*/

private void readConfigurationDependentBehaviors(){

final Resources res = mContext.getResources();

...

mNavBarOpacityMode = res.getInteger(

com.android.internal.R.integer.config_navBarOpacityMode);

}

public void setInitialDisplaySize(Display display, int width, int height, int density){

// This method might be called before the policy has been fully initialized

// or for other displays we don't care about.

// TODO(multi-display): Define policy for secondary displays.

...

// Allow the navigation bar to move on non-square small devices (phones).

mNavigationBarCanMove = width != height && shortSizeDp < 600;

mHasNavigationBar = res.getBoolean(com.android.internal.R.bool.config_showNavigationBar);

// Allow a system property to override this. Used by the emulator.

// See also hasNavigationBar().

String navBarOverride = SystemProperties.get("qemu.hw.mainkeys");

if ("1".equals(navBarOverride)) {

mHasNavigationBar = false;

} else if ("0".equals(navBarOverride)) {

mHasNavigationBar = true;

}

...

}

...

private boolean canHideNavigationBar(){

return mHasNavigationBar;

}

...

public void adjustWindowParamsLw(WindowManager.LayoutParams attrs){

switch (attrs.type) {

case TYPE_SYSTEM_OVERLAY:

case TYPE_SECURE_SYSTEM_OVERLAY:

// These types of windows can't receive input events.

attrs.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE

| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;

attrs.flags &= ~WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;

break;

case TYPE_STATUS_BAR:

// If the Keyguard is in a hidden state (occluded by another window), we force to

// remove the wallpaper and keyguard flag so that any change in-flight after setting

// the keyguard as occluded wouldn't set these flags again.

// See [email protected] #processKeyguardSetHiddenResultLw}.

if (mKeyguardOccluded) {

attrs.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;

attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;

}

break;

...

}

if (attrs.type != TYPE_STATUS_BAR) {

// The status bar is the only window allowed to exhibit keyguard behavior.

attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;

}

...

}

....

public void onConfigurationChanged(){

// TODO(multi-display): Define policy for secondary displays.

Context uiContext = ActivityThread.currentActivityThread().getSystemUiContext();

final Resources res = uiContext.getResources();

mStatusBarHeight =

res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);

// Height of the navigation bar when presented horizontally at bottom

mNavigationBarHeightForRotationDefault[mPortraitRotation] =

mNavigationBarHeightForRotationDefault[mUpsideDownRotation] =

res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);

mNavigationBarHeightForRotationDefault[mLandscapeRotation] =

mNavigationBarHeightForRotationDefault[mSeascapeRotation] = res.getDimensionPixelSize(

com.android.internal.R.dimen.navigation_bar_height_landscape);

// Width of the navigation bar when presented vertically along one side

mNavigationBarWidthForRotationDefault[mPortraitRotation] =

mNavigationBarWidthForRotationDefault[mUpsideDownRotation] =

mNavigationBarWidthForRotationDefault[mLandscapeRotation] =

mNavigationBarWidthForRotationDefault[mSeascapeRotation] =

res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);

if (ALTERNATE_CAR_MODE_NAV_SIZE) {

// Height of the navigation bar when presented horizontally at bottom

mNavigationBarHeightForRotationInCarMode[mPortraitRotation] =

mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] =

res.getDimensionPixelSize(

com.android.internal.R.dimen.navigation_bar_height_car_mode);

mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] =

mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize(

com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode);

// Width of the navigation bar when presented vertically along one side

mNavigationBarWidthForRotationInCarMode[mPortraitRotation] =

mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] =

mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] =

mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] =

res.getDimensionPixelSize(

com.android.internal.R.dimen.navigation_bar_width_car_mode);

}

}

...

private int getNavigationBarWidth(int rotation, int uiMode){

if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {

return mNavigationBarWidthForRotationInCarMode[rotation];

} else {

return mNavigationBarWidthForRotationDefault[rotation];

}

}

...

private int getNavigationBarHeight(int rotation, int uiMode){

if (ALTERNATE_CAR_MODE_NAV_SIZE && (uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) {

return mNavigationBarHeightForRotationInCarMode[rotation];

} else {

return mNavigationBarHeightForRotationDefault[rotation];

}

}

...

/**

* Preflight adding a window to the system.

*

* Currently enforces that three window types are singletons:

*

*

STATUS_BAR_TYPE

*

KEYGUARD_TYPE

*

*

* @param win The window to be added

* @param attrs Information about the window to be added

*

* @return If ok, WindowManagerImpl.ADD_OKAY. If too many singletons,

* WindowManagerImpl.ADD_MULTIPLE_SINGLETON

*/

public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs){

switch (attrs.type) {

case TYPE_STATUS_BAR:

mContext.enforceCallingOrSelfPermission(

android.Manifest.permission.STATUS_BAR_SERVICE,

"PhoneWindowManager");

if (mStatusBar != null) {

if (mStatusBar.isAlive()) {

return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;

}

}

mStatusBar = win;

mStatusBarController.setWindow(win);

setKeyguardOccludedLw(mKeyguardOccluded, true /* force */);

break;

case TYPE_NAVIGATION_BAR:

mContext.enforceCallingOrSelfPermission(

android.Manifest.permission.STATUS_BAR_SERVICE,

"PhoneWindowManager");

if (mNavigationBar != null) {

if (mNavigationBar.isAlive()) {

return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;

}

}

mNavigationBar = win;

mNavigationBarController.setWindow(win);

mNavigationBarController.setOnBarVisibilityChangedListener(

mNavBarVisibilityListener, true);

if (DEBUG_LAYOUT) Slog.i(TAG, "NAVIGATION BAR: " + mNavigationBar);

break;

case TYPE_NAVIGATION_BAR_PANEL:

case TYPE_STATUS_BAR_PANEL:

case TYPE_STATUS_BAR_SUB_PANEL:

case TYPE_VOICE_INTERACTION_STARTING:

mContext.enforceCallingOrSelfPermission(

android.Manifest.permission.STATUS_BAR_SERVICE,

"PhoneWindowManager");

break;

}

return ADD_OKAY;

}

...

/** {@inheritDoc} */

@Override

public void removeWindowLw(WindowState win){

if (mStatusBar == win) {

mStatusBar = null;

mStatusBarController.setWindow(null);

} else if (mNavigationBar == win) {

mNavigationBar = null;

mNavigationBarController.setWindow(null);

}

}

...

/** {@inheritDoc} */

@Override

public int selectAnimationLw(WindowState win, int transit){

if (PRINT_ANIM) Log.i(TAG, "selectAnimation in " + win

+ ": transit=" + transit);

if (win == mStatusBar) {

final boolean isKeyguard = (win.getAttrs().privateFlags & PRIVATE_FLAG_KEYGUARD) != 0;

final boolean expanded = win.getAttrs().height == MATCH_PARENT

&& win.getAttrs().width == MATCH_PARENT;

if (isKeyguard || expanded) {

return -1;

}

if (transit == TRANSIT_EXIT

|| transit == TRANSIT_HIDE) {

return R.anim.dock_top_exit;

} else if (transit == TRANSIT_ENTER

|| transit == TRANSIT_SHOW) {

return R.anim.dock_top_enter;

}

} else if (win == mNavigationBar) {

if (win.getAttrs().windowAnimations != 0) {

return 0;

...

return 0;

}

...

/** {@inheritDoc} */

@Override

public long interceptKeyBeforeDispatching(WindowState win, KeyEvent event, int policyFlags){

final boolean keyguardOn = keyguardOn();

/*final*/ int keyCode = event.getKeyCode();

final int repeatCount = event.getRepeatCount();

final int metaState = event.getMetaState();

final int flags = event.getFlags();

final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

final boolean canceled = event.isCanceled();

final boolean longPress = (flags & KeyEvent.FLAG_LONG_PRESS) != 0;

...

}

...

private final Runnable mClearHideNavigationFlag = new Runnable() {

@Override

public void run(){

synchronized (mWindowManagerFuncs.getWindowManagerLock()) {

// Clear flags.

mForceClearedSystemUiFlags &=

~View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;

}

mWindowManagerFuncs.reevaluateStatusBarVisibility();

}

};

...

/**

* Input handler used while nav bar is hidden. Captures any touch on the screen,

* to determine when the nav bar should be shown and prevent applications from

* receiving those touches.

* 当状态栏和导航栏处于隐藏状态的时候,点击屏幕,会显示出状态栏和导航栏,显示时间大概1s

*/

final class HideNavInputEventReceiver extends InputEventReceiver{

public HideNavInputEventReceiver(InputChannel inputChannel, Looper looper){

super(inputChannel, looper);

}

@Override

public void onInputEvent(InputEvent event, int displayId){

boolean handled = false;

try {

if (event instanceof MotionEvent

&& (event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) {

final MotionEvent motionEvent = (MotionEvent)event;

if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {

// When the user taps down, we re-show the nav bar.

boolean changed = false;

synchronized (mWindowManagerFuncs.getWindowManagerLock()) {

if (mInputConsumer == null) {

return;

}

// Any user activity always causes us to show the

// navigation controls, if they had been hidden.

// We also clear the low profile and only content

// flags so that tapping on the screen will atomically

// restore all currently hidden screen decorations.

int newVal = mResettingSystemUiFlags |

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION |

View.SYSTEM_UI_FLAG_LOW_PROFILE |

View.SYSTEM_UI_FLAG_FULLSCREEN;

if (mResettingSystemUiFlags != newVal) {

mResettingSystemUiFlags = newVal;

changed = true;

}

// We don't allow the system's nav bar to be hidden

// again for 1 second, to prevent applications from

// spamming us and keeping it from being shown.

newVal = mForceClearedSystemUiFlags |

View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;

if (mForceClearedSystemUiFlags != newVal) {

mForceClearedSystemUiFlags = newVal;

changed = true;

mHandler.postDelayed(mClearHideNavigationFlag, 1000);

}

}

if (changed) {

mWindowManagerFuncs.reevaluateStatusBarVisibility();

}

}

}

} finally {

finishInputEvent(event, handled);

}

}

}

...

@Override

public int adjustSystemUiVisibilityLw(int visibility){

mStatusBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);

mNavigationBarController.adjustSystemUiVisibilityLw(mLastSystemUiFlags, visibility);

// Reset any bits in mForceClearingStatusBarVisibility that

// are now clear.

mResettingSystemUiFlags &= visibility;

// Clear any bits in the new visibility that are currently being

// force cleared, before reporting it.

return visibility & ~mResettingSystemUiFlags

& ~mForceClearedSystemUiFlags;

}

...

private boolean layoutStatusBar(Rect pf, Rect df, Rect of, Rect vf, Rect dcf, int sysui,

boolean isKeyguardShowing){

// decide where the status bar goes ahead of time

if (mStatusBar != null) {

// apply any navigation bar insets

pf.left = df.left = of.left = mUnrestrictedScreenLeft;

pf.top = df.top = of.top = mUnrestrictedScreenTop;

pf.right = df.right = of.right = mUnrestrictedScreenWidth + mUnrestrictedScreenLeft;

pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenHeight

+ mUnrestrictedScreenTop;

vf.left = mStableLeft;

vf.top = mStableTop;

vf.right = mStableRight;

vf.bottom = mStableBottom;

mStatusBarLayer = mStatusBar.getSurfaceLayer();

// Let the status bar determine its size.

mStatusBar.computeFrameLw(pf /* parentFrame */, df /* displayFrame */,

vf /* overlayFrame */, vf /* contentFrame */, vf /* visibleFrame */,

dcf /* decorFrame */, vf /* stableFrame */, vf /* outsetFrame */);

// For layout, the status bar is always at the top with our fixed height.

mStableTop = mUnrestrictedScreenTop + mStatusBarHeight;

boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;

boolean statusBarTranslucent = (sysui

& (View.STATUS_BAR_TRANSLUCENT | View.STATUS_BAR_TRANSPARENT)) != 0;

if (!isKeyguardShowing) {

statusBarTranslucent &= areTranslucentBarsAllowed();

}

// If the status bar is hidden, we don't want to cause

// windows behind it to scroll.

if (mStatusBar.isVisibleLw() && !statusBarTransient) {

// Status bar may go away, so the screen area it occupies

// is available to apps but just covering them when the

// status bar is visible.

mDockTop = mUnrestrictedScreenTop + mStatusBarHeight;

mContentTop = mVoiceContentTop = mCurTop = mDockTop;

mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;

mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;

mContentRight = mVoiceContentRight = mCurRight = mDockRight;

if (DEBUG_LAYOUT) Slog.v(TAG, "Status bar: " +

String.format(

"dock=[%d,%d][%d,%d] content=[%d,%d][%d,%d] cur=[%d,%d][%d,%d]",

mDockLeft, mDockTop, mDockRight, mDockBottom,

mContentLeft, mContentTop, mContentRight, mContentBottom,

mCurLeft, mCurTop, mCurRight, mCurBottom));

}

if (mStatusBar.isVisibleLw() && !mStatusBar.isAnimatingLw()

&& !statusBarTransient && !statusBarTranslucent

&& !mStatusBarController.wasRecentlyTranslucent()) {

// If the opaque status bar is currently requested to be visible,

// and not in the process of animating on or off, then

// we can tell the app that it is covered by it.

mSystemTop = mUnrestrictedScreenTop + mStatusBarHeight;

}

if (mStatusBarController.checkHiddenLw()) {

return true;

}

}

return false;

}

private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation,

int uiMode, int overscanLeft, int overscanRight, int overscanBottom, Rect dcf,

boolean navVisible, boolean navTranslucent, boolean navAllowedHidden,

boolean statusBarExpandedNotKeyguard){

if (mNavigationBar != null) {

boolean transientNavBarShowing = mNavigationBarController.isTransientShowing();

// Force the navigation bar to its appropriate place and

// size. We need to do this directly, instead of relying on

// it to bubble up from the nav bar, because this needs to

// change atomically with screen rotations.

mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight,

displayRotation);

if (mNavigationBarPosition == NAV_BAR_BOTTOM) {

// It's a system nav bar or a portrait screen; nav bar goes on bottom.

int top = displayHeight - overscanBottom

- getNavigationBarHeight(displayRotation, uiMode);

mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom);

mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top;

if (transientNavBarShowing) {

mNavigationBarController.setBarShowingLw(true);

} else if (navVisible) {

mNavigationBarController.setBarShowingLw(true);

mDockBottom = mTmpNavigationFrame.top;

mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;

mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;

} else {

// We currently want to hide the navigation UI - unless we expanded the status

// bar.

mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);

}

if (navVisible && !navTranslucent && !navAllowedHidden

&& !mNavigationBar.isAnimatingLw()

&& !mNavigationBarController.wasRecentlyTranslucent()) {

// If the opaque nav bar is currently requested to be visible,

// and not in the process of animating on or off, then

// we can tell the app that it is covered by it.

mSystemBottom = mTmpNavigationFrame.top;

}

} else if (mNavigationBarPosition == NAV_BAR_RIGHT) {

// Landscape screen; nav bar goes to the right.

int left = displayWidth - overscanRight

- getNavigationBarWidth(displayRotation, uiMode);

mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight);

mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left;

if (transientNavBarShowing) {

mNavigationBarController.setBarShowingLw(true);

} else if (navVisible) {

mNavigationBarController.setBarShowingLw(true);

mDockRight = mTmpNavigationFrame.left;

mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;

mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;

} else {

// We currently want to hide the navigation UI - unless we expanded the status

// bar.

mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);

}

if (navVisible && !navTranslucent && !navAllowedHidden

&& !mNavigationBar.isAnimatingLw()

&& !mNavigationBarController.wasRecentlyTranslucent()) {

// If the nav bar is currently requested to be visible,

// and not in the process of animating on or off, then

// we can tell the app that it is covered by it.

mSystemRight = mTmpNavigationFrame.left;

}

} else if (mNavigationBarPosition == NAV_BAR_LEFT) {

// Seascape screen; nav bar goes to the left.

int right = overscanLeft + getNavigationBarWidth(displayRotation, uiMode);

mTmpNavigationFrame.set(overscanLeft, 0, right, displayHeight);

mStableLeft = mStableFullscreenLeft = mTmpNavigationFrame.right;

if (transientNavBarShowing) {

mNavigationBarController.setBarShowingLw(true);

} else if (navVisible) {

mNavigationBarController.setBarShowingLw(true);

mDockLeft = mTmpNavigationFrame.right;

// TODO: not so sure about those:

mRestrictedScreenLeft = mRestrictedOverscanScreenLeft = mDockLeft;

mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;

mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;

} else {

// We currently want to hide the navigation UI - unless we expanded the status

// bar.

mNavigationBarController.setBarShowingLw(statusBarExpandedNotKeyguard);

}

if (navVisible && !navTranslucent && !navAllowedHidden

&& !mNavigationBar.isAnimatingLw()

&& !mNavigationBarController.wasRecentlyTranslucent()) {

// If the nav bar is currently requested to be visible,

// and not in the process of animating on or off, then

// we can tell the app that it is covered by it.

mSystemLeft = mTmpNavigationFrame.right;

}

}

// Make sure the content and current rectangles are updated to

// account for the restrictions from the navigation bar.

mContentTop = mVoiceContentTop = mCurTop = mDockTop;

mContentBottom = mVoiceContentBottom = mCurBottom = mDockBottom;

mContentLeft = mVoiceContentLeft = mCurLeft = mDockLeft;

mContentRight = mVoiceContentRight = mCurRight = mDockRight;

mStatusBarLayer = mNavigationBar.getSurfaceLayer();

// And compute the final frame.

mNavigationBar.computeFrameLw(mTmpNavigationFrame, mTmpNavigationFrame,

mTmpNavigationFrame, mTmpNavigationFrame, mTmpNavigationFrame, dcf,

mTmpNavigationFrame, mTmpNavigationFrame);

if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + mTmpNavigationFrame);

if (mNavigationBarController.checkHiddenLw()) {

return true;

}

}

return false;

}

快捷开关

下拉通知栏

截图模块

防误触模块

亮度调节

PIP 画中画

双屏异显

Recent模块

在AndroidManifest.xml里面,我们注意到SystemUISecondaryUserService,对于每一个用户都有一个SystemUI进程,所以在用户切换的时候,需要用SystemUISecondaryUserService来确保新的用户进程创建.1

2

3

4

5

6

android:exported="true"

android:permission="com.android.systemui.permission.SELF" />

RecentsActivity.java的onCreate函数开始1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreDrawListener,

ColorExtractor.OnColorsChangedListener{

...

/** Called with the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState){

super.onCreate(savedInstanceState);

mFinishedOnStartup = false;

// In the case that the activity starts up before the Recents component has initialized

// (usually when debugging/pushing the SysUI apk), just finish this activity.

SystemServicesProxy ssp = Recents.getSystemServices();

if (ssp == null) {

mFinishedOnStartup = true;

finish();

return;

}

SystemUI 新功能

隐藏导航栏

悬浮按钮

单手模式(小屏模式)

单手键盘

口袋模式(防误触模式)

凹口设计

灭屏动画

翻转静音

1.来电静音

2.计时器和闹钟静音

双击唤醒

指关节截屏

字母手势

面部解锁

画中画

异屏双显

沉浸模式

##SB和NB颜色

通知栏和状态栏功能

通知

通知:允许通知.通知方式:状态栏上显示、在屏幕顶部悬浮显示、在锁屏上显示.

通知栏:

通知栏下拉规则:1)智能判断,有通知时,下拉显示通知,无通知时,下拉显示开关

2)依据下拉位置来判断:左边下拉显示通知页,右边下拉显示开关页

在通知栏显示流量信息.

状态栏:显示运营商名称

有通知时显示图标

显示实时网速

显示电量百分比,电量百分比显示方式

Demo模式命令调试SystemUI

在SystemUI目录有一个Readme.md文件,在8.1.0版本中内容如下:1* [Demo Mode](/packages/SystemUI/docs/demo_mode.md)

我们到此目录查看demo_mode.md文件

如下:

Demo Mode for the Android System UI

Demo mode for the status bar allows you to force the status bar into a fixed state, useful for taking screenshots with a consistent status bar state, or testing different status icon permutations. Demo mode is available in recent versions of Android.

Enabling demo mode

Demo mode is protected behind a system setting. To enable it for a device, run:1adb shell settings put global sysui_demo_allowed 1

Protocol

The protocol is based on broadcast intents, and thus can be driven via the command line (adb shell am broadcast) or an app (Context.sendBroadcast).

Broadcast action1com.android.systemui.demo

Commands

Commands and subcommands (below) are sent as string extras in the broadcast

intent.

Commands are sent as string extras with key command (required). Possible values are:CommandSubcommandArgumentDescriptionenterEnters demo mode, bar state allowed to be modified (for convenience, any of the other non-exit commands will automatically flip demo mode on, no need to call this explicitly in practice)

exitExits demo mode, bars back to their system-driven state

batteryControl the battery display

levelSets the battery level (0 - 100)

pluggedSets charging state (true, false)

powersaveSets power save mode (true, anything else)

networkControl the RSSI display

airplaneshow to show icon, any other value to hide

fullySets MCS state to fully connected (true, false)

wifishow to show icon, any other value to hide

levelSets wifi level (null or 0-4)

mobileshow to show icon, any other value to hide

datatypeValues: 1x, 3g, 4g, e, g, h, lte, roam, any other value to hide

levelSets mobile signal strength level (null or 0-4)

carriernetworkchangeSets mobile signal icon to carrier network change UX when disconnected (show to show icon, any other value to hide)

simsSets the number of sims (1-8)

nosimshow to show icon, any other value to hide

barsControl the visual style of the bars (opaque, translucent, etc)

modeSets the bars visual style (opaque, translucent, semi-transparent)

statusControl the system status icons

volumeSets the icon in the volume slot (silent, vibrate, any other value to hide)

bluetoothSets the icon in the bluetooth slot (connected, disconnected, any other value to hide)

locationSets the icon in the location slot (show, any other value to hide)

alarmSets the icon in the alarm_clock slot (show, any other value to hide)

syncSets the icon in the sync_active slot (show, any other value to hide)

ttySets the icon in the tty slot (show, any other value to hide)

eriSets the icon in the cdma_eri slot (show, any other value to hide)

muteSets the icon in the mute slot (show, any other value to hide)

speakerphoneSets the icon in the speakerphone slot (show, any other value to hide)

notificationsControl the notification icons

visiblefalse to hide the notification icons, any other value to show

clockControl the clock display

millisSets the time in millis

hhmmSets the time in hh:mm

Examples

Enter demo mode1adb shell am broadcast -a com.android.systemui.demo -e command enter

Exit demo mode1adb shell am broadcast -a com.android.systemui.demo -e command exit

Set the clock to 12:311

2adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm

1231

Set the wifi level to max1

2adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi

show -e level 4

Show the silent volume icon1

2adb shell am broadcast -a com.android.systemui.demo -e command status -e volume

silent

Empty battery, and not charging (red exclamation point)1

2adb shell am broadcast -a com.android.systemui.demo -e command battery -e level

0 -e plugged false

Hide the notification icons1

2adb shell am broadcast -a com.android.systemui.demo -e command notifications -e

visible false

Exit demo mode1adb shell am broadcast -a com.android.systemui.demo -e command exit

Example demo controller app in AOSP1frameworks/base/tests/SystemUIDemoModeController

Example script (for screenshotting purposes)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#!/bin/sh

CMD=$1

if [[ $ADB == "" ]]; then

ADB=adb

fi

if [[ $CMD != "on" && $CMD != "off" ]]; then

echo "Usage: $0 [on|off] [hhmm]" >&2

exit

fi

if [[ "$2" != "" ]]; then

HHMM="$2"

fi

$ADB root || exit

$ADB wait-for-devices

$ADB shell settings put global sysui_demo_allowed 1

if [ $CMD == "on" ]; then

$ADB shell am broadcast -a com.android.systemui.demo -e command enter || exit

if [[ "$HHMM" != "" ]]; then

$ADB shell am broadcast -a com.android.systemui.demo -e command clock -e

hhmm ${HHMM}

fi

$ADB shell am broadcast -a com.android.systemui.demo -e command battery -e

plugged false

$ADB shell am broadcast -a com.android.systemui.demo -e command battery -e

level 100

$ADB shell am broadcast -a com.android.systemui.demo -e command network -e

wifi show -e level 4

$ADB shell am broadcast -a com.android.systemui.demo -e command network -e

mobile show -e datatype none -e level 4

$ADB shell am broadcast -a com.android.systemui.demo -e command notifications

-e visible false

elif [ $CMD == "off" ]; then

$ADB shell am broadcast -a com.android.systemui.demo -e command exit

fi

导航栏和状态栏的显示与隐藏

POLICY_CONTROL实现

隐藏虚拟键及顶部状态栏:

adb shell settings put global policy_control immersive.full=隐藏顶部状态栏(底部虚拟键会显示):

adb shell settings put global policy_control immersive.status=

隐藏虚拟键(顶部状态栏会显示):

adb shell settings put global policy_control immersive.navigation=*

恢复原来的设置:

adb shell settings put global policy_control null

参考文献

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值