前言
在Android系统中,其他模块想要和SystemUI模块交互,基本都离不开StatusBarManagerService这个服务的,StatusBarManagerService顾名思义,就是状态栏管理服务,但其实这个服务不单单可以管理系统状态栏,通过这个服务,我们可以管理SystemUI模块的大部分系统栏组件,比如状态栏、导航栏、最近任务等,本篇文章我们先来简单认识一下这个服务。
一、SystemServer创建StatusBarManagerService服务
1、和大部分系统服务一样,StatusBarManagerService服务也是在SystemServer中被创建:
public final class SystemServer {
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
...代码省略...
try {
traceBeginAndSlog("StartServices");
startBootstrapServices();//启动引导服务
startCoreServices();//启动核心服务
startOtherServices();//启动其他服务
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...代码省略...
}
}
2、startOtherServices方法和WindowManagerService服务启动相关的代码如下所示。
public final class SystemServer {
private ActivityManagerService mActivityManagerService;
private boolean mOnlyCore;
private boolean mFirstBoot;
private void startOtherServices() {
...代码省略...
StatusBarManagerService statusBar = null;
...代码省略...
boolean isWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
...代码省略...
if (!isWatch) {
traceBeginAndSlog("StartStatusBarManagerService");
try {
//系统栏管理服务
statusBar = new StatusBarManagerService(context, wm);
ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar);
} catch (Throwable e) {
reportWtf("starting StatusBarManagerService", e);
}
traceEnd();
}
...代码省略...
}
}
二、StatusBarManagerService类定义
2.1 构造方法
public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener {
/**
* 构造方法
*/
public StatusBarManagerService(Context context) {
mContext = context;
LocalServices.addService(StatusBarManagerInternal.class, mInternalService);
LocalServices.addService(GlobalActionsProvider.class, mGlobalActionsProvider);
// We always have a default display.
final UiState state = new UiState();
mDisplayUiState.put(DEFAULT_DISPLAY, state);
final DisplayManager displayManager =
(DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
displayManager.registerDisplayListener(this, mHandler);
mActivityTaskManager = LocalServices.getService(ActivityTaskManagerInternal.class);
}
}
2.2 继承的父类
StatusBarManagerService继承自IStatusBarService.Stub,IStatusBarService.aidl文件如下所示。
interface IStatusBarService
{
@UnsupportedAppUsage
void expandNotificationsPanel();
@UnsupportedAppUsage
void collapsePanels();
void togglePanel();
@UnsupportedAppUsage
void disable(int what, IBinder token, String pkg);
void disableForUser(int what, IBinder token, String pkg, int userId);
void disable2(int what, IBinder token, String pkg);
void disable2ForUser(int what, IBinder token, String pkg, int userId);
int[] getDisableFlags(IBinder token, int userId);
void setIcon(String slot, String iconPackage, int iconId, int iconLevel, String contentDescription);
@UnsupportedAppUsage
void setIconVisibility(String slot, boolean visible);
@UnsupportedAppUsage
void removeIcon(String slot);
void setImeWindowStatus(int displayId, in IBinder token, int vis, int backDisposition,
boolean showImeSwitcher, boolean isMultiClientImeEnabled);
void expandSettingsPanel(String subPanel);
// ---- Methods below are for use by the status bar policy services ----
// You need the STATUS_BAR_SERVICE permission
RegisterStatusBarResult registerStatusBar(IStatusBar callbacks);
void onPanelRevealed(boolean clearNotificationEffects, int numItems);
void onPanelHidden();
// Mark current notifications as "seen" and stop ringing, vibrating, blinking.
void clearNotificationEffects();
void onNotificationClick(String key, in NotificationVisibility nv);
void onNotificationActionClick(String key, int actionIndex, in Notification.Action action, in NotificationVisibility nv, boolean generatedByAssistant);
void onNotificationError(String pkg, String tag, int id,
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
void onNotificationClear(String pkg, int userId, String key,
int dismissalSurface, int dismissalSentiment, in NotificationVisibility nv);
void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
in NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded, in int notificationLocation);
void onNotificationDirectReplied(String key);
void onNotificationSmartSuggestionsAdded(String key, int smartReplyCount, int smartActionCount,
boolean generatedByAsssistant, boolean editBeforeSending);
void onNotificationSmartReplySent(in String key, in int replyIndex, in CharSequence reply,
in int notificationLocation, boolean modifiedBeforeSending);
void onNotificationSettingsViewed(String key);
void onNotificationBubbleChanged(String key, boolean isBubble, int flags);
void onBubbleNotificationSuppressionChanged(String key, boolean isNotifSuppressed, boolean isBubbleSuppressed);
void hideCurrentInputMethodForBubbles();
void grantInlineReplyUriPermission(String key, in Uri uri, in UserHandle user, String packageName);
void clearInlineReplyUriPermissions(String key);
void onNotificationFeedbackReceived(String key, in Bundle feedback);
void onGlobalActionsShown();
void onGlobalActionsHidden();
/**
* These methods are needed for global actions control which the UI is shown in sysui.
*/
void shutdown();
void reboot(boolean safeMode);
void addTile(in ComponentName tile);
void remTile(in ComponentName tile);
void clickTile(in ComponentName tile);
@UnsupportedAppUsage
void handleSystemKey(in int key);
/**
* Methods to show toast messages for screen pinning
*/
void showPinningEnterExitToast(boolean entering);
void showPinningEscapeToast();
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
int userId, long operationId, String opPackageName, long requestId,
int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
// Used to set a temporary message, e.g. fingerprint not recognized, finger moved too fast, etc
void onBiometricHelp(int modality, String message);
// Used to show an error - the dialog will dismiss after a certain amount of time
void onBiometricError(int modality, int error, int vendorCode);
// Used to hide the authentication dialog, e.g. when the application cancels authentication
void hideAuthenticationDialog();
/**
* Sets an instance of IUdfpsHbmListener for UdfpsController.
*/
void setUdfpsHbmListener(in IUdfpsHbmListener listener);
/**
* Show a warning that the device is about to go to sleep due to user inactivity.
*/
void showInattentiveSleepWarning();
/**
* Dismiss the warning that the device is about to go to sleep due to user inactivity.
*/
void dismissInattentiveSleepWarning(boolean animated);
/**
* Notifies SystemUI to start tracing.
*/
void startTracing();
/**
* Notifies SystemUI to stop tracing.
*/
void stopTracing();
/**
* Returns whether SystemUI tracing is enabled.
*/
boolean isTracing();
/**
* If true, suppresses the ambient display from showing. If false, re-enables the ambient
* display.
*/
void suppressAmbientDisplay(boolean suppress);
}
2.3 实现的接口
StatusBarManagerService实现了DisplayListener,该接口如下所示。
public final class DisplayManager {
/**
* Listens for changes in available display devices.
*/
public interface DisplayListener {
/**
* Called whenever a logical display has been added to the system.
* Use {@link DisplayManager#getDisplay} to get more information about
* the display.
*
* @param displayId The id of the logical display that was added.
*/
void onDisplayAdded(int displayId);
/**
* Called whenever a logical display has been removed from the system.
*
* @param displayId The id of the logical display that was removed.
*/
void onDisplayRemoved(int displayId);
/**
* Called whenever the properties of a logical {@link android.view.Display},
* such as size and density, have changed.
*
* @param displayId The id of the logical display that changed.
*/
void onDisplayChanged(int displayId);
}
}
2.4 常用属性
public class StatusBarManagerService extends IStatusBarService.Stub implements DisplayListener {
private final Context mContext;
private final Handler mHandler = new Handler();
private NotificationDelegate mNotificationDelegate;
private volatile IStatusBar mBar;
private final ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>();
// for disabling the status bar
private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>();
private GlobalActionsProvider.GlobalActionsListener mGlobalActionListener;
private final IBinder mSysUiVisToken = new Binder();
private final Object mLock = new Object();
private final DeathRecipient mDeathRecipient = new DeathRecipient();
private final ActivityTaskManagerInternal mActivityTaskManager;
private int mCurrentUserId;
private boolean mTracingEnabled;
private final SparseArray<UiState> mDisplayUiState = new SparseArray<>();
@GuardedBy("mLock")
private IUdfpsHbmListener mUdfpsHbmListener;
/**
* Private API used by NotificationManagerService.
*/
private final StatusBarManagerInternal mInternalService = new StatusBarManagerInternal() {
private boolean mNotificationLightOn;
@Override
public void setNotificationDelegate(NotificationDelegate delegate) {
mNotificationDelegate = delegate;
}
@Override
public void showScreenPinningRequest(int taskId) {
if (mBar != null) {
try {
mBar.showScreenPinningRequest(taskId);
} catch (RemoteException e) {
}
}
}
@Override
public void showAssistDisclosure() {
if (mBar != null) {
try {
mBar.showAssistDisclosure();
} catch (RemoteException e) {
}
}
}
@Override
public void startAssist(Bundle args) {
if (mBar != null) {
try {
mBar.startAssist(args);
} catch (RemoteException e) {
}
}
}
@Override
public void onCameraLaunchGestureDetected(int source) {
if (mBar != null) {
try {
mBar.onCameraLaunchGestureDetected(source);
} catch (RemoteException e) {
}
}
}
/**
* Notifies the status bar that a Emergency Action launch gesture has been detected.
*
* TODO (b/169175022) Update method name and docs when feature name is locked.
*/
@Override
public void onEmergencyActionLaunchGestureDetected() {
if (SPEW) Slog.d(TAG, "Launching emergency action");
if (mBar != null) {
try {
mBar.onEmergencyActionLaunchGestureDetected();
} catch (RemoteException e) {
if (SPEW) Slog.d(TAG, "Failed to launch emergency action");
}
}
}
@Override
public void setDisableFlags(int displayId, int flags, String cause) {
StatusBarManagerService.this.setDisableFlags(displayId, flags, cause);
}
@Override
public void toggleSplitScreen() {
enforceStatusBarService();
if (mBar != null) {
try {
mBar.toggleSplitScreen();
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionFinished(int displayId) {
enforceStatusBarService();
if (mBar != null) {
try {
mBar.appTransitionFinished(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void toggleRecentApps() {
if (mBar != null) {
try {
mBar.toggleRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void setCurrentUser(int newUserId) {
if (SPEW) Slog.d(TAG, "Setting current user to user " + newUserId);
mCurrentUserId = newUserId;
}
@Override
public void preloadRecentApps() {
if (mBar != null) {
try {
mBar.preloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void cancelPreloadRecentApps() {
if (mBar != null) {
try {
mBar.cancelPreloadRecentApps();
} catch (RemoteException ex) {}
}
}
@Override
public void showRecentApps(boolean triggeredFromAltTab) {
if (mBar != null) {
try {
mBar.showRecentApps(triggeredFromAltTab);
} catch (RemoteException ex) {}
}
}
@Override
public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
if (mBar != null) {
try {
mBar.hideRecentApps(triggeredFromAltTab, triggeredFromHomeKey);
} catch (RemoteException ex) {}
}
}
@Override
public void collapsePanels() {
if (mBar != null) {
try {
mBar.animateCollapsePanels();
} catch (RemoteException ex) {
}
}
}
@Override
public void dismissKeyboardShortcutsMenu() {
if (mBar != null) {
try {
mBar.dismissKeyboardShortcutsMenu();
} catch (RemoteException ex) {}
}
}
@Override
public void toggleKeyboardShortcutsMenu(int deviceId) {
if (mBar != null) {
try {
mBar.toggleKeyboardShortcutsMenu(deviceId);
} catch (RemoteException ex) {}
}
}
@Override
public void showChargingAnimation(int batteryLevel) {
if (mBar != null) {
try {
mBar.showWirelessChargingAnimation(batteryLevel);
} catch (RemoteException ex){
}
}
}
@Override
public void showPictureInPictureMenu() {
if (mBar != null) {
try {
mBar.showPictureInPictureMenu();
} catch (RemoteException ex) {}
}
}
@Override
public void setWindowState(int displayId, int window, int state) {
if (mBar != null) {
try {
mBar.setWindowState(displayId, window, state);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionPending(int displayId) {
if (mBar != null) {
try {
mBar.appTransitionPending(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionCancelled(int displayId) {
if (mBar != null) {
try {
mBar.appTransitionCancelled(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void appTransitionStarting(int displayId, long statusBarAnimationsStartTime,
long statusBarAnimationsDuration) {
if (mBar != null) {
try {
mBar.appTransitionStarting(
displayId, statusBarAnimationsStartTime, statusBarAnimationsDuration);
} catch (RemoteException ex) {}
}
}
@Override
public void setTopAppHidesStatusBar(boolean hidesStatusBar) {
if (mBar != null) {
try {
mBar.setTopAppHidesStatusBar(hidesStatusBar);
} catch (RemoteException ex) {}
}
}
@Override
public boolean showShutdownUi(boolean isReboot, String reason) {
if (!mContext.getResources().getBoolean(R.bool.config_showSysuiShutdown)) {
return false;
}
if (mBar != null) {
try {
mBar.showShutdownUi(isReboot, reason);
return true;
} catch (RemoteException ex) {}
}
return false;
}
// TODO(b/118592525): support it per display if necessary.
@Override
public void onProposedRotationChanged(int rotation, boolean isValid) {
if (mBar != null){
try {
mBar.onProposedRotationChanged(rotation, isValid);
} catch (RemoteException ex) {}
}
}
@Override
public void onDisplayReady(int displayId) {
if (mBar != null) {
try {
mBar.onDisplayReady(displayId);
} catch (RemoteException ex) {}
}
}
@Override
public void onRecentsAnimationStateChanged(boolean running) {
if (mBar != null) {
try {
mBar.onRecentsAnimationStateChanged(running);
} catch (RemoteException ex) {}
}
}
@Override
public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
@Behavior int behavior, InsetsVisibilities requestedVisibilities,
String packageName) {
getUiState(displayId).setBarAttributes(appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
if (mBar != null) {
try {
mBar.onSystemBarAttributesChanged(displayId, appearance, appearanceRegions,
navbarColorManagedByIme, behavior, requestedVisibilities, packageName);
} catch (RemoteException ex) { }
}
}
@Override
public void showTransient(int displayId, @InternalInsetsType int[] types,
boolean isGestureOnSystemBar) {
getUiState(displayId).showTransient(types);
if (mBar != null) {
try {
mBar.showTransient(displayId, types, isGestureOnSystemBar);
} catch (RemoteException ex) { }
}
}
@Override
public void abortTransient(int displayId, @InternalInsetsType int[] types) {
getUiState(displayId).clearTransient(types);
if (mBar != null) {
try {
mBar.abortTransient(displayId, types);
} catch (RemoteException ex) { }
}
}
@Override
public void showToast(int uid, String packageName, IBinder token, CharSequence text,
IBinder windowToken, int duration,
@Nullable ITransientNotificationCallback callback) {
if (mBar != null) {
try {
mBar.showToast(uid, packageName, token, text, windowToken, duration, callback);
} catch (RemoteException ex) { }
}
}
@Override
public void hideToast(String packageName, IBinder token) {
if (mBar != null) {
try {
mBar.hideToast(packageName, token);
} catch (RemoteException ex) { }
}
}
@Override
public void requestWindowMagnificationConnection(boolean request) {
if (mBar != null) {
try {
mBar.requestWindowMagnificationConnection(request);
} catch (RemoteException ex) { }
}
}
@Override
public void handleWindowManagerLoggingCommand(String[] args, ParcelFileDescriptor outFd) {
if (mBar != null) {
try {
mBar.handleWindowManagerLoggingCommand(args, outFd);
} catch (RemoteException ex) { }
}
}
@Override
public void setNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
if (mBar != null) {
try {
mBar.setNavigationBarLumaSamplingEnabled(displayId, enable);
} catch (RemoteException ex) { }
}
}
@Override
public void setUdfpsHbmListener(IUdfpsHbmListener listener) {
synchronized (mLock) {
mUdfpsHbmListener = listener;
}
if (mBar != null) {
try {
mBar.setUdfpsHbmListener(listener);
} catch (RemoteException ex) { }
}
}
};
private final GlobalActionsProvider mGlobalActionsProvider = new GlobalActionsProvider() {
@Override
public boolean isGlobalActionsDisabled() {
// TODO(b/118592525): support global actions for multi-display.
final int disabled2 = mDisplayUiState.get(DEFAULT_DISPLAY).getDisabled2();
return (disabled2 & DISABLE2_GLOBAL_ACTIONS) != 0;
}
@Override
public void setGlobalActionsListener(GlobalActionsProvider.GlobalActionsListener listener) {
mGlobalActionListener = listener;
mGlobalActionListener.onGlobalActionsAvailableChanged(mBar != null);
}
@Override
public void showGlobalActions() {
if (mBar != null) {
try {
mBar.showGlobalActionsMenu();
} catch (RemoteException ex) {}
}
}
};
}