Android SystemUI组件(02)SystemBars分析

198 篇文章 97 订阅

该系列文章总纲链接:专题分纲目录 Android SystemUI组件


本章关键点总结 & 说明:

说明:本章节持续迭代之前章节的思维导图,主要关注下方 SystemBars分析部分即可。主要解读了SystemBars的启动流程以及如何调用到 状态栏和导航栏的创建函数。

1 SystemBars start 启动分析

分析SystemBars的start方法,代码实现如下:

public class SystemBars extends SystemUI implements ServiceMonitor.Callbacks {
    //...
    private ServiceMonitor mServiceMonitor;
    @Override
    public void start() {
        mServiceMonitor = new ServiceMonitor(TAG, DEBUG,
                mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this);
        // will call onNoService if no remote service is found
        mServiceMonitor.start();  
    }
    //...
}

这里继续分析关键代码mServiceMonitor.start()的实现,如下所示:

public class ServiceMonitor {
    //...
    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.addDataScheme("package");
        mContext.registerReceiver(mBroadcastReceiver, filter);
        mHandler.sendEmptyMessage(MSG_START_SERVICE);
    }
    //...
}

这里最后通过handler发送了消息MSG_START_SERVICE,对于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;

            //...
        }
    }
};

对消息的处理主要是执行startService方法,实现如下:

private void startService() {
    mServiceName = getComponentNameFromSetting();
    if (mServiceName == null) {
        mBound = false;
        //这个mCallbacks对象就是之前传入进来的SystemBar类型的
        mCallbacks.onNoService();
    } else {
        long delay = mCallbacks.onServiceStartAttempt();
        mHandler.sendEmptyMessageDelayed(MSG_CONTINUE_START_SERVICE, delay);
    }
}

对于第一次启动的服务会走上面的分支,SystemBar的onNoService代码实现如下:

    @Override
    public void onNoService() {
        // fallback to using an in-process implementation
        createStatusBarFromConfig();  
    }

继续分析createStatusBarFromConfig的实现,代码如下所示:

private void createStatusBarFromConfig() {
    final String clsName = mContext.getString(R.string.config_statusBarComponent);
    //...
    //通过类加载器实例化类
    Class<?> cls = null;
    //...
    cls = mContext.getClassLoader().loadClass(clsName);
	//...
    mStatusBar = (BaseStatusBar) cls.newInstance();
	//...
    mStatusBar.mContext = mContext;
    mStatusBar.mComponents = mComponents;
    mStatusBar.start();
}

当远程服务没有启动时,首先从xml文件读取要启动的类名,我们来查看这个xml文件 res\values\config.xml,内容如下:

<resources>
    ...
    <!-- Component to be used as the status bar service.  Must implement the IStatusBar
     interface.  This name is in the ComponentName flattened format (package/class)  -->
    <string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.PhoneStatusBar</string>
    ...
</resources>

由上可知,这个StatusBar实际上是PhoneStatusBar,从这里开始将进入到PhoneStatusBar的启动流程,在这里我们开始探寻导航栏和状态的创建方法的探寻。

2 导航栏创建方法探寻

实例化PhoneStatusBar类后会调用start方法,我们就从PhoneStatusBar的start方法开始分析,start方法代码实现如下:

@Override
public void start() {
    mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
            .getDefaultDisplay();
    updateDisplaySize();

	//src绘图模式
    mScrimSrcModeEnabled = mContext.getResources().getBoolean(
            R.bool.config_status_bar_scrim_behind_use_src);
			
	//调用父类BaseStatusBar的start方法
    super.start(); // calls createAndAddWindows()

    mMediaSessionManager
            = (MediaSessionManager) mContext.getSystemService(Context.MEDIA_SESSION_SERVICE);
	
	//创建导航栏
    addNavigationBar();
	
    //更新状态栏图标
    mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController);
    mSettingsObserver.onChange(false); // set up

    mHeadsUpObserver.onChange(true); // set up
    if (ENABLE_HEADS_UP) {
        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED), true,
                mHeadsUpObserver);
        mContext.getContentResolver().registerContentObserver(
                Settings.Global.getUriFor(SETTING_HEADS_UP_TICKER), true,
                mHeadsUpObserver);
    }
    mUnlockMethodCache = UnlockMethodCache.getInstance(mContext);
    mUnlockMethodCache.addListener(this);
	
	//启动锁屏
    startKeyguard();

    mDozeServiceHost = new DozeServiceHost();
    putComponent(DozeHost.class, mDozeServiceHost);
    putComponent(PhoneStatusBar.class, this);

    setControllerUsers();
    notifyUserAboutHiddenNotifications();
    mScreenPinningRequest = new ScreenPinningRequest(mContext);
}

这里我们看到了导航栏创建的关键方法:addNavigationBar(),接下来我们继续探寻 状态栏的创建方法。

3 状态栏创建方法探寻

PhoneStatusBar的start方法中调用了父类(BaseStatusBar类型)的start()方法,代码实现如下:

public void start() {
    //状态栏的窗口需要使用WM进行窗口的创建,因为不属于Activity
    mWindowManager = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
    mWindowManagerService = WindowManagerGlobal.getWindowManagerService();
    mDisplay = mWindowManager.getDefaultDisplay();
    mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService(
            Context.DEVICE_POLICY_SERVICE);

    mNotificationColorUtil = NotificationColorUtil.getInstance(mContext);
    mNotificationData = new NotificationData(this);

    mAccessibilityManager = (AccessibilityManager)
            mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);

    mDreamManager = IDreamManager.Stub.asInterface(
            ServiceManager.checkService(DreamService.DREAM_SERVICE));
    mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);

    //监听设备归属状态的变化,以禁用或启用某些功能
    mSettingsObserver.onChange(false); // set up
	//监听设置文件的改变,以便更新ContenProvider数据库
    mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED), true,
            mSettingsObserver);
    mContext.getContentResolver().registerContentObserver(
            Settings.Global.getUriFor(Settings.Global.ZEN_MODE), false,
            mSettingsObserver);
    mContext.getContentResolver().registerContentObserver(
            Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS), false,
            mSettingsObserver,
            UserHandle.USER_ALL);

    mContext.getContentResolver().registerContentObserver(
            Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS),
            true,
            mLockscreenSettingsObserver,
            UserHandle.USER_ALL);

	//获取statusbarService服务,于SystemUI而言是一个代理,它会将操作状态栏的请求发送给SystemUI,并由后者来完成请求。
    mBarService = IStatusBarService.Stub.asInterface(
            ServiceManager.getService(Context.STATUS_BAR_SERVICE));

    //设置recents回调函数
    mRecents = getComponent(RecentsComponent.class);
    mRecents.setCallback(this);

    final Configuration currentConfig = mContext.getResources().getConfiguration();
    mLocale = currentConfig.locale;
    mLayoutDirection = TextUtils.getLayoutDirectionFromLocale(mLocale);
    mFontScale = currentConfig.fontScale;

    mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);

    //动画相关
    mLinearOutSlowIn = AnimationUtils.loadInterpolator(mContext,android.R.interpolator.linear_out_slow_in);
    mFastOutLinearIn = AnimationUtils.loadInterpolator(mContext,android.R.interpolator.fast_out_linear_in);

    // Connect in to the status bar manager service
    StatusBarIconList iconList = new StatusBarIconList();
    mCommandQueue = new CommandQueue(this, iconList);

    int[] switches = new int[8];
    ArrayList<IBinder> binders = new ArrayList<IBinder>();
    //...
	//经过一系列对象的创建与初始化后,开始向StatusBarService进行注册。
    mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders);
    //...
	//关键点:创建 状态栏和导航栏窗口。由于创建状态栏和导航栏 窗口涉及到控件树的创建,因此它由子类PhoneStatusBar或TabletStatusBar实现,以根据不同的布局方案选择创建不同的窗口与控件树。
    createAndAddWindows();
	/*应用来自IStatusBarService中所获取的信息。mCommandQueue已经注册到IStatusBarService中,状态栏与导航栏的窗口与控件树也都创建完毕。接下来是应用从IStatusBarService中所获取的信息 */
    disable(switches[0], false /* animate */);
	// 设置SystemUIVisibility
    setSystemUiVisibility(switches[1], 0xffffffff);
	// 设置菜单键的可见性
    topAppWindowChanged(switches[2] != 0);
	
	// 根据输入法窗口的可见性调整导航栏的样式
    setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0);

	// 依次向系统状态区添加状态图标
    int N = iconList.size();
    int viewIndex = 0;
    for (int i=0; i<N; i++) {
        StatusBarIcon icon = iconList.getIcon(i);
        if (icon != null) {
            addIcon(iconList.getSlot(i), i, viewIndex, icon);
            viewIndex++;
        }
    }

    // Set up the initial notification state.
	//...
    mNotificationListener.registerAsSystemService(mContext,
        new ComponentName(mContext.getPackageName(), getClass().getCanonicalName()),UserHandle.USER_ALL);
	//...
    mCurrentUserId = ActivityManager.getCurrentUser();
    setHeadsUpUser(mCurrentUserId);

    IntentFilter filter = new IntentFilter();
    filter.addAction(Intent.ACTION_USER_SWITCHED);
    filter.addAction(Intent.ACTION_USER_ADDED);
    filter.addAction(BANNER_ACTION_CANCEL);
    filter.addAction(BANNER_ACTION_SETUP);
    filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
    mContext.registerReceiver(mBroadcastReceiver, filter);
    updateCurrentProfilesCache();
}

BaseStatusBar.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中的createAndAddWindows,代码实现如下:

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

致此,经过前面的分析,我们了解到,通过SystemBars的start启动,最终执行到了两个关键函数:

  • addNavigationBar(); //创建导航栏(PhoneStatusbar)
  • addStatusBarWindow();//创建状态栏(BaseStatusbar)

下一章节开始,我们从创建流程开始分析 状态栏和导航栏。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值