How SystemUI works in Android

How SystemUI works in Android , on the device it is located in system /priv-app /-SystemUI. 3r33767.  3r3r7777. 3r33767.  3r3r7777. global user interface. that starts during the system boot process and cannot be completed. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. starts SystemUI when booting the system. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. static final void startSystemUi (Context context, WindowManagerService windowManager) {
Intent intent = new Intent (); 3r3r7777. intent.setComponent (new ComponentName ("com.android.systemui",
"com.android.systemui.SystemUIService")); 3r3r7777. intent.addFlags (Intent.FLAG_DEBUG_TRIAGED_MISSING); 3r3r7777. //Slog.d(TAG, "Starting service:" + intent); 3r3r7777. context.startServiceAsUser (intent, UserHandle.SYSTEM); 3r3r7777. windowManager.onSystemUiStarted (); 3r3r7777.} 3r3758. 3r33767.  3r3r7777. Here we see how the SystemUI service is launched using the non-public startServiceAsUser API. If you wanted to use it, you would have to turn to reflection. But if you decide to use the reflection API in Android - think a few times if it's worth it. 3r3119. Think a hundred times :) [/s] 3r33767.  3r3r7777. 3r33767.  3r3r7777. So, there is a separate process for the application, and in fact each section SystemUI is a separate service or independent module. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public abstract class SystemUI implements SysUiServiceProvider {
public Context mContext; 3r3r7777. public Map
, Object> mComponents; 3r3r7777. 3r3r7777. public abstract void start (); 3r3r7777. 3r3r7777. protected void onConfigurationchanged (Configuration newConfig) {
}
3r3r7777. public void dump (FileDescriptor fd, PrintWriter pw, String[]args) {
}
3r3r7777. protected void onBootCompleted () {
}
3r3r7777. @SuppressWarnings ("unchecked")
public
T getComponent (Class
InterfaceType) {3r3777. return (T) (mComponents! = null? mComponents.get (interfaceType): null); 3r3r7777.}
3r3r7777. public
void putComponent (Class
interfaceType, C component) {
if (mComponents! = null) {
mComponents.put (interfaceType, component); 3r3r7777.}
}
3r3r7777. public static void overrideNotificationAppName (Context context, Notification.Builder n,
boolean system) {
final Bundle extras = new Bundle (); 3r3r7777. String appName = system
? context.getString (com.android.internal.R.string.notification_app_name_system)
: context.getString (com.android.internal.R.string.notification_app_name_settings); 3r3r7777. extras.putString (Notification.EXTRA_SUBSTITUTE_APP_NAME, appName); 3r3r7777. 3r3r7777. n.addExtras (extras); 3r3r7777.}
}
3r3757. 3r3758. 3r33767.  3r3r7777. The start () method is called to run each service 3r3770. which are listed below. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3754. 3r3187. 3r3r7777.
com.android.systemui.Dependency
3r3r7777.
com.android.systemui.util.NotificationChannels
3r3r7777.
com.android.systemui.statusbar.CommandQueue $ CommandQueueStart
3r3r7777.
com.android.systemui.keyguard.KeyguardViewMediator
3r3r7777.
com.android.systemui.recents.Recents
3r3r7777.
com.android.systemui.volume.VolumeUI
3r3r7777.
com.android.systemui.stackdivider.Divider
3r3r7777.
com.android.systemui.SystemBars
3r3r7777.
com.android.systemui.usb.StorageNotification
3r3r7777.
com.android.systemui.power.PowerUI
3r3r7777.
com.android.systemui.media.RingtonePlayer
3r3r7777.
com.android.systemui.keyboard.KeyboardUI
3r3r7777.
com.android.systemui.pip.PipUI
3r3r7777.
com.android.systemui.shortcut.ShortcutKeyDispatcher
3r3r7777.
@ string /config_systemUIVendorServiceComponent
3r3r7777.
com.android.systemui.util.leak.GarbageMonitor $ Service
3r3r7777.
com.android.systemui.LatencyTester
3r3r7777.
com.android.systemui.globalactions.GlobalActionsComponent
3r3r7777.
com.android.systemui.ScreenDecorations
3r3r7777.
com.android.systemui.fingerprint.FingerprintDialogImpl
3r3r7777.
com.android.systemui.SliceBroadcastRelayHandler
3r3r7777.
3r3757. 3r3758. 3r33767.  3r3r7777.

Volume control

3r33767.  3r3r7777. We regularly use the volume buttons on our devices, but we do not think about what processes should occur in the system in order for us to add or subtract sound. The operation seems fairly simple in words, but if you look at VolumeUI, which is located in a subfolder of
SystenUI /volume
In different modes, the interface has its own variation. 3r33767.  3r3r7777. 3r33767.  3r3r7777. VolumeUI
, it is also inherited from SystemUI. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public class VolumeUI extends SystemUI {
private static final String TAG = "VolumeUI"; 3r3r7777. private static boolean LOGD = Log.isLoggable (TAG, Log.DEBUG); 3r3r7777. 3r3r7777. private final Handler mHandler = new Handler (); 3r3r7777. 3r3r7777. private boolean mEnabled; 3r3r7777. private VolumeDialogComponent mVolumeComponent; 3r3r7777. 3r3r7777. @Override
public void start () {3r3r7777. boolean enableVolumeUi = mContext.getResources (). getBoolean (R.bool.enable_volume_ui); 3r3r7777. boolean enableSafetyWarning =
mContext.getResources (). getBoolean (R.bool.enable_safety_warning); 3r3r7777. mEnabled = enableVolumeUi || enableSafetyWarning; 3r3r7777. if (! mEnabled) return; 3r3r7777. mVolumeComponent = new VolumeDialogComponent (this, mContext, null); 3r3r7777. mVolumeComponent.setEnableDialogs (enableVolumeUi, enableSafetyWarning); 3r3r7777. putComponent (VolumeComponent.class, getVolumeComponent ()); 3r3r7777. setDefaultVolumeController (); 3r3r7777.}
… 3r3758. 3r33767.  3r3r7777. Here we see that with the help of mEnabled we determine whether we should show the panel with the sound setting. And judging by the VolumeDialogComponent, VolumeUI displays the soundbar in the form of a dialogue. But all actions regarding pressing the volume keys are handled in 3r3303. PhoneWindow
. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. protected boolean onkeydown (int featureId, int keyCode, KeyEvent event) {
3r3r7777. switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
case KeyEvent.KEYCODE_VOLUME_MUTE: {
//If we have a session send it, then
//use the suggested stream. 3r3r7777. if (mMediaController! = null) {
mMediaController.dispatchVolumeButtonEventAsSystemService (event); 3r3r7777.} else {
getMediaSessionManager (). dispatchVolumeKeyEventAsSystemService (event,
mVolumeControlStreamType); 3r3r7777.}
return true; 3r3r7777.}
3r3r7777. 3r3r7777. protected boolean onkeyup (int featureId, int keyCode, KeyEvent event) {
final KeyEvent.DispatcherState dispatcher =
mDecor! = null? mDecor.getKeyDispatcherState (): null; 3r3r7777.    if (dispatcher! = null) {
dispatcher.handleUpEvent (event); 3r3r7777.}
//Log.i(TAG, "Key up: repeat =" + event.getRepeatCount ()
//+ "flags = 0x" + Integer.toHexString (event.getFlags ())); 3r3r7777. 3r3r7777. switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN: {
//If we have a session send it, then
//use the suggested stream. 3r3r7777. if (mMediaController! = null) {
mMediaController.dispatchVolumeButtonEventAsSystemService (event); 3r3r7777.} else {
getMediaSessionManager (). dispatchVolumeKeyEventAsSystemService (
event, mVolumeControlStreamType); 3r3r7777.}
return true; 3r3r7777.}
… 3r3758. 3r33767.  3r3r7777. As far as we can see, KEYCODE_VOLUME_UP (+) is not processed and will go into processing KEYCODE_VOLUME_DOWN (-). And in both events, both onkeydown and onkeyup, the method is called. dispatchVolumeButtonEventAsSystemService . 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public void dispatchVolumeButtonEventAsSystemService (@NonNull KeyEvent keyEvent) {
switch (keyEvent.getAction ()) {
case KeyEvent.ACTION_DOWN: {
int direction = 0; 3r3r7777. switch (keyEvent.getKeyCode ()) {
case KeyEvent.KEYCODE_VOLUME_UP:
direction = AudioManager.ADJUST_RAISE; 3r3r7777. break; 3r3r7777. 3r3r7777. mSessionBinder.adjustVolume (mContext.getPackageName (), mCbStub, true, direction,
}
3rr3757.
 3r3r7777. So, here we call the adjustVolume method so that we can check our direction to which the event parameter will be assigned. 3r33767.  3r3r7777. 3r33767.  3r3r7777. As a result, when we get to AudioService where sendVolumeUpdate will be invoked, where besides calling the postVolumeChanged method, the HDMI interface will be installed. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. //UI update and Broadcast Intent
protected void sendVolumeUpdate (int streamType, int oldIndex, int index, int flags) {
3r3r7777. mVolumeController.postVolumeChanged (streamType, flags); 3r3r7777.}
3r3r7777. private int updateFlagsForSystemAudio (int flags) {
3r3r7777. if (mHdmiSystemAudioSupported &&
((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {3r3777. flags & = ~ AudioManager.FLAG_SHOW_UI; 3r3r7777.}
3r3r7777.}
return flags; 3r3r7777.}
3r3r7777. public void postVolumeChanged (int streamType, int flags) {
3r3r7777. mController.volumeChanged (streamType, flags); 3r3r7777. 3r3r7777.} 3r3758. 3r33767.  3r3r7777.

Ringtone Player

3r33767.  3r3r7777. Android RingtonePlayer plays the role of a player. It is also inherited from SystemUI and in method start () 3r33770. we see:
 3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. @Override
public void start () {3r3r7777. 3r3r7777. mAudioService.setRingtonePlayer (mCallback); 3r3r7777. 3r3r7777.} 3r3758. 3r33767.  3r3r7777. Here we set mCallback, which is essentially an instance of
IRingtonePlayer
. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. private IRingtonePlayer mCallback = new IRingtonePlayer.Stub () {
@Override
public void play (IBinder token, Uri uri, AudioAttributes aa, float volume, boolean looping)
throws RemoteException {
3r3r7777.}
3r3r7777. @Override
public void stop (IBinder token) {3r3r7777. 3r3r7777.}
3r3r7777. @Override
public boolean isPlaying (IBinder token) {
3r3r7777.}
3r3r7777. @Override
public void setPlaybackProperties (IBinder token, float volume, boolean looping) {
3r3r7777.}
3r3r7777. @Override
public void playAsync (Uri uri, UserHandle user, boolean looping, AudioAttributes aa) {
3r3r7777.}
3r3r7777. @Override
public void stopAsync () {
3r3r7777.}
3r3r7777. @Override
public String getTitle (Uri uri) {
3r3r7777.}
3r3r7777. @Override
public ParcelFileDescriptor openRingtone (Uri uri) {
3r3r7777.}
}; 3r3757. 3r3758. 3r33767.  3r3r7777. As a result, you can manage RingtonePlayerService with the help of Binder to play audio files. 3r33767.  3r3r7777. 3r33767.  3r3r7777.

PowerUI

3r33767.  3r3r7777. PowerUI responsible for power management and notification. It is similarly inherited from SystemUI and has a start () method. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public void start () {3r3r7777. mPowerManager = (PowerManager) mContext.getSystemService (Context.POWER_SERVICE); 3r3r7777. mHardwarePropertiesManager = (HardwarePropertiesManager)
mContext.getSystemService (Context.HARDWARE_PROPERTIES_SERVICE); 3r3r7777. mScreenOffTime = mPowerManager.isScreenOn ()? -1: SystemClock.elapsedRealtime (); 3r3r7777. mWarnings = Dependency.get (WarningsUI.class); 3r3r7777. mEnhancedEstimates = Dependency.get (EnhancedEstimates.class); 3r3r7777. mLastConfiguration.setTo (mContext.getResources (). getConfiguration ()); 3r3r7777. 3r3r7777. ContentObserver obs = new ContentObserver (mHandler) {
@Override
public void onchange (boolean selfChange) {
updateBatteryWarningLevels (); 3r3r7777.}
}; 3r3r7777. final ContentResolver resolver = mContext.getContentResolver (); 3r3r7777. resolver.registerContentObserver (Settings.Global.getUriFor (
Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
false, obs, UserHandle.USER_ALL); 3r3r7777. updateBatteryWarningLevels (); 3r3r7777. mReceiver.init (); 3r3r7777. 3r3r7777. showThermalShutdownDialog (); 3r3r7777. 3r3r7777. initTemperatureWarning (); 3r3r7777.} 3r3758. 3r33767.  3r3r7777. As we can see from the above code, the Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL changes the subscription to changes, and then the call 3r33535. mReceiver.init ()
. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public void init () {
//Register for Intent broadcasts for
IntentFilter filter = new IntentFilter (); 3r3r7777. filter.addAction (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); 3r3r7777. filter.addAction (Intent.ACTION_BATTERY_CHANGED); 3r3r7777. filter.addAction (Intent.ACTION_SCREEN_OFF); 3r3r7777. filter.addAction (Intent.ACTION_SCREEN_ON); 3r3r7777. filter.addAction (Intent.ACTION_USER_SWITCHED); 3r3r7777. mContext.registerReceiver (this, filter, null, mHandler); 3r3r7777.} 3r3758. 3r33767.  3r3r7777. This is where the broadcast receiver is registered, through which changes are tracked. 3r33767.  3r3r7777. 3r33767.  3r3r7777.

Tasks

3r33767.  3r3r7777. 3r33535. Recents
- This is the main and frequently used function in mobile devices based on Android. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r33570. Main features: 3r33571. 3r33767.  3r3r7777. 3r? 3574.  3r3r7777.
Display all tasks
 3r3r7777.
Switch between tasks
 3r3r7777.
Deleting tasks
 3r3r7777. 3r33585. 3r33767.  3r3r7777. 3r33767.  3r3r7777. In addition, Recents are also inherited from SystemUI. In RecentsActivity, the latest tasks are created and updated so that we can see them on our screen. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r? 3594. 3r33767.  3r3r7777. And in with the help of r3r3597. RecentTaskInfo
we can get information about a specific task. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. public static class RecentTaskInfo implements Parcelable {
3r3r7777. public int id; 3r3r7777. public int persistentId; 3r3r7777. public Intent baseIntent; 3r3r7777. public ComponentName origActivity; 3r3r7777. public ComponentName realActivity; 3r3r7777. public CharSequence description; 3r3r7777. public int stackId; 3r3r7777. 3r3757. 3r3758. 3r33767.  3r3r7777. In general, running tasks can be put in a separate topic. I studied it from all sides, because I wanted to blur the application screen before switching the application to background, so that an unreadable snapshot version was displayed in RecentsTask. However, the problem is that the application snapshot is taken before onpause () is called. This problem can be solved in several ways. Or set the flag so that the system simply hides the contents of the screen using
 3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. getWindow (). setFlags (WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE); 3r3757. 3r3758. 3r33767.  3r3r7777. What I was talking about in previous article 3r33770. , devoted just to snapshots. 3r33767.  3r3r7777. 3r33767.  3r3r7777. You can even make sure that the specific activity of the application is not displayed in tasks by putting 3r-3767 in the manifest.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3754. android: excludeFromRecents = "true" 3r3758. 3r33767.  3r3r7777. Or you can use the trick using
 3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. Intent.FLAG_ACTIVITY_MULTIPLE_TASK 3r3758. 3r33767.   3r3r7777. You can set the main activity above flag excludeFromRecents = true in order for its screen to be absent in running tasks, but at the time of loading the application, launch a separate task that will show either a blurred screenshot of the main activity or any other image. In more detail, how this can be done is described in
official documentation 3r33770. on the example of Google Drive. 3r33767.  3r3r7777. 3r33767.  3r3r7777.

Lock screen

3r33767.  3r3r7777. Keyguard is more complicated than all the above modules. It is a service that runs in SystemUI, and is managed using KeyguardViewMediator. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. private void setupLocked () {
3r3r7777. 3r3r7777. //Assume keyguard is showing (until it is disabled) until we know for sure, then Keyguard
//is disabled. 3r3r7777. if (mContext.getResources (). getBoolean (
com.android.keyguard.R.bool.config_enableKeyguardService)) {
setShowingLocked (! shouldWaitForProvisioning ()
&& mLockPatternUtils.isLockScreenDisabled (3r3r7777. KeyguardUpdateMonitor.getCurrentUser ()),
mAodShowing, OSH, which is in items 3r3r7777.} else {
//The system's keyguard is disabled or missing. 3r3r7777. setShowingLocked (false, mAodShowing, mSecondaryDisplayShowing, true); 3r3r7777.}
3r3r7777. 3r3r7777. 3r3r7777. mLockSounds = new SoundPool (? AudioManager.STREAM_SYSTEM, 0); 3r3r7777. String soundPath = Settings.Global.getString (cr, Settings.Global.LOCK_SOUND); 3r3r7777. if (soundPath! = null) {
mLockSoundId = mLockSounds.load (soundPath, 1); 3r3r7777.}
3r3r7777. 3r3r7777. int lockSoundDefaultAttenuation = mContext.getResources (). getInteger (
com.android.internal.R.integer.config_lockSoundVolumeDb); 3r3r7777. mLockSoundVolume = (float) Math.pow (1? (float) lockSoundDefaultAttenuation /20); 3r3r7777. 3r3r7777. 3r3r7777.} 3r3758. 3r33767.  3r3r7777. However, in fact, the KeyguardService does not independently work with the lock screen interface, it only transfers information to the StatusBar module, where actions regarding the visual appearance of the screen and the display of information are already performed. 3r33767.  3r3r7777. 3r33767.  3r3r7777.

The notification bar

3r33767.  3r3r7777.
SystemBars
It has a rather complicated structure and structure. His work is divided into two stages:
 3r3r7777. 3r33737.  3r3r7777.
Initializing SystemBars
 3r3r7777.
Display notifications
 3r3r7777.
3r33767.  3r3r7777. If you look at the launch of SystemBars
 3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3734. private void createStatusBarFromConfig () {
3r3r7777. final String clsName = mContext.getString (R.string.config_statusBarComponent); 3r3r7777. 3r3r7777. cls = mContext.getClassLoader (). loadClass (clsName); 3r3r7777. 3r3r7777. mStatusBar = (SystemUI) cls.newInstance (); 3r3r7777. 3r3r7777.} 3r3758. 3r33767.  3r3r7777. Then we see a link to the resource from which read class name and create an instance of it. 3r33767.  3r3r7777. 3r33767.  3r3r7777. 3r3753. 3r3754. 3r3755. com.android.systemui.statusbar.phone.StatusBar
3r3757. 3r3758. 3r33767.  3r3r7777. Thus, we see that StatusBar is called here, which will work with the output of notifications and UI. 3r33767.  3r3r7777. 3r33767.  3r3r7777. I think no one doubted that Android is very complex and contains many tricks, which are described in a huge number of lines of code. SystemUI is one of the most important parts of this system and I enjoyed studying it. Due to the fact that there is very little material on this topic, if you notice any errors, please correct me. 3r33767.  3r3r7777. 3r33767.  3r3r7777. P.S. I always put up a selection of material and shorter articles at @miproblema in telegram. 3r3778. 3r3r7777. 3r3r7777. 3r3r7777. 3r33775. ! function (e) {function t (t, n) {if (! (n in e)) {for (var r, a = e.document, i = a.scripts, o = i.length; o-- ;) if (-1! == i[o].src.indexOf (t)) {r = i[o]; break} if (! r) {r = a.createElement ("script"), r.type = "text /jаvascript", r.async =! ? r.defer =! ? r.src = t, r.charset = "UTF-8"; var d = function () {var e = a.getElementsByTagName ("script")[0]; e.parentNode.insertBefore (r, e)}; "[object Opera]" == e.opera? a.addEventListener? a.addEventListener ("DOMContentLoaded", d,! 1): e.attachEvent ("onload", d ): d ()}}} t ("//mediator.mail.ru/script/2820404/"""_mediator") () ();
3r3r7777. 3r3778.
+ 0 -

Add comment