今天来看一下android 手机的状态栏的源码流程分析。

相关类

frameworks\base\services\java\com\android\server\SystemServer.javaframeworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.javaframeworks\base\packages\SystemUI\src\com\android\systemui\SystemUIApplication.javaframeworks\base\packages\SystemUI\res\values\config.xmlsystemui\app\src\main\java\com\android\systemui\statusbar\phone\StatusBar.javaapp\src\main\java\com\android\systemui\statusbar\phone\CollapsedStatusBarFragmentapp\src\main\java\com\android\systemui\statusbar\phone\StatusBarWindowManagerapp\src\main\java\com\android\systemui\statusbar\phone\PhoneStatusBarPolicy.javasettingslib\src\main\java\com\android\settingslib\graph\BatteryMeterDrawableBase

1.systemUI的启动

frameworks\base\services\java\com\android\server\SystemServer.javastatic final void startSystemUi(Context context, WindowManagerService windowManager) {        Intent intent = new Intent();        intent.setComponent(new ComponentName("com.android.systemui",                    "com.android.systemui.SystemUIService"));        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);        //Slog.d(TAG, "Starting service: " + intent);        context.startServiceAsUser(intent, UserHandle.SYSTEM);        windowManager.onSystemUiStarted();    }
frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIService.java    @Override    public void onCreate() {        super.onCreate();        ((SystemUIApplication) getApplication()).startServicesIfNeeded();// 在这里启动        // For debugging RescueParty        if (Build.IS_DEBUGGABLE && SystemProperties.getBoolean("debug.crash_sysui", false)) {            throw new RuntimeException();        }        if (Build.IS_DEBUGGABLE) {            // b/71353150 - looking for leaked binder proxies            BinderInternal.nSetBinderProxyCountEnabled(true);            BinderInternal.nSetBinderProxyCountWatermarks(1000,900);            BinderInternal.setBinderProxyCountCallback(                    new BinderInternal.BinderProxyLimitListener() {                        @Override                        public void onLimitReached(int uid) {                            Slog.w(SystemUIApplication.TAG,                                    "uid " + uid + " sent too many Binder proxies to uid "                                    + Process.myUid());                        }                    }, Dependency.get(Dependency.MAIN_HANDLER));        }    }
frameworks\base\packages\SystemUI\src\com\android\systemui\SystemUIApplication.java    public void startServicesIfNeeded() {        String[] names = getResources().getStringArray(R.array.config_systemUIServiceComponents);        startServicesIfNeeded(names);    }//这里可以看到有一个array的数组需要启动        private void startServicesIfNeeded(String[] services) {        if (mServicesStarted) {            return;        }        mServices = new SystemUI[services.length];        if (!mBootCompleted) {            // check to see if maybe it was already completed long before we began            // see ActivityManagerService.finishBooting()            if ("1".equals(SystemProperties.get("sys.boot_completed"))) {                mBootCompleted = true;                if (DEBUG) Log.v(TAG, "BOOT_COMPLETED was already sent");            }        }        Log.v(TAG, "Starting SystemUI services for user " +                Process.myUserHandle().getIdentifier() + ".");        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",                Trace.TRACE_TAG_APP);        log.traceBegin("StartServices");        final int N = services.length;        for (int i = 0; i < N; i++) {            String clsName = services[i];            if (DEBUG) Log.d(TAG, "loading: " + clsName);            log.traceBegin("StartServices" + clsName);            long ti = System.currentTimeMillis();            Class cls;            try {                cls = Class.forName(clsName);                mServices[i] = (SystemUI) cls.newInstance();            } catch(ClassNotFoundException ex){                throw new RuntimeException(ex);            } catch (IllegalAccessException ex) {                throw new RuntimeException(ex);            } catch (InstantiationException ex) {                throw new RuntimeException(ex);            }            mServices[i].mContext = this;            mServices[i].mComponents = mComponents;            if (DEBUG) Log.d(TAG, "running: " + mServices[i]);            mServices[i].start();   // 每个都从这里启动            log.traceEnd();            // Warn if initialization of component takes too long            ti = System.currentTimeMillis() - ti;            if (ti > 1000) {                Log.w(TAG, "Initialization of " + cls.getName() + " took " + ti + " ms");            }            if (mBootCompleted) {                mServices[i].onBootCompleted();            }        }

这里其实大家不要被名称搞混了,这不是服务,而是继承systemUI的类。通过start方法去加载启动

frameworks\base\packages\SystemUI\res\values\config.xml这里可以看到有这么多类需要启动加载。      <string-array name="config_systemUIServiceComponents" translatable="false">        <item>com.android.systemui.Dependencyitem>        <item>com.android.systemui.util.NotificationChannelsitem>        <item>com.android.systemui.statusbar.CommandQueue$CommandQueueStartitem>        <item>com.android.systemui.keyguard.KeyguardViewMediatoritem>        <item>com.android.systemui.recents.Recentsitem>        <item>com.android.systemui.volume.VolumeUIitem>        <item>com.android.systemui.stackdivider.Divideritem>        <item>com.android.systemui.SystemBarsitem>        <item>com.android.systemui.usb.StorageNotificationitem>        <item>com.android.systemui.power.PowerUIitem>        <item>com.android.systemui.media.RingtonePlayeritem>        <item>com.android.systemui.keyboard.KeyboardUIitem>        <item>com.android.systemui.pip.PipUIitem>        <item>com.android.systemui.shortcut.ShortcutKeyDispatcheritem>        <item>@string/config_systemUIVendorServiceComponentitem>        <item>com.android.systemui.util.leak.GarbageMonitor$Serviceitem>        <item>com.android.systemui.LatencyTesteritem>        <item>com.android.systemui.globalactions.GlobalActionsComponentitem>        <item>com.android.systemui.ScreenDecorationsitem>        <item>com.android.systemui.fingerprint.FingerprintDialogImplitem>        <item>com.android.systemui.SliceBroadcastRelayHandleritem>    string-array>

这里只分析com.android.systemui.SystemBars的流程

systemui\app\src\main\java\com\android\systemui\SystemBars    @Override    public void start() {        if (DEBUG) Log.d(TAG, "start");        createStatusBrFromConfig();    } private void createStatusBarFromConfig() {        if (DEBUG) Log.d(TAG, "createStatusBarFromConfig");        final String clsName = mContext.getString(R.string.config_statusBarComponent);        //    com.android.systemui.statusbar.phone.StatusBar        // 这里这个采用反射        if (clsName == null || clsName.length() == 0) {            throw andLog("No status bar component configured", null);        }        Class<?> cls = null;        try {            cls = mContext.getClassLoader().loadClass(clsName);        } catch (Throwable t) {            throw andLog("Error loading status bar component: " + clsName, t);        }        try {            mStatusBar = (SystemUI) cls.newInstance();        } catch (Throwable t) {            throw andLog("Error creating status bar component: " + clsName, t);        }        mStatusBar.mContext = mContext;        mStatusBar.mComponents = mComponents;        mStatusBar.start();        if (DEBUG) Log.d(TAG, "started " + mStatusBar.getClass().getSimpleName());    }
systemui\app\src\main\java\com\android\systemui\statusbar\phone\StatusBar.java   @Override    public void start() {    ...  省略部分代码,只保留文章相关的     createAndAddWindows() ;    ...            }        private void addStatusBarWindow() {        makeStatusBarView();// 调用此处方法        mStatusBarWindowManager = Dependency.get(StatusBarWindowManager.class);        mRemoteInputManager.setUpWithPresenter(this, mEntryManager, this,                new RemoteInputController.Delegate() {                    public void setRemoteInputActive(NotificationData.Entry entry,                            boolean remoteInputActive) {                        mHeadsUpManager.setRemoteInputActive(entry, remoteInputActive);                        entry.row.notifyHeightChanged(true /* needsAnimation */);                        updateFooter();                    }                    public void lockScrollTo(NotificationData.Entry entry) {                        mStackScroller.lockScrollTo(entry.row);                    }                    public void requestDisallowLongPressAndDismiss() {                        mStackScroller.requestDisallowLongPress();                        mStackScroller.requestDisallowDismiss();                    }                });        mRemoteInputManager.getController().addCallback(mStatusBarWindowManager);        mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight()); // 这个方法里面其实就可以看出是个window    }    protected void makeStatusBarView() {     inflateStatusBarWindow(context);  // 加载布局,下面分析        FragmentHostManager.get(mStatusBarWindow)                .addTagListener(CollapsedStatusBarFragment.TAG, new FragmentHostManager.FragmentListener() {                    @Override                    public void onFragmentViewCreated(String tag, Fragment fragment) {                        CollapsedStatusBarFragment statusBarFragment =                                (CollapsedStatusBarFragment) fragment;                 //这里这个fragment 才是我们的状态栏的fragment statusBarFragment.initNotificationIconArea(mNotificationIconAreaController);                        mStatusBarView = (PhoneStatusBarView) fragment.getView();                        mStatusBarView.setBar(StatusBar.this);                        mStatusBarView.setPanel(mNotificationPanel);                        mStatusBarView.setScrimController(mScrimController);                        mStatusBarView.setBouncerShowing(mBouncerShowing);                        if (mHeadsUpAppearanceController != null) {                            // This view is being recreated, let's destroy the old one                            mHeadsUpAppearanceController.destroy();                        }                        mHeadsUpAppearanceController = new HeadsUpAppearanceController(                                mNotificationIconAreaController, mHeadsUpManager, mStatusBarWindow);                        StatusBar.this.setAreThereNotifications();                        StatusBar.this.checkBarModes();                        /// M: add for plmn display feature @{                        StatusBar.this.attachPlmnPlugin();                        ///@}                    }                }).getFragmentManager()                .beginTransaction()                .replace(R.id.status_bar_container, new CollapsedStatusBarFragment(),                        CollapsedStatusBarFragment.TAG)  // 这可以看到这里也是在加载这个fragment 状态栏                .commit();        mIconController = Dependency.get(StatusBarIconController.class);}    // 加载布局    protected void inflateStatusBarWindow(Context context) {        mStatusBarWindow = (StatusBarWindowView) View.inflate(context,                R.layout.super_status_bar, null);    }
app\src\main\java\com\android\systemui\statusbar\phone\CollapsedStatusBarFragment    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,            Bundle savedInstanceState) {        return inflater.inflate(R.layout.status_bar, container, false);        // 这个布局文件就是我们手机的状态栏    }
app\src\main\java\com\android\systemui\statusbar\phone\StatusBarWindowManager    public void add(View statusBarView, int barHeight) {        // Now that the status bar window encompasses the sliding panel and its        // translucent backdrop, the entire thing is made TRANSLUCENT and is        // hardware-accelerated.        mLp = new WindowManager.LayoutParams(                ViewGroup.LayoutParams.MATCH_PARENT,                barHeight,                WindowManager.LayoutParams.TYPE_STATUS_BAR,                WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE                        | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH                        | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS,                PixelFormat.TRANSLUCENT);        mLp.token = new Binder();        mLp.gravity = Gravity.TOP;        mLp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;        mLp.setTitle("StatusBar");        mLp.packageName = mContext.getPackageName();        mLp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;        mStatusBarView = statusBarView;        mBarHeight = barHeight;        mWindowManager.addView(mStatusBarView, mLp);  // 可以看到这个其实也是一个window        mLpChanged = new WindowManager.LayoutParams();        mLpChanged.copyFrom(mLp);    }

到此,状态栏就启动了。接下来说说状态栏的加载以及布局

2.状态栏布局

super_status_bar.xml<com.android.systemui.statusbar.phone.StatusBarWindowView xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:sysui="http://schemas.android.com/apk/res-auto"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:fitsSystemWindows="true">    <com.android.systemui.statusbar.BackDropView        android:id="@+id/backdrop"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:visibility="gone"        sysui:ignoreRightInset="true">        <ImageView            android:id="@+id/backdrop_back"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:scaleType="centerCrop" />        <ImageView            android:id="@+id/backdrop_front"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:scaleType="centerCrop"            android:visibility="invisible" />    </com.android.systemui.statusbar.BackDropView>    <com.android.systemui.statusbar.ScrimView        android:id="@+id/scrim_behind"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:importantForAccessibility="no"        sysui:ignoreRightInset="true" />    <FrameLayout        android:id="@+id/status_bar_container"  // 这个fragment就是我们之前说的那个状态栏的fragment        android:layout_width="match_parent"        android:layout_height="wrap_content" />    <ViewStub        android:id="@+id/fullscreen_user_switcher_stub"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout="@layout/car_fullscreen_user_switcher" />    <include        layout="@layout/status_bar_expanded"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:visibility="invisible" />    <include layout="@layout/brightness_mirror" />    <com.android.systemui.statusbar.ScrimView        android:id="@+id/scrim_in_front"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:importantForAccessibility="no"        sysui:ignoreRightInset="true" /></com.android.systemui.statusbar.phone.StatusBarWindowView>

// 真正状态栏的显示

status_bar.xml<com.android.systemui.statusbar.phone.PhoneStatusBarView    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"    android:layout_width="match_parent"    android:layout_height="@dimen/status_bar_height"    android:id="@+id/status_bar"    android:background="@drawable/system_bar_background"    android:orientation="vertical"    android:focusable="false"    android:descendantFocusability="afterDescendants"    android:accessibilityPaneTitle="@string/status_bar"    >    <ImageView        android:id="@+id/notification_lights_out"        android:layout_width="@dimen/status_bar_icon_size"        android:layout_height="match_parent"        android:paddingStart="@dimen/status_bar_padding_start"        android:paddingBottom="2dip"        android:src="@drawable/ic_sysbar_lights_out_dot_small"        android:scaleType="center"        android:visibility="gone"        />    <LinearLayout android:id="@+id/status_bar_contents"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:paddingStart="@dimen/status_bar_padding_start"        android:paddingEnd="@dimen/status_bar_padding_end"        android:orientation="horizontal"        >        <ViewStub            android:id="@+id/operator_name"            android:layout_width="wrap_content"            android:layout_height="match_parent"            android:layout="@layout/operator_name" />        <FrameLayout            android:layout_height="match_parent"            android:layout_width="0dp"            android:layout_weight="1">            <include layout="@layout/heads_up_status_bar_layout" />            <!-- The alpha of the left side is controlled by PhoneStatusBarTransitions, and the             individual views are controlled by StatusBarManager disable flags DISABLE_CLOCK and             DISABLE_NOTIFICATION_ICONS, respectively -->            <LinearLayout                android:id="@+id/status_bar_left_side"                android:layout_height="match_parent"                android:layout_width="match_parent"                android:clipChildren="false"            >            // 时间显示                <com.android.systemui.statusbar.policy.Clock                    android:id="@+id/clock"                    android:layout_width="wrap_content"                    android:layout_height="match_parent"                    android:textAppearance="@style/TextAppearance.StatusBar.Clock"                    android:singleLine="true"                    android:paddingStart="@dimen/status_bar_left_clock_starting_padding"                    android:paddingEnd="@dimen/status_bar_left_clock_end_padding"                    android:gravity="center_vertical|start"                /> // 通知显示区域                <com.android.systemui.statusbar.AlphaOptimizedFrameLayout                    android:id="@+id/notification_icon_area"                    android:layout_width="0dp"                    android:layout_height="match_parent"                    android:layout_weight="1"                    android:orientation="horizontal"                    android:clipChildren="false"/>            </LinearLayout>        </FrameLayout>        <!-- Space should cover the notch (if it exists) and let other views lay out around it -->        <android.widget.Space            android:id="@+id/cutout_space_view"            android:layout_width="0dp"            android:layout_height="match_parent"            android:gravity="center_horizontal|center_vertical"        />// 系统icon        <com.android.keyguard.AlphaOptimizedLinearLayout android:id="@+id/system_icon_area"            android:layout_width="0dp"            android:layout_height="match_parent"            android:layout_weight="1"            android:orientation="horizontal"            android:gravity="center_vertical|end"            >            <include layout="@layout/system_icons" />        </com.android.keyguard.AlphaOptimizedLinearLayout>    </LinearLayout>    <ViewStub        android:id="@+id/emergency_cryptkeeper_text"        android:layout_width="wrap_content"        android:layout_height="match_parent"        android:layout="@layout/emergency_cryptkeeper_text"    /></com.android.systemui.statusbar.phone.PhoneStatusBarView>
system_icons.xml这里主要就是显示一些系统的图标,包括闹钟,wifi。蓝牙等,系统中这些图片都是矢量图<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/system_icons"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:gravity="center_vertical">    <com.android.systemui.statusbar.phone.StatusIconContainer android:id="@+id/statusIcons"        android:layout_width="0dp"        android:layout_weight="1"        android:layout_height="match_parent"        android:paddingEnd="@dimen/signal_cluster_battery_padding"        android:gravity="center_vertical"        android:orientation="horizontal"/>// 电池    <com.android.systemui.BatteryMeterView android:id="@+id/battery"        android:layout_height="match_parent"        android:layout_width="wrap_content"        android:clipToPadding="false"        android:clipChildren="false" /></LinearLayout>

总结下来状态栏如下所示

接下来看一下系统icon 栏是如何显示的

app\src\main\java\com\android\systemui\statusbar\phone\PhoneStatusBarPolicy.java系统icon 栏的初始化和更新都是在这个类里面去实现的 @VisibleForTesting    public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController) {        mContext = context;        mIconController = iconController;        mCast = Dependency.get(CastController.class);        mHotspot = Dependency.get(HotspotController.class);        mBluetooth = Dependency.get(BluetoothController.class);        mNextAlarmController = Dependency.get(NextAlarmController.class);        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);        mUserInfoController = Dependency.get(UserInfoController.class);        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);        mRotationLockController = Dependency.get(RotationLockController.class);        mDataSaver = Dependency.get(DataSaverController.class);        mZenController = Dependency.get(ZenModeController.class);        mProvisionedController = Dependency.get(DeviceProvisionedController.class);        mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);        mLocationController = Dependency.get(LocationController.class);        mSlotCast = context.getString(com.android.internal.R.string.status_bar_cast);        mSlotHotspot = context.getString(com.android.internal.R.string.status_bar_hotspot);        mSlotBluetooth = context.getString(com.android.internal.R.string.status_bar_bluetooth);        mSlotTty = context.getString(com.android.internal.R.string.status_bar_tty);        mSlotZen = context.getString(com.android.internal.R.string.status_bar_zen);        mSlotVolume = context.getString(com.android.internal.R.string.status_bar_volume);        mSlotAlarmClock = context.getString(com.android.internal.R.string.status_bar_alarm_clock);        mSlotManagedProfile = context.getString(                com.android.internal.R.string.status_bar_managed_profile);        mSlotRotate = context.getString(com.android.internal.R.string.status_bar_rotate);        mSlotHeadset = context.getString(com.android.internal.R.string.status_bar_headset);        mSlotDataSaver = context.getString(com.android.internal.R.string.status_bar_data_saver);        mSlotLocation = context.getString(com.android.internal.R.string.status_bar_location);       // systemicon 的初始化        // listen for broadcasts        IntentFilter filter = new IntentFilter();        /// M: [Multi-User] Will register this action using special receiver.        //filter.addAction(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED);        filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);        filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);        filter.addAction(AudioManager.ACTION_HEADSET_PLUG);        filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);        filter.addAction(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED);        filter.addAction(Intent.ACTION_MANAGED_PROFILE_AVAILABLE);        filter.addAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE);        /// M: [Multi-User] Add user switched action for updating possible alarm icon.        filter.addAction(Intent.ACTION_USER_SWITCHED);        filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED); // 广播的注册        /// M: Add icon for embms session.        filter.addAction(TelephonyIntents.ACTION_EMBMS_SESSION_STATUS_CHANGED);        filter.addAction(SMART_DEVICE_BROADCAST);        mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);        /// M: [Multi-User] Register Alarm intent by user        registerAlarmClockChanged(UserHandle.USER_OWNER, false);        // Alarm clock        mIconController.setIcon(mSlotAlarmClock, R.drawable.stat_sys_alarm, null);        mIconController.setIconVisibility(mSlotAlarmClock, false);接受到广播后去更新icon    private void updateAlarm() {        final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT);        final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0;        int zen = mZenController.getZen();        final boolean zenNone = zen == Global.ZEN_MODE_NO_INTERRUPTIONS;        mIconController.setIcon(mSlotAlarmClock, zenNone ? R.drawable.stat_sys_alarm_dim                : R.drawable.stat_sys_alarm, buildAlarmContentDescription());        mIconController.setIconVisibility(mSlotAlarmClock, mCurrentUserSetup && hasAlarm);    } // 广播接收器@VisibleForTesting    /*private*/ BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {        @Override        public void onReceive(Context context, Intent intent) {            String action = intent.getAction();            switch (action) {                case AudioManager.RINGER_MODE_CHANGED_ACTION:                case AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION:                    updateVolumeZen();                    break;                case TelephonyIntents.ACTION_SIM_STATE_CHANGED:                    // Avoid rebroadcast because SysUI is direct boot aware.                    if (intent.getBooleanExtra(TelephonyIntents.EXTRA_REBROADCAST_ON_UNLOCK,                            false)) {                        break;                    }                    updateSimState(intent);                    break;                case TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED:                    updateTTY(intent.getIntExtra(TelecomManager.EXTRA_CURRENT_TTY_MODE,                            TelecomManager.TTY_MODE_OFF));                    break;                case Intent.ACTION_MANAGED_PROFILE_AVAILABLE:                case Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE:                case Intent.ACTION_MANAGED_PROFILE_REMOVED:                    updateManagedProfile();                    break;                case AudioManager.ACTION_HEADSET_PLUG:                    updateHeadsetPlug(intent);                    break;                case Intent.ACTION_USER_SWITCHED:                    updateAlarm();                    int newUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);                    registerAlarmClockChanged(newUserId, true);                    break;                case TelephonyIntents.ACTION_EMBMS_SESSION_STATUS_CHANGED:                    updateEmbmsState(intent);                    break;                case SMART_DEVICE_BROADCAST:                    updateSmartDevice(intent);                    break;                     }        }    };

所以如果,需要在systemicon 栏客制化加入一个其他的icon,则可以在这个类里面仿照做修改

4. 电池电量的更新

从上面的xml 中可以看到电池电量的UI是在BatteryMeterView.java 类中
而真正去绘制电视的UI显示则是在settingslib的BatteryMeterDrawableBase.java 类中

settingslib\src\main\java\com\android\settingslib\graph\BatteryMeterDrawableBase // 初始化画笔    public BatteryMeterDrawableBase(Context context, int frameColor) {        mContext = context;        final Resources res = context.getResources();        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);        final int N = levels.length();        mColors = new int[2 * N];        for (int i = 0; i < N; i++) {            mColors[2 * i] = levels.getInt(i, 0);            if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {                mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getThemeAttributeId(i, 0));            } else {                mColors[2 * i + 1] = colors.getColor(i, 0);            }        }        levels.recycle();        colors.recycle();        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);        mCriticalLevel = mContext.getResources().getInteger(                com.android.internal.R.integer.config_criticalBatteryWarningLevel);        mButtonHeightFraction = context.getResources().getFraction(                R.fraction.battery_button_height_fraction, 1, 1);        mSubpixelSmoothingLeft = context.getResources().getFraction(                R.fraction.battery_subpixel_smoothing_left, 1, 1);        mSubpixelSmoothingRight = context.getResources().getFraction(                R.fraction.battery_subpixel_smoothing_right, 1, 1);        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mFramePaint.setColor(frameColor);        mFramePaint.setDither(true);        mFramePaint.setStrokeWidth(0);        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mBatteryPaint.setDither(true);        mBatteryPaint.setStrokeWidth(0);        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);        mTextPaint.setTypeface(font);        mTextPaint.setTextAlign(Paint.Align.CENTER);        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        font = Typeface.create("sans-serif", Typeface.BOLD);        mWarningTextPaint.setTypeface(font);        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);        if (mColors.length > 1) {            mWarningTextPaint.setColor(mColors[1]);        }        mChargeColor = Utils.getDefaultColor(mContext, android.R.color.holo_red_dark);        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mBoltPaint.setColor(Utils.getDefaultColor(mContext,  android.R.color.holo_green_dark));        mBoltPoints = loadPoints(res, R.array.batterymeter_bolt_points);        mPlusPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPlusPaint.setColor(Utils.getDefaultColor(mContext, R.color.batterymeter_plus_color));        mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);        mPowersavePaint = new Paint(Paint.ANTI_ALIAS_FLAG);        mPowersavePaint.setColor(mPlusPaint.getColor());        mPowersavePaint.setStyle(Style.STROKE);        mPowersavePaint.setStrokeWidth(context.getResources()                .getDimensionPixelSize(R.dimen.battery_powersave_outline_thickness));        mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);        mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);    }// 画电池  @Override    public void draw(Canvas c) {        final int level = mLevel;        final Rect bounds = getBounds();        if (level == -1) return;        float drawFrac = (float) level / 100f;        final int height = mHeight;        final int width = (int) (getAspectRatio() * mHeight);        final int px = (mWidth - width) / 2;        final int buttonHeight = Math.round(height * mButtonHeightFraction);        final int left = mPadding.left + bounds.left;        final int top = bounds.bottom - mPadding.bottom - height;        mFrame.set(left, top, width + left, height + top);        mFrame.offset(px, 0);        // button-frame: area above the battery body        mButtonFrame.set(                mFrame.left + Math.round(width * 0.28f),                mFrame.top,                mFrame.right - Math.round(width * 0.28f),                mFrame.top + buttonHeight);        // frame: battery body area        mFrame.top += buttonHeight;        // set the battery charging color        mBatteryPaint.setColor(batteryColorForLevel(level));        if (level >= FULL) {            drawFrac = 1f;        } else if (level <= mCriticalLevel) {            drawFrac = 0f;        }        final float levelTop = drawFrac == 1f ? mButtonFrame.top                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));        // define the battery shape        mShapePath.reset();        mOutlinePath.reset();        final float radius = getRadiusRatio() * (mFrame.height() + buttonHeight);        mShapePath.setFillType(FillType.WINDING);        mShapePath.addRoundRect(mFrame, radius, radius, Direction.CW);        mShapePath.addRect(mButtonFrame, Direction.CW);        mOutlinePath.addRoundRect(mFrame, radius, radius, Direction.CW);        Path p = new Path();        p.addRect(mButtonFrame, Direction.CW);        mOutlinePath.op(p, Op.XOR);        if (mCharging) {            // define the bolt shape            // Shift right by 1px for maximal bolt-goodness            final float bl = mFrame.left + mFrame.width() / 4f + 1;            final float bt = mFrame.top + mFrame.height() / 6f;            final float br = mFrame.right - mFrame.width() / 4f + 1;            final float bb = mFrame.bottom - mFrame.height() / 10f;            if (mBoltFrame.left != bl || mBoltFrame.top != bt                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {                mBoltFrame.set(bl, bt, br, bb);                mBoltPath.reset();                mBoltPath.moveTo(                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());                for (int i = 2; i < mBoltPoints.length; i += 2) {                    mBoltPath.lineTo(                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());                }                mBoltPath.lineTo(                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());            }            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);            boltPct = Math.min(Math.max(boltPct, 0), 1);            if (boltPct <= BOLT_LEVEL_THRESHOLD) {                // draw the bolt if opaque                c.drawPath(mBoltPath, mBoltPaint);            } else {                // otherwise cut the bolt out of the overall shape                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);            }        } else if (mPowerSaveEnabled) {            // define the plus shape            final float pw = mFrame.width() * 2 / 3;            final float pl = mFrame.left + (mFrame.width() - pw) / 2;            final float pt = mFrame.top + (mFrame.height() - pw) / 2;            final float pr = mFrame.right - (mFrame.width() - pw) / 2;            final float pb = mFrame.bottom - (mFrame.height() - pw) / 2;            if (mPlusFrame.left != pl || mPlusFrame.top != pt                    || mPlusFrame.right != pr || mPlusFrame.bottom != pb) {                mPlusFrame.set(pl, pt, pr, pb);                mPlusPath.reset();                mPlusPath.moveTo(                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());                for (int i = 2; i < mPlusPoints.length; i += 2) {                    mPlusPath.lineTo(                            mPlusFrame.left + mPlusPoints[i] * mPlusFrame.width(),                            mPlusFrame.top + mPlusPoints[i + 1] * mPlusFrame.height());                }                mPlusPath.lineTo(                        mPlusFrame.left + mPlusPoints[0] * mPlusFrame.width(),                        mPlusFrame.top + mPlusPoints[1] * mPlusFrame.height());            }            // Always cut out of the whole shape, and sometimes filled colorError            mShapePath.op(mPlusPath, Path.Op.DIFFERENCE);            if (mPowerSaveAsColorError) {                c.drawPath(mPlusPath, mPlusPaint);            }        }        // compute percentage text        boolean pctOpaque = false;        float pctX = 0, pctY = 0;        String pctText = null;        if (!mCharging && !mPowerSaveEnabled && level > mCriticalLevel && mShowPercent) {            mTextPaint.setColor(getColorForLevel(level));            mTextPaint.setTextSize(height *                    (SINGLE_DIGIT_PERCENT ? 0.75f                            : (mLevel == 100 ? 0.38f : 0.5f)));            mTextHeight = -mTextPaint.getFontMetrics().ascent;            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level / 10) : level);            pctX = mWidth * 0.5f + left;            pctY = (mHeight + mTextHeight) * 0.47f + top;            pctOpaque = levelTop > pctY;            if (!pctOpaque) {                mTextPath.reset();                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);                // cut the percentage text out of the overall shape                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);            }        }        // draw the battery shape background        c.drawPath(mShapePath, mFramePaint);        // draw the battery shape, clipped to charging level        mFrame.top = levelTop;        c.save();        c.clipRect(mFrame);        c.drawPath(mShapePath, mBatteryPaint);        c.restore();        if (!mCharging && !mPowerSaveEnabled) {            if (level <= mCriticalLevel) {                // draw the warning text                final float x = mWidth * 0.5f + left;                final float y = (mHeight + mWarningTextHeight) * 0.48f + top;                c.drawText(mWarningString, x, y, mWarningTextPaint);            } else if (pctOpaque) {                // draw the percentage text                c.drawText(pctText, pctX, pctY, mTextPaint);            }        }        // Draw the powersave outline last        if (!mCharging && mPowerSaveEnabled && mPowerSaveAsColorError) {            c.drawPath(mOutlinePath, mPowersavePaint);        }    }

更多相关文章

  1. Android(安卓)ASE 脚本环境
  2. Android(安卓)启动过程
  3. Android(安卓)启动过程(2)
  4. Android(安卓)ListView分隔线
  5. 华为手机Android(安卓)Studio开发不显示Logcat解决办法
  6. Android开机启动分析(一)logo的显示
  7. android ListView 属性
  8. Android开源图表库介绍
  9. Android(安卓)屏幕设置

随机推荐

  1. 畅享英特尔® 移动科技 开启Android 应用
  2. 美化你的android程序:自定义ListView背景
  3. 微软发布 mircosft remote desktop for a
  4. Android实例剖析笔记(五)
  5. 手势识别兼容Android 1.x和2.x的代码
  6. Android关于图片内存计算
  7. 控件更新Invalidate和postInvalidate的区
  8. Android(安卓)Rtmp客户端搭建
  9. Android硬件抽象层(HAL)概要介绍和学习计划
  10. 浅谈Android五大布局——LinearLayout、F