SystemUI源码分析三(StatusBar的加载流程)

本文详细分析了Android SystemUI中StatusBar的加载流程,从SystemServer启动SystemUIService开始,逐步探讨SystemBar的onStart()函数,ServiceMonitor的逻辑,以及PhoneStatusBar在BaseStatusBar基础上的实现。主要内容包括:创建和初始化PhoneStatusBarView,加载status_bar.xml及相关布局,添加状态栏和导航栏,以及图标状态的安装和更新。通过CommandQueue和StatusBarManagerService理解图标加载和更新的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SystemServer中调用startsystemui函数启动SystemUIService,在SystemUIService的onCreate()函数中执行一下这个语句

((SystemUIApplication) getApplication()).startServicesIfNeeded();

SystemBar继承SystemUI,因此被启动了。

那接下来就进入SystemBar这个类中看onStart()函数

public void start(){
    if(DEBUG)Log.d(TAG,"start");
    //创建监听器对象
    mServiceMonitor = new ServiceMonitor(TAG,DEBUG,mContext,Settings.Secure.BAR_SERVICE_COMPONENT,this);
    //开始监听
    mServiceMonitor.start();
}

ServiceMonitor.java

public void start() {
    // listen for setting changes
    ContentResolver cr = mContext.getContentResolver();
    cr.registerContentObserver(Settings.Secure.getUriFor(mSettingKey),
            false /*notifyForDescendents*/, mSettingObserver, UserHandle.USER_ALL);

    // listen for package/component changes
    //监听应用的安装卸载变化
    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_PACKAGE_addED);
    filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
    filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
    filter.addDataScheme("package");
    mContext.registerReceiver(mBroadcastReceiver, filter);

    //发送消息给主线程,启动Service
    mHandler.sendEmptyMessage(MSG_START_SERVICE);
}
/*处理接收到的消息*/
private final Handler mHandler = new Handler() {
    public void handleMessage(Message msg) {
        switch(msg.what) {
            case MSG_START_SERVICE:
                startService();
                break;
            case MSG_CONTINUE_START_SERVICE:
                continueStartService();
                break;
            case MSG_STOP_SERVICE:
                stopService();
                break;
            case MSG_PACKAGE_INTENT:
                packageIntent((Intent)msg.obj);
                break;
            case MSG_CHECK_BOUND:
                checkBound();
                break;
            case MSG_SERVICE_DISCONNECTED:
                serviceDisconnected((ComponentName)msg.obj);
                break;
        }
    }
};

private void startService() {
    mServiceName = getComponentNameFromSetting();
    if (mDebug) Log.d(mTag, "startService mServiceName=" + mServiceName);
    if (mServiceName == null) {
        mBound = false;
        mCallbacks.onNoService();
    } else {
        long delay = mCallbacks.onServiceStartAttempt();
        mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
    }
}

先获取Service的componentName,如果为null则回调onNoService方法。如果不为null,则通过mHandler发送消息给主线程。

private void continueStartService() {
    if (mDebug) Log.d(mTag, "continueStartService");
    Intent intent = new Intent().setComponent(mServiceName);
    try {
        mServiceConnection = new SC();
        mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        if (mDebug) Log.d(mTag, "mBound: " + mBound);
    } catch (Throwable t) {
        Log.w(mTag, "Error binding to service: " + mServiceName, t);
    }
    if (!mBound) {
        mCallbacks.onNoService();
    }
}

获取的componentName不管是不是空,最终都会回调onNoService()。

public void onNoService() {
    if (DEBUG) Log.d(TAG, "onNoService");
    createStatusBarFromConfig();  // fallback to using an in-process implementation
}

private void createStatusBarFromConfig() {
    if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");
    //取出className
    final String clsName = mContext.getString(R.string.config_statusBarComponent);
    if (clsName == null || clsName.length() == 0) {
        throw andLog("No status bar component configured", null);
    }
    Class<?> cls = null;
    try {
        //动态加载class文件
        cls = mContext.getClassLoader().loadClass(clsName);
    } catch (Throwable t) {
        throw andLog("Error loading status bar component: " + clsName, t);
    }
    try {
        //创建BaseStatusBar实例
        mStatusBar = (BaseStatusBar) cls.newInstance();
    } catch (Throwable t) {
        throw andLog("Error creating status bar component: " + clsName, t);
    }
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    //启动BaseStatusBar
    mStatusBar.start();
    if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());
}

frameworks\base\packages\SystemUI\res\values\config.xml
R.string.config_statusBarComponent的值是:

<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>

PhoneStatusBar继承自BaseStatusBar

启动BaseStatusBar,那就接着来看BaseStatusBar.java,这个类继承自SystemUI

public void start(){
    createAndAddWindows();
}

/**
 * Create all windows necessary for the status bar (including navigation, overlay panels, etc)
 * and add them to the window manager.
 */
protected abstract void createAndAddWindows();

是个抽象函数,PhoneStatusBar继承自BaseStatusBar,那我们来看下PhoneStatusBar

 public void start() {
    ……
    super.start(); // calls createAndAddWindows()
}

果然是PhoneStatusBar启动时调用了父类(BaseStatusBar)的createAndAddWindows(),这里PhoneStatusBar实现了父类的抽象方法。主要是添加状态栏、添加导航栏、更新图标

一、添加状态栏

@Override
public void createAndAddWindows() {
    addStatusBarWindow();
}

private void addStatusBawWindow(){
    makeStatusBarView();
    mStatusBarWindowManager = new StatusBarWindowManager(mContext);
    mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}

这个函数做了两件事

(1)创建PhoneStatusBarView并初始化PhoneStatusBarView中的控件。

(2)创建StatusBarWindowManager对象,调用它的add()函数为PhoneStatusBarView创建窗口,包括窗口的大小、位置、是否透明等属性。

先来分析makeStatusBarView()函数。

protected PhoneStatusBarView makeStatusBarView() {
    final Context context = mContext;

    Resources res = context.getResources();

    //获取屏幕参数
    updateDisplaySize(); // populates mDisplayMetrics
    //更新Panels资源数据,statusbar包含很多panel,在创建PhoneStatusBarView时需要更新panel数据
    updateResources();

    //引入StatusBarWindowView布局
    mStatusBarWindow = (StatusBarWindowView) View.inflate(context,
            R.layout.super_status_bar, null);
    //statusbarwindow
    mStatusBarWindow.setService(this);
    //设置触摸事件监听器
    mStatusBarWindow.setOnTouchListener(new View.OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            checkUserAutohide(v, event);
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                if (mExpandedVisible) {
                    animateCollapsePanels();
                }
            }
            return mStatusBarWindow.onTouchEvent(event);
        }
    });

    //初始化statusbarview
    mStatusBarView = (PhoneStatusBarView) mStatusBarWindow.findViewById(R.id.status_bar);
    mStatusBarView.setBar(this);

    //初始化panelholder
    PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
    mStatusBarView.setPanelHolder(holder);

    //初始化通知panel
    mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
            R.id.notification_panel);
    mNotificationPanel.setStatusBar(this);


    if (!mHighEnd) {
        mStatusBarWindow.setBackground(null);
        //设置notificationpanel背景
        mNotificationPanel.setBackground(new FastColorDrawable(context.getColor(
                R.color.notification_panel_solid_background)));
    }

    //通知样式
    mHeadsUpManager = new HeadsUpManager(context, mStatusBarWindow);
    mHeadsUpManager.setBar(this);
    mHeadsUpManager.addListener(this);
    mHeadsUpManager.addListener(mNotificationPanel);
    mNotificationPanel.setHeadsUpManager(mHeadsUpManager);
    mNotificationData.setHeadsUpManager(mHeadsUpManager);

    if (MULTIUSER_DEBUG) {
        mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
                R.id
### Android 14 SystemUI 滑动解锁代码实现机制与源码分析 #### 系统服务初始化 在Android 14中,`SystemUIService`作为核心组件之一,在系统启动过程中被加载并初始化。具体来说,`SystemServer`会在适当阶段调用`startSystemUi`方法来启动`SystemUIService`[^2]。这一步骤确保了`SystemUI`模块能够在设备开机后立即可用。 ```java static final void startSystemUi(Context context, WindowManagerService windowManager) { // 启动SystemUIService Intent intent = new Intent(); intent.setComponent(new ComponentName("com.android.systemui", "com.android.systemui.SystemUIService")); intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING); context.startServiceAsUser(intent, UserHandle.SYSTEM); // 通知WindowManagerService,SystemUI已启动 windowManager.onSystemUiStarted(); } ``` 一旦`SystemUIService`成功创建,它会通过`((SystemUIApplication) getApplication()).startServicesIfNeeded();`语句进一步初始化所有必要的子服务[^1]。 --- #### 锁屏界面构建 锁屏界面的呈现依赖于`KeyguardViewController`和`StatusBar`两个关键类的合作。其中: - `StatusBar`提供了整体布局管理能力; - `KeyguardViewController`则专注于处理具体的用户输入事件以及相应的业务逻辑。 两者共同作用以形成完整的滑动解锁体验。 --- #### 滑动解锁的核心逻辑 当用户尝试通过向下滑动的方式解除屏幕锁定时,以下步骤会被依次执行: 1. **触摸事件分发** 屏幕上的每一次触碰都会转化为一系列MotionEvent对象,并逐级传递给目标视图树直至找到合适的处理器。对于锁屏场景而言,默认情况下这些事件最终到达`KeyguardViewController`内部定义好的回调函数处等待下一步处置。 2. **手势方向判定** 利用VelocityTracker工具测量手指运动的速度矢量信息,据此推断出当前是否存在有效的拖拽意图。如果检测结果显示确实发生了朝正下方方向的大致直线型位移,则继续推进后续环节;反之终止整个流程返回初始态。 3. **防误触策略应用** 新增加了一套基于机器学习模型训练出来的预测引擎用来评估每次互动的真实性概率值大小。只有当计算所得数值低于预设阈限时才会认定此次操作属于合法范畴之内允许继续向前发展下去[^3]。 ```java private boolean isFalseTouch(float x, float y, @Classifier.InteractionType int interactionType) { if (!mStatusBar.isFalsingThresholdNeeded()) { return false; } /* * If falsing classifier enabled and predicts this as a false touch, * treat it accordingly. */ if (mFalsingManager.isClassifierEnabled()) { return mFalsingManager.isFalseTouch(interactionType); } if (!mTouchAboveFalsingThreshold) { return true; } if (mUpwardsWhenThresholdReached) { return false; } return !isDirectionUpwards(x, y); } ``` 上述片段清晰展现了如何综合考量多种因素做出精准裁定的过程。 4. **正式开启认证通道** 经过前面几轮筛选保留下来的候选者才有资格进入最后的身份核实阶段。此时要么直接跳转至主桌面显示画面(无密码保护情形),要么弹框请求用户提供额外验证材料比如PIN码或者生物特征样本等等。 --- ### 性能优化措施 考虑到实际应用场景复杂多样难免会出现各种意外状况干扰正常运作效率低下等情况的发生几率增大。为此开发团队采取了一系列针对性很强的技术手段加以防范应对: - 对频繁使用的热点区域实施局部刷新而非全局重绘降低开销成本。 - 动态调整敏感度参数平衡便捷性和准确性之间的关系达到最佳组合比例设定标准。 - 加强异常捕捉恢复机制建设提升鲁棒性水平抵御外部恶劣环境带来的冲击损害程度最小化。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值