demo-mode.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // cspell: ignore carriernetworkchange
  2. // cspell: ignore powersave
  3. // cspell: ignore nosim
  4. // cspell: ignore systemui
  5. // cspell: ignore sysui
  6. import { Adb, AdbCommandBase } from '@yume-chan/adb';
  7. import { Settings } from "./settings.js";
  8. export enum DemoModeSignalStrength {
  9. Hidden = 'null',
  10. Level0 = '0',
  11. Level1 = '1',
  12. Level2 = '2',
  13. Level3 = '3',
  14. Level4 = '4',
  15. }
  16. // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/connectivity/NetworkControllerImpl.java;l=1362;drc=3b775bf7ad89902f94e03d191b0d8fbdebf2bdbf
  17. export const DemoModeMobileDataTypes = ['1x', '3g', '4g', '4g+', '5g', '5ge', '5g+',
  18. 'e', 'g', 'h', 'h+', 'lte', 'lte+', 'dis', 'not', 'null'] as const;
  19. export type DemoModeMobileDataType = (typeof DemoModeMobileDataTypes)[number];
  20. // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java;l=3136
  21. export const DemoModeStatusBarModes = ['opaque', 'translucent', 'semi-transparent', 'transparent', 'warning'] as const;
  22. export type DemoModeStatusBarMode = (typeof DemoModeStatusBarModes)[number];
  23. export class DemoMode extends AdbCommandBase {
  24. private settings: Settings;
  25. constructor(adb: Adb) {
  26. super(adb);
  27. this.settings = new Settings(adb);
  28. }
  29. public static readonly AllowedSettingKey = 'sysui_demo_allowed';
  30. // Demo Mode actually doesn't have a setting indicates its enablement
  31. // However Developer Mode menu uses this key
  32. // So we can only try our best to guess if it's enabled
  33. public static readonly EnabledSettingKey = 'sysui_tuner_demo_on';
  34. public async getAllowed(): Promise<boolean> {
  35. const output = await this.settings.get('global', DemoMode.AllowedSettingKey);
  36. return output.trim() === '1';
  37. }
  38. public async setAllowed(value: boolean): Promise<void> {
  39. if (value) {
  40. await this.settings.put('global', DemoMode.AllowedSettingKey, '1');
  41. } else {
  42. await this.setEnabled(false);
  43. await this.settings.delete('global', DemoMode.AllowedSettingKey);
  44. }
  45. }
  46. public async getEnabled(): Promise<boolean> {
  47. const result = await this.settings.get('global', DemoMode.EnabledSettingKey);
  48. return result.trim() === '1';
  49. }
  50. public async setEnabled(value: boolean): Promise<void> {
  51. if (value) {
  52. await this.settings.put('global', DemoMode.EnabledSettingKey, '1');
  53. } else {
  54. await this.settings.delete('global', DemoMode.EnabledSettingKey);
  55. await this.broadcast('exit');
  56. }
  57. }
  58. public async broadcast(command: string, extra?: Record<string, string>): Promise<void> {
  59. await this.adb.subprocess.spawnAndWaitLegacy([
  60. 'am',
  61. 'broadcast',
  62. '-a',
  63. 'com.android.systemui.demo',
  64. '-e',
  65. 'command',
  66. command,
  67. ...(extra ? Object.entries(extra).flatMap(([key, value]) => ['-e', key, value]) : []),
  68. ]);
  69. }
  70. public async setBatteryLevel(level: number): Promise<void> {
  71. await this.broadcast('battery', { level: level.toString() });
  72. }
  73. public async setBatteryCharging(value: boolean): Promise<void> {
  74. await this.broadcast('battery', { plugged: value.toString() });
  75. }
  76. public async setPowerSaveMode(value: boolean): Promise<void> {
  77. await this.broadcast('battery', { powersave: value.toString() });
  78. }
  79. public async setAirplaneMode(show: boolean): Promise<void> {
  80. await this.broadcast('network', { airplane: show ? 'show' : 'hide' });
  81. }
  82. public async setWifiSignalStrength(value: DemoModeSignalStrength): Promise<void> {
  83. await this.broadcast('network', { wifi: 'show', level: value });
  84. }
  85. public async setMobileDataType(value: DemoModeMobileDataType): Promise<void> {
  86. for (let i = 0; i < 2; i += 1) {
  87. await this.broadcast('network', {
  88. mobile: 'show',
  89. sims: '1',
  90. nosim: 'hide',
  91. slot: '0',
  92. datatype: value,
  93. fully: 'true',
  94. roam: 'false',
  95. level: '4',
  96. inflate: 'false',
  97. activity: 'in',
  98. carriernetworkchange: 'hide',
  99. });
  100. }
  101. }
  102. public async setMobileSignalStrength(value: DemoModeSignalStrength): Promise<void> {
  103. await this.broadcast('network', { mobile: 'show', level: value });
  104. }
  105. public async setNoSimCardIcon(show: boolean): Promise<void> {
  106. await this.broadcast('network', { nosim: show ? 'show' : 'hide' });
  107. }
  108. public async setStatusBarMode(mode: DemoModeStatusBarMode): Promise<void> {
  109. await this.broadcast('bars', { mode });
  110. }
  111. public async setVibrateModeEnabled(value: boolean): Promise<void> {
  112. // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java;l=103
  113. await this.broadcast('status', { volume: value ? 'vibrate' : 'hide' });
  114. }
  115. public async setBluetoothConnected(value: boolean): Promise<void> {
  116. // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java;l=114
  117. await this.broadcast('status', { bluetooth: value ? 'connected' : 'hide' });
  118. }
  119. public async setLocatingIcon(show: boolean): Promise<void> {
  120. await this.broadcast('status', { location: show ? 'show' : 'hide' });
  121. }
  122. public async setAlarmIcon(show: boolean): Promise<void> {
  123. await this.broadcast('status', { alarm: show ? 'show' : 'hide' });
  124. }
  125. public async setSyncingIcon(show: boolean): Promise<void> {
  126. await this.broadcast('status', { sync: show ? 'show' : 'hide' });
  127. }
  128. public async setMuteIcon(show: boolean): Promise<void> {
  129. await this.broadcast('status', { mute: show ? 'show' : 'hide' });
  130. }
  131. public async setSpeakerPhoneIcon(show: boolean): Promise<void> {
  132. await this.broadcast('status', { speakerphone: show ? 'show' : 'hide' });
  133. }
  134. public async setNotificationsVisibility(show: boolean): Promise<void> {
  135. // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java;l=3131
  136. await this.broadcast('notifications', { visible: show.toString() });
  137. }
  138. public async setTime(hour: number, minute: number): Promise<void> {
  139. await this.broadcast('clock', {
  140. // cspell: disable-next-line
  141. hhmm:
  142. hour.toString().padStart(2, '0') +
  143. minute.toString().padStart(2, '0'),
  144. });
  145. }
  146. }